Destino Dev

Blog

Fallbacks práticos para Container Queries e @layer — componentes responsivos só CSS

Por John Pires · 11 de março de 2026

Fallbacks práticos para Container Queries e @layer — componentes responsivos só CSS

Quando e por que usar

O problema que container queries resolvem

Componentes modernos já não vivem no vácuo: um card ou um componente de formulário pode aparecer em vários contextos com larguras diferentes. Usar apenas media queries globais força um design acoplado ao viewport, não ao container. Container queries resolvem isso ao permitir que um componente responda ao seu próprio contêiner, não à janela.

Do ponto de vista de manutenção, container queries movem decisões de layout para o nível do componente. Isso reduz a necessidade de classes utilitárias específicas de layout em cada lugar onde o componente é usado.

Quando evitar ou postergar

Não é mágica: se sua UI depende de mudanças de layout globais (p.ex. um layout de quebra completa do grid da página), media queries ainda fazem sentido. Ademais, porque nem todo navegador do seu público pode suportar container queries, planeje fallback. Se você depende de behavior que exige JavaScript (medidas complexas, sincronização entre componentes), container queries podem não ser suficientes sozinhas.

Escolha container queries quando o objetivo for tornar um componente autônomo, reutilizável e que precise ajustar seu conteúdo segundo a largura do pai.

Comparação com alternativas

Jeito errado: apenas media queries globais

Code review: vejo muitos projetos onde o desenvolvedor resolve responsividade do componente com media queries globais. Isso funciona até que você coloque o componente em um contexto diferente (sidebar, modal, card menor).

Exemplo errado: usar media queries globais e breakpoints do tema para controlar um card. Isso quebra quando o card é reduzido dentro de um grid.

Contexto: o bloco abaixo mostra um card que muda layout com media queries globais. O problema é que a condição depende do viewport, não do contêiner.

/* Jeito errado: dependente do viewport. Se o card estiver num sidebar pequeno, não reage. */
.card {
  display: block;
}
@media (min-width: 700px) {
  .card { display: flex; }
  .card .meta { width: 200px; }
}

O que acontece: em telas grandes o card vira um layout lateral, mas se você inserir esse card em um espaço reduzido dentro da mesma tela, ele continuará em layout lateral e ficará quebrado.

Jeito certo: container queries por componente

Code review: prefira container queries para regras que precisam reagir ao espaço do componente. A mudança não é só técnica — é mental: pense no componente como uma caixa que sabe seu próprio tamanho.

Contexto: abaixo um card que define seu container e aplica estilos quando o container atinge 45rem.

/* Jeito certo: define o componente como container e usa @container para regras locais */
.card {
  container-type: inline-size; /* torna possível @container */
  container-name: card;       /* opcional, para leitura */
  padding: 1rem;
  border: 1px solid #ddd;
}
@container (min-width: 45rem) {
  .card { display: flex; gap: 1rem; }
  .card .meta { width: 18rem; }
}

O que acontece: o card reage ao espaço que tem dentro do contexto onde for renderizado — sidebar, grid, modal — sem quebrar. Se o card for reduzido por estar dentro de um grid, as regras @container ignoram o viewport e tomam a decisão correta.

Implementação progressiva

Detecção e fallback com @supports

Bom pattern: use @supports para testar suporte a container-type, e mantenha uma versão fallback baseada em media queries ou classes utilitárias. A ordem importa: escreva as regras básicas, depois o fallback global, e finalmente as regras modernas que sobrescrevem. Use @layer para controlar ordem e impedir que bundlers injetem CSS na ordem errada.

Contexto: o bloco abaixo demonstra uma estrategia progressiva. Primeiro estilos base, depois media queries como fallback, por fim @supports com @container. Isso garante comportamento em navegadores sem suporte.

/* Implementação progressiva:
   1) estilos base
   2) fallback com media queries (globais)
   3) se suportado, usar container queries para sobrescrever
*/
/* base */
.card { padding: 1rem; border-radius: 6px; }
/* fallback: usa breakpoint global estimado */
@media (min-width: 700px) {
  .card { display: flex; }
}
/* upgrade quando o browser tiver container support */
@supports (container-type: inline-size) {
  .card { container-type: inline-size; }
  @container (min-width: 45rem) {
    .card { display: flex; }
  }
}

O que acontece: navegadores sem container queries aplicam o layout baseado no viewport. Navegadores com suporte aplicam o comportamento baseado no contêiner, substituindo o fallback via cascade.

Ordenação sólida com @layer

Problema comum em code review: regras modernas acabam sendo sobrescritas por utilitários importados depois no bundle. @layer permite declarar camadas explícitas para controlar prioridade sem hacks de especificidade.

Contexto: define três layers — base, components e utilities — garantindo que estilos de componente possam ser mais específicos que base mas menos que utilities quando necessário.

/* Declarando layers em arquivo root.css */
@layer base, components, utilities;

@layer base {
  html { box-sizing: border-box; }
}
@layer components {
  .card { padding: 1rem; border: 1px solid #eee; }
}
@layer utilities {
  .u-flex { display: flex; }
}

/* components vem antes de utilities, utilities pode sobrescrever quando realmente necessário */

O que acontece: independentemente da ordem de importação, regras em layers seguem a ordem declarada na raiz, tornando overrides previsíveis. Isso evita o clássico bug onde um utilitário reinicia seu componente.

Integração com ecossistema real

React, Web Components e Shadow DOM

Code review: ao usar frameworks, saiba onde seu CSS vive. Em React com CSS global, container queries funcionam normalmente. Em Web Components usando Shadow DOM, container queries ainda funcionam, mas o container costuma ser o host do componente — você precisa declarar container-type no host ou em um wrapper dentro do shadow.

Contexto: exemplo de CSS para um web component que define o host como container. Isso mantém o componente responsivo dentro do Shadow DOM sem expor estilos globais.

/* CSS do shadow root do componente */
:host { display: block; container-type: inline-size; }
@container (min-width: 30rem) {
  :host { --layout: row; }
}
:host(.row) .content { display: flex; }

O que acontece: o componente passa a responder à largura do host, não ao viewport. Isso é ideal para componentes que serão compostos em contextos variados.

Build tools, PurgeCSS e scoping

Pain point: ferramentas que removem CSS não reconhecem dinamicamente selectors usados por @container ou classes aplicadas por scripts. Garanta regras de preservação no PurgeCSS ou configure safelisting. Além disso, quando usar @layer, declare a ordem no arquivo root para manter previsibilidade após concatenação/minificação.

Integre @supports e @layer em arquivos que não serão purgados; mantenha a declaração de @layer numa folha raiz importada antes de tudo para evitar que bundlers troquem a ordem real das camadas.

Checklist de qualidade para produção

Testes e regressões

Inclua casos de teste visuais que renderizam o componente em vários containers: modal, sidebar, grid com colunas reduzidas e listagens. Registre screenshots para testes visuais (Percy, Playwright snapshots) para captar regressões de layout quando adicionar novas regras.

Checklist prático:

  • Verificar o componente em 4 tamanhos de container distintos.
  • Testar em navegadores sem suporte (Chrome antigo, Safari versão anterior) para validar fallback.
  • Automatizar screenshot dos estados principais.

Performance, acessibilidade e manutenção

Container queries não adicionam custo de layout significativo além do que o browser já faz ao reflowar. Evite usar unidades que causem recomputação pesada (p.ex. usar JavaScript ou medir constantemente). Para acessibilidade, verifique foco e ordem de leitura em diferentes layouts — um layout em coluna pode alterar a ordem visual; mantenha DOM order sem depender apenas de CSS order para transmitir informação.

Inclua documentação no design system: como definir container-type, guidelines de breakpoints locais e quando preferir classes utilitárias. Isso evita decisões ad-hoc que quebram consistência.

Erros comuns, armadilhas e dicas práticas

Erros comuns

Listagem direta de erros que encontro em code review:

  1. Esquecer container-type no elemento — sem isso @container não funciona.
  2. Confiar em breakpoints do viewport para componentes que podem aparecer em espaços menores.
  3. Não declarar @layer no ponto de entrada — levando a ordem imprevisível após bundle.
  4. Usar unidades viewport (vw/vh) para décisions de layout internas do componente.
Dica: trate container queries como contrato do componente. Defina container-type e documente os breakpoints do componente no design system.

Armadilhas e soluções

Uma armadilha subtile é quando você espera que um componente dentro de um container flex ou grid tenha um tamanho previsível. Sempre teste o componente como item flexível. Se precisar de limites, use min-width e max-width dentro do componente para evitar que ele desapareça em layouts extremos.

Outra armadilha é a especificidade: usar IDs ou regras inline pode bloquear overrides em layers. Prefira a combinação de @layer + classes simples, evitando aumentar a especificidade sem motivo.

Conclusão prática

Resumo rápido (o que aplicar hoje)

1) Marque o componente com container-type: inline-size sempre que precisar que ele responda ao espaço local. 2) Use @supports (container-type: inline-size) para enfileirar o upgrade. 3) Declare @layer base, components, utilities na raiz do projeto. 4) Mantenha um fallback simples com media queries para navegadores sem suporte.

Aplicando esses passos você reduz bugs de layout ao mover componentes entre contextos, melhora reusabilidade e mantém o CSS previsível em projetos complexos.

Próximos passos e disciplina de equipe

Inclua guidelines no README do design system: como nomear breakpoints locais, quando usar container queries vs media queries, e onde declarar as layers. Faça reviews focados em previsibilidade de cascade e documente exemplos de componentes com e sem container queries.

Ao seguir o padrão acima você terá componentes responsivos só com CSS, com fallback estável e ordem de estilos previsível na produção.

Assuntos: CSS, container-queries, css-layers, responsive, component-driven

Leia também