CSS Container Queries na Prática: Componentes Que Se Adaptam ao Próprio Contexto
O problema que media queries nunca resolveram
Você tem um card de produto. Ele aparece em três lugares: sidebar de 300px, grid principal de 2 colunas e uma landing page com layout de coluna única. Com media queries, você estiliza baseado na viewport. Mas a viewport não muda quando o card sai da sidebar e vai para o grid: o que muda é o contêiner onde ele está.
Esse é o problema central. Media queries respondem ao tamanho da janela do navegador. Container Queries respondem ao tamanho do elemento pai. A diferença parece sutil até você tentar criar um design system com componentes reutilizáveis. Quando o mesmo componente precisa funcionar em contextos com larguras diferentes, media queries forçam você a criar variantes manuais, passar props de tamanho, ou acoplar o componente ao layout da página.
Container Queries eliminam esse acoplamento. O componente se adapta sozinho ao espaço disponível, sem saber nada sobre a página onde está.
Como funciona: containment context
Para usar Container Queries, você precisa de duas coisas: declarar um contêiner e escrever queries contra ele.
/* O pai precisa ser declarado como contêiner.
container-type: inline-size observa apenas a largura,
que é o caso de uso mais comum e o mais seguro para evitar
loops de layout infinitos. */
.card-wrapper {
container-type: inline-size;
container-name: card;
}
/* A query usa @container em vez de @media */
@container card (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 200px 1fr;
gap: 1rem;
}
}
@container card (max-width: 399px) {
.card {
display: flex;
flex-direction: column;
}
}
O container-type: inline-size é a escolha padrão. Existe container-type: size (observa largura e altura), mas ele exige que o contêiner tenha dimensões explícitas nas duas direções, o que raramente faz sentido para layouts web fluidos.
A propriedade container-name é opcional. Sem ela, @container faz query contra o contêiner ancestral mais próximo. Nomear é útil quando você tem contêineres aninhados e precisa ser específico sobre qual está consultando.
Um componente de card completo e funcional
/* card.css */
.product-card-container {
container-type: inline-size;
container-name: product-card;
}
.product-card {
border: 1px solid #e2e8f0;
border-radius: 8px;
overflow: hidden;
background: #fff;
}
.product-card__image {
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
}
.product-card__body {
padding: 1rem;
}
.product-card__title {
font-size: 1rem;
margin: 0 0 0.5rem;
}
.product-card__price {
font-size: 1.25rem;
font-weight: 700;
color: #1a202c;
}
.product-card__actions {
display: flex;
flex-direction: column;
gap: 0.5rem;
margin-top: 1rem;
}
/* Quando o contêiner tem pelo menos 400px,
o card muda para layout horizontal */
@container product-card (min-width: 400px) {
.product-card {
display: grid;
grid-template-columns: 200px 1fr;
}
.product-card__image {
aspect-ratio: 1;
height: 100%;
}
.product-card__actions {
flex-direction: row;
}
}
/* Acima de 600px, o card ganha mais espaço e
ajusta tipografia para compensar a largura */
@container product-card (min-width: 600px) {
.product-card {
grid-template-columns: 250px 1fr;
}
.product-card__title {
font-size: 1.25rem;
}
.product-card__price {
font-size: 1.5rem;
}
}
<!-- O HTML não muda independente de onde o card aparece -->
<div class="product-card-container">
<article class="product-card">
<img
class="product-card__image"
src="/images/product-keyboard.jpg"
alt="Teclado mecânico com switches brown"
/>
<div class="product-card__body">
<h3 class="product-card__title">Teclado Mecânico TKL</h3>
<span class="product-card__price">R$ 349,90</span>
<div class="product-card__actions">
<button type="button">Adicionar ao carrinho</button>
<button type="but
---
Leia o artigo completo em [https://www.vivodecodigo.com.br/react/css-container-queries-componentes-adaptam-proprio-contexto](https://www.vivodecodigo.com.br/react/css-container-queries-componentes-adaptam-proprio-contexto)