Pular para o conteúdo
~/.primo-academy.sh
☰ Aulas · CSS · 0/36
Recomendado: essencial

Container Queries: @container Responde ao Pai

3 min de leitura

fonte

Por décadas, o CSS teve um único ponto de referência para "como eu me adapto": a tela inteira (@media). Container queries mudam isso. Agora, um componente pode se adaptar ao tamanho do seu próprio pai, e não ao tamanho da janela.

É a feature que destrava componentes verdadeiramente reutilizáveis: o mesmo card funciona em uma sidebar estreita e em uma página cheia, reagindo ao espaço que tem disponível.

O problema antes das container queries

Imagine um card de produto que aparece em vários contextos:

  • Homepage: 3 colunas, card tem 400px.
  • Sidebar: 1 coluna estreita, card tem 200px.
  • Página de detalhe: 1 coluna larga, card tem 800px.

Com media queries, você estilizava pela tela. Mas o breakpoint que importa é o tamanho do card, não o da tela. E a tela é uma proxy ruim - o mesmo 1200px de tela tem o card em 200px na sidebar e em 800px no conteúdo principal.

/* Media queries - proxy ruim */
@media (max-width: 600px) {
  .card { /* ... */ }
}

/* Se o card está numa sidebar de 200px dentro de uma tela de 1500px,
   a media query não dispara. */

A solução: container queries

.card-wrapper {
  container-type: inline-size;
  container-name: card;
}

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

@container card (max-width: 399px) {
  .card {
    display: block;  /* imagem em cima, texto embaixo */
  }
}

A @container olha o tamanho do container (no caso, o .card-wrapper com container-type: inline-size) e aplica regras baseadas nisso. O card passa a ser autônomo - não importa onde ele está, ele se adapta.

container-type: definindo o que medir

.card-wrapper {
  container-type: inline-size;   /* mede largura inline (X) */
  /* ou: size (mede largura E altura) */
  /* ou: normal (default - sem container query) */
}
  • inline-size: o mais comum. Mede a largura (no caso de LTR, o eixo horizontal). É o que você precisa em 95% dos casos.
  • size: mede largura E altura. Útil em casos raros (componente que precisa saber se está "alto" ou "largo").

container-name: identificando o container

.sidebar { container-name: sidebar; }
.main    { container-name: main; }

@container sidebar (min-width: 300px) { /* ... */ }
@container main (min-width: 800px)    { /* ... */ }

Quando o mesmo elemento tem vários ancestrais candidatos a container, nomeá-los permite escolher qual consultar. Sem nome, a @container olha o ancestral container mais próximo.

A regra de ouro dos containers

.card-wrapper {
  container-type: inline-size;
}

Tem que ser o ancestral do elemento que vai reagir à query. O container tem que ser direto (ou ancestral comum) dos elementos estilizados. Filhos ou netos do wrapper respondem à query; o próprio wrapper não responde a si mesmo.

cqi e cqw: unidades relativas ao container

.card {
  font-size: clamp(1rem, 3cqi, 1.5rem);  /* 3% da largura inline do container */
  padding: 2cqw;                          /* 2% da largura do container */
}
  • cqi (container query inline): 1% da largura inline do container.
  • cqw (container query width): 1% da largura do container.
  • São equivalentes para LTR; diferem em escritas verticais.

Combinado com clamp(), dá pra fazer tipografia que escala com o container, não com a tela:

.card h2 {
  font-size: clamp(1.2rem, 5cqi, 2.5rem);
}

O título é grande quando o card tem muito espaço, e pequeno quando está apertado - sozinho, sem media query.

Suporte e fallback

Container queries têm suporte amplo em navegadores modernos (Chrome 105+, Safari 16+, Firefox 110+). Para projetos que precisam suportar navegadores muito antigos, a abordagem é progressive enhancement: o CSS padrão (sem @container) já precisa estar usável, e o @container "melhora" em navegadores que suportam.

/* Funciona em qualquer lugar */
.card {
  display: block;
}

/* Melhora em navegadores com container query */
@container (min-width: 400px) {
  .card {
    display: grid;
    grid-template-columns: 1fr 2fr;
  }
}
  • container-type: inline-size define o que medir.
  • @container (min-width: N) aplica regras baseadas no container.
  • cqi / cqw são unidades relativas ao container.
  • Combinar com clamp() faz tipografia que escala com o componente, não com a tela.

Dica: a primeira vez que você usa container query em produção, a sensação é "isso sempre deveria ter existido". É o tipo de feature que muda a forma de pensar componentes. Um .card deixa de ser "estilizado pra 400px" e passa a ser "se adapta a qualquer largura". É a mesma ideia dos componentes de frameworks JS, mas sem o framework.

No próximo nó, vamos ver o :has() - o "seletor pai" que o CSS prometeu há anos e finalmente entregou.

// recursos

// avaliação da trilha

ainda sem avaliações