Container queries CSS
Nesting manteve os seletores do componente juntos. Media queries ainda observam o viewport. Container queries respondem a outra pergunta: qual a largura desta caixa pai? Assim o mesmo cartão de produto fica compacto num rail estreito e abre na coluna principal — mesmo que a janela do browser não mude.
Por que o viewport não chega
Layouts colocam o mesmo componente em slots desiguais: um rail lateral de 16rem e uma área principal flexível. Os dois partilham a largura do viewport, logo @media (min-width: …) dispara igual nos dois. Precisas de estilos ligados ao contentor à volta do cartão, não ao ecrã inteiro.
Criar um contexto de contenção
Escolhe o pai que deve reportar o tamanho. Define container-type — em geral inline-size para consultar o tamanho inline do pai (largura em escrita horizontal) sem forçar contenção de tamanho nos dois eixos:
.rail {
container-type: inline-size;
container-name: rail;
width: 16rem;
padding: 1rem;
background: #f8fafc;
}
.stage {
container-type: inline-size;
container-name: stage;
flex: 1;
min-width: 0;
padding: 1.25rem;
}
Sem container-type, @container não tem nada fiável para medir. container-name é opcional mas útil quando vários antepassados são contentores — apontas a um pelo nome.
Consultar o contentor com @container
Depois da preparação, envolve regras em @container com uma condição de tamanho. Os descendentes reagem quando essa caixa corresponde — não só quando o viewport muda:
.product-card {
display: grid;
gap: 0.75rem;
padding: 1rem;
border: 1px solid #e2e8f0;
border-radius: 0.75rem;
background: #fff;
}
.product-card .media {
aspect-ratio: 16 / 10;
border-radius: 0.5rem;
background: #cbd5e1;
}
.product-card .meta {
font-size: 0.875rem;
color: #64748b;
}
@container (min-width: 28rem) {
.product-card {
grid-template-columns: 10rem 1fr;
align-items: center;
}
.product-card .title {
font-size: 1.25rem;
}
}
Num .rail estreito, o empilhamento numa coluna mantém-se. O mesmo HTML num .stage largo desbloqueia duas colunas — mesmo markup, mesmo viewport, largura de contentor diferente.
Contentores nomeados
Se contentores aninhados confundem qual caixa é consultada, indica o nome após @container:
@container stage (min-width: 36rem) {
.product-card {
grid-template-columns: 12rem 1fr auto;
gap: 1.25rem;
}
.product-card .buy {
justify-self: end;
}
}
@container rail (max-width: 18rem) {
.product-card .meta {
display: none;
}
}
@container stage (…) só olha para o antepassado chamado stage. Regras apertadas do rail não brigam com regras amplas do stage quando ambos envolvem markup relacionado.
Unidades de container query
Com contexto de contenção, comprimentos como cqi (1 % do inline-size do contentor de consulta) e cqw (1 % da largura) fazem tipo e espaçamento seguirem o pai, não o viewport (vi / vw):
.product-card .title {
font-size: clamp(1rem, 0.85rem + 2.5cqi, 1.5rem);
}
.product-card {
padding: clamp(0.75rem, 2.5cqi, 1.5rem);
}
Combina com var() e clamp() de lições anteriores do Modern Toolkit. Unidades de contentor medem o contexto usado na consulta — ideal para widgets reutilizáveis.
Contentor vs media — quem faz o quê?
📊 Container queries vs media queries
| Pergunta que fazes | Preferir | Ferramenta típica |
|---|---|---|
| Quão largo é o viewport do browser? | Shell da página, nav, página multicolumna | @media (min-width: …) |
| Quão largo é este pai à volta do componente? | Cartões, widgets, embeds em slots desiguais | @container (min-width: …) após container-type |
| Preciso dos dois? | Muitas vezes sim | MQ para a página; CQ para o componente no slot |
Dois slots, um componente
Um esboço pequeno mostra o ganho — dois contentores, uma classe de cartão:
.page {
display: flex;
gap: 1rem;
align-items: start;
}
.rail {
container-type: inline-size;
container-name: rail;
width: 16rem;
}
.stage {
container-type: inline-size;
container-name: stage;
flex: 1;
min-width: 0;
}
/* Same .product-card class in both slots — @container rules above decide layout */
Não precisas de .product-card--sidebar e .product-card--main só por causa da largura do slot. O slot reporta o tamanho; o cartão escuta.
Combinar media de página com contentores do componente
Guarda consultas de viewport para decisões de página (colapsar nav, shell numa coluna). Usa container queries para decisões de componente no slot que a página der:
@media (max-width: 40rem) {
.page {
flex-direction: column;
}
.rail {
width: auto;
}
}
@container (min-width: 28rem) {
.product-card {
grid-template-columns: 10rem 1fr;
}
}
Num telemóvel pequeno a página empilha; no desktop largo o rail pode continuar estreito e o stage largo — só container queries exprimem essa divisão com clareza.
Experimenta
- Adiciona
container-type: inline-sizea um wrapper do cartão; confirma o contexto de contenção no DevTools. - Escreve
@container (min-width: 24rem)para passar de empilhado a duas colunas. - Define
container-name: panele mira com@container panel (min-width: 30rem). - Tamanho de título com
cqie redimensiona só o pai (não a janela). - Mantém um
@mediano shell da página; não dupliques essa lógica dentro do cartão.
Erros comuns
@containersemcontainer-typenum antepassado — nada útil para medir- Substituir todas as media queries por container queries — o shell continua com
@media - Três contentores aninhados sem saber qual largura manda — nomeia e aponta explicitamente
- Copiar breakpoints de viewport (
48rem) cegamente a cada widget — ajusta ao slot, não ao catálogo de dispositivos - Confundir nesting (
&, seletores aninhados) com contenção — nesting organiza seletores; container queries medem caixas
Resumo
- Container queries estilam pelo tamanho do pai, não só o viewport
container-type(muitas vezesinline-size);container-nameopcional para clareza@container (min-width: …)/@container name (…)para reestilizar descendentescqi/cqwquando comprimentos devem seguir o contentor- A seguir no Modern Toolkit: feature queries (
@supports) — estilos conforme capacidade do browser
🧠 Teste Seu Conhecimento
Teste Seu Conhecimento
Desafie-se com este questionário interativo e veja o quão bem você entende o tópico
📝 Instruções
- Leia cada pergunta cuidadosamente
- Selecione a melhor resposta para cada pergunta
- Você pode refazer o quiz quantas vezes quiser
- Seu progresso será mostrado no topo