Destino Dev

Blog

Container Queries: refatorando componentes com layers, nesting e animações

Por John Pires · 11 de março de 2026

Container Queries: refatorando componentes com layers, nesting e animações

Motivacao e trade-offs

Por que usar container queries em vez de media queries

Componentes modernos precisam ser responsivos ao contexto em que estão inseridos, não apenas à largura da janela. Container queries resolvem isso: permitem que o estilo do componente dependa do tamanho do seu contêiner pai. Isso reduz CSS duplicado, melhora reusabilidade e evita hacks como classes utilitárias aplicadas manualmente.

Ao refatorar componentes com container queries, você passa do pensamento "viewport-first" para "container-first". Isso facilita construir bibliotecas de componentes que se comportam corretamente em grids, sidebars e módulos com largura variável.

Trade-offs práticos

Nem tudo é ganho: container queries aumentam a complexidade de layout e podem introduzir custos de desempenho se usados sem critério — principalmente quando acoplados a animações que provocam repaints e reflows intensos. Também há dependência de suporte do navegador; embora esteja presente nos navegadores modernos, é importante testar em ambientes antigos.

Use container queries quando o comportamento do componente mudar com base no espaço disponível. Para mudanças globais do layout da página, continue usando media queries.

Fundamentos técnicos

Princípios: container-type e @container

Para um elemento poder escutar container queries, ele precisa ser um container. Isso é feito com a propriedade container-type. O valor mais comum é inline-size, porque a maior parte das variações é horizontal. Exemplo: .card { container-type: inline-size; }. Depois disso, você usa @container (min-width: 480px) { ... } dentro do seu CSS para condicionar estilos.

Existem duas formas de identificar um container: por nome (container-name) ou pelo fluxo implícito. Nomear é útil quando existem múltiplos containers aninhados e você deseja direcionar um específico.

Interação com layers, nesting e animations

@layer controla ordem de cascata de forma previsível sem abusar de especificidade. Combine layers com container queries para criar um sistema onde regras base ficam em um layer e overrides em um layer posterior.

Nesting reduz verbosidade e melhora legibilidade de componentes complexos: você pode declarar estilos filhos dentro do bloco do componente com &. Em conjunto com container queries, isso deixa o CSS muito mais coeso.

Animações precisam ser projetadas para não animar propriedades que forcem reflow massivo (por exemplo, width/height) quando usado dentro de container queries. Prefira transform e opacity, e sincronize os breakpoint de container queries com transições de estado.

Exemplo 1: caso simples

Contexto: um card que muda de layout dentro de um grid

Objetivo: refatorar um componente .card que, dependendo da largura do contêiner pai, alterna entre coluna (mobile) e linha (desktop). Vamos usar container queries com nesting e uma animação simples que revela metadados.

Antes de aplicar a query, definimos o container e estilos base. Em seguida, aplicamos a regra condicional dentro de @container.

/* Define o card como um container e estilos base */
.card {
  container-type: inline-size;
  container-name: card;
  display: grid;
  gap: 12px;
  grid-template-columns: 1fr;
  background: white;
  border-radius: 8px;
  padding: 16px;
  box-shadow: 0 2px 6px rgba(0,0,0,0.08);
}

/* Transição para a área de metadata */
.card .meta { 
  transition: transform 280ms ease, opacity 220ms ease;
  transform: translateY(8px);
  opacity: 0;
}

/* Nomeado: quando o contêiner atingir 480px ou mais, altera o layout */
@container card (min-width: 480px) {
  .card {
    grid-template-columns: 1fr 240px;
    align-items: center;
  }
  .card .meta {
    transform: translateY(0);
    opacity: 1;
  }
}

O que esse bloco faz: define o card como container e aplica um layout em uma coluna por padrão. Quando o contêiner atinge 480px, o layout muda para duas colunas e a meta aparece com uma transição.

Resultado prático: o mesmo componente se adapta corretamente quando colocado em colunas estreitas ou em um painel largo.

Variação: alternativa sem nomear o container

Se você não nomear o container, a sintaxe fica mais compacta, mas perde controle quando existirem containers aninhados. Exemplo abaixo mostra a forma implícita.

/* Implícito, útil para componentes isolados */
.card-implicit {
  container-type: inline-size;
}

@container (min-width: 520px) {
  .card-implicit { display: grid; grid-template-columns: 1fr 200px; }
}

Após a mudança, o card-implicit funciona igual ao exemplo anterior quando o seu próprio espaço de layout exceder 520px.

Exemplo 2: caso avancado do mundo real

Contexto: componente complexo em um design system

Você tem um componente .product-list-item usado em diferentes contextos: list view, grid view e sidebar. Cada contexto impõe restrições diferentes de espaço. Desejamos um CSS organizado por layers e com fallback de animação. Também queremos que overrides locais possam prevalecer sem aumentar especificidade.

Plano: usar @layer para separar regras base, component e overrides; container queries para comportamento local; nesting para clareza; animações eficientes com transform.

/* Layers: base -> components -> overrides */
@layer base {
  :root { --accent: #0a74ff; }
  .visually-hidden { position: absolute; clip: rect(0 0 0 0); }
}

@layer components {
  .product-list-item {
    container-type: inline-size;
    display: grid;
    grid-template-columns: 1fr;
    gap: 10px;
    padding: 14px;
    border-radius: 6px;
    background: linear-gradient(180deg, #fff, #fbfbfb);
    transition: box-shadow .18s ease;
  }

  /* nesting: estado interno e children */
  .product-list-item .thumb { width: 100%; height: 180px; object-fit: cover; }
  .product-list-item .info { display: flex; flex-direction: column; gap: 6px; }
  .product-list-item .price { color: var(--accent); font-weight: 700; }
}

@layer overrides {
  /* overrides do produto em contexto de sidebar */
  .sidebar .product-list-item { padding: 10px; }
}

O que acontece aqui: a camada components contém o padrão. overrides é carregado depois e pode alterar o comportamento local sem usar !important.

Container query e animação eficiente coordenação

Agora colocamos uma regra condicional: quando o container for largo, exibimos informações adicionais e aplicamos uma micro-ânimação que usa transform em vez de height.

/* Regras reativas ao espaço disponível */
@container (min-width: 600px) {
  .product-list-item {
    grid-template-columns: 220px 1fr;
    align-items: start;
  }
  .product-list-item .thumb { height: 160px; }
  .product-list-item .details { transform: translateY(0); opacity: 1; }
}

/* animação: não animar width/height */
.product-list-item .details {
  transform: translateY(8px);
  opacity: 0;
  transition: transform .26s cubic-bezier(.2,.9,.2,1), opacity .2s ease;
}

Resultado: a lista se adapta automaticamente quando inserida em diferentes contextos (grid, sidebar, main), com overrides locais controlados por layers. A animação é suave e evita reflows caros.

Debugging e troubleshooting

Erros comuns e armadilhas

Erro 1: esquecer de declarar container-type. Sem isso, @container não terá efeito. Erro 2: nomear múltiplos containers e confundir o alvo. Se usar container-name, verifique que o nome seja único quando necessário.

Armadilha de performance: animar propriedades de layout (height, width, margin) dentro de container queries aplicada frequentemente. Isso pode causar layout thrash se o container refazer cálculo a cada frame.

Tip: prefira transformar e opacity para animações. Se precisar animar o layout, faça isso fora de ciclos intensos ou use will-change com parcimônia.

Dicas práticas de debugging

Use DevTools (Chrome, Edge) que exibe contêineres e permite inspecionar container queries aplicadas. Ferramentas mostram quando uma regra @container está ativa; aproveite a aba Computed Styles para ver estilos resolvidos.

  • Verifique se o elemento tem container-type.
  • Teste com redimensionamento do próprio elemento no DevTools (resize handle).
  • Desative layers temporariamente com comentários para entender conflitos de cascade.

Uma técnica útil é simular diferentes contextos inserindo o componente em um iframe ou em um container com largura forçada via DevTools. Isso evita confundir behavior do viewport com comportamento do contêiner.

Erros comuns, armadilhas e dicas práticas

Problema: especificidade vs layers

Alguns desenvolvedores aumentam especificidade para vencer regras de bibliotecas. Com @layer, essa prática não é necessária na maioria dos casos. Organize layers: base < components < overrides. Se algo não aplicar, verifique a ordem de declaração e se o layer foi importado na ordem correta.

Problema: container query não reage

Checklist rápido: 1) existe container-type? 2) a sintaxe do @container está correta? 3) não há outro container pai que esteja limitando o espaço? 4) o elemento alvo está sendo realmente renderizado (display: none impede cálculo)?

Além disso, verifique se você não está confundindo min-width do container com min-width do viewport — eles são independentes.

Conclusao

Resumo prático

Container queries mudam como construímos componentes responsivos: passam o foco do viewport para o contexto local. Use container-type para habilitar, combine com @layer para controlar a cascade, e use nesting para manter o CSS legível. Para animações, prefira propriedades que não forcem reflow.

Refatore gradualmente: comece pelos componentes que mais sofrem com diferentes contextos (cards, list-items, navs). Evite aplicar container queries em excesso; prefira um design system claro com layers bem definidos.

Checklist final antes de pousar no prod

  1. Testar em cenários reais: grid, sidebar e small container.
  2. Validar performance: evitar animações que causem reflow pesado.
  3. Garantir ordem de layers e nomes de container sem colisões.
  4. Adicionar testes visuais e snapshots para variações de tamanho do contêiner.

Aplicando essas práticas você terá componentes mais previsíveis, menores folhas de estilo e menos css específico por contexto. Container queries, quando combinadas com layers, nesting e animações bem projetadas, elevam a qualidade do seu design system sem transtornar a manutenção.

Assuntos: CSS, container-queries, css-layers, css-nesting, animations

Leia também