{"id":727,"date":"2026-09-17T18:34:48","date_gmt":"2026-09-17T21:34:48","guid":{"rendered":"https:\/\/yellowkode.com\/blog\/container-queries-css-componente-decide-layout\/"},"modified":"2026-09-17T18:34:48","modified_gmt":"2026-09-17T21:34:48","slug":"container-queries-css-componente-decide-layout","status":"publish","type":"post","link":"https:\/\/yellowkode.com\/blog\/container-queries-css-componente-decide-layout\/","title":{"rendered":"Container Queries no CSS: Quando o Componente Decide o Pr\u00f3prio Layout"},"content":{"rendered":"<h2>O fato<\/h2>\n<p>Em 16 de setembro de 2026, Victor Ayomipo publicou no Smashing Magazine o artigo <em>Stop Treating CSS Container Queries Like Traditional Media Queries<\/em>. A tese \u00e9 direta: container queries e media queries se parecem na sintaxe, e por isso quase todo mundo usa container queries errado, tratando como se fosse a mesma coisa. A ado\u00e7\u00e3o refor\u00e7a o argumento. Segundo a mesma mat\u00e9ria, citando o State of CSS, 86% dos desenvolvedores conhecem container queries, mas s\u00f3 41,4% usam. E n\u00e3o \u00e9 falta de suporte de navegador: o suporte cobre Chrome 105+, Firefox 110+, Safari 16+ e Edge 105+, com cobertura global de aproximadamente 90% em meados de 2026.<\/p>\n<p>Este artigo \u00e9 sobre <em>por que<\/em> as duas ferramentas resolvem problemas diferentes, e como parar de aplicar o modelo mental errado.<\/p>\n<h2>Como as duas coisas funcionam por baixo<\/h2>\n<h3>Media query pergunta para a janela<\/h3>\n<p>Quando voc\u00ea escreve <code>@media (min-width: 1024px)<\/code>, voc\u00ea est\u00e1 fazendo uma pergunta ao navegador sobre o viewport, ou seja, sobre a janela inteira do navegador. Nada mais. Se a janela tem 1920px de largura, a condi\u00e7\u00e3o dispara, independente de onde o componente que voc\u00ea est\u00e1 estilizando est\u00e1 posicionado dentro dessa janela.<\/p>\n<p>Isso \u00e9 o que Ayomipo chama de layout macro no artigo original, e \u00e9 uma boa forma de pensar: media query enxerga estrutura de p\u00e1gina. Cabe\u00e7alho que atravessa a tela, grid principal, prefer\u00eancia de tema escuro via <code>prefers-color-scheme<\/code>, orienta\u00e7\u00e3o do dispositivo. Coisas que s\u00e3o verdade sobre a p\u00e1gina inteira.<\/p>\n<h3>Container query pergunta para o pai<\/h3>\n<p>Container query inverte o eixo. Em vez de perguntar sobre a janela, o componente pergunta sobre o espa\u00e7o que o pai dele oferece. Diferente de media queries, container queries se estabelecem em duas partes: voc\u00ea define um container, e escreve estilos para um elemento filho que se aplicam quando o container pai satisfaz as condi\u00e7\u00f5es da consulta. Voc\u00ea define um container usando a propriedade container-type. Um container-type de inline-size permite consultar o eixo inline do container.<\/p>\n<p>Na pr\u00e1tica, o CSS fica assim:<\/p>\n<pre><code>.card-wrapper {\n container-type: inline-size;\n container-name: card;\n}\n\n@container card (min-width: 450px) {\n .card {\n display: flex;\n flex-direction: row;\n }\n}<\/code><\/pre>\n<p>Duas coisas importantes de entender aqui, porque \u00e9 onde as pessoas escorregam.<\/p>\n<p>Primeiro, inline-size \u00e9 um valor l\u00f3gico, ent\u00e3o se refere \u00e0 largura quando voc\u00ea usa modo de escrita horizontal (o padr\u00e3o), ou \u00e0 altura para modo de escrita vertical. N\u00e3o \u00e9 sin\u00f4nimo de <code>width<\/code>. \u00c9 o eixo de fluxo do texto. Em portugu\u00eas e ingl\u00eas, \u00e9 largura. Em japon\u00eas vertical, seria altura.<\/p>\n<p>Segundo, o <code>container-type: inline-size<\/code> aplica <em>containment<\/em>, que \u00e9 o que torna a consulta poss\u00edvel. Ambos os valores de container-type aplicam diferentes tipos de containment de tamanho. Containment inline-size em um elemento impede que seus descendentes afetem seu inline-size. Esse \u00e9 o pulo do gato: o navegador s\u00f3 consegue calcular o tamanho do container de forma isolada, sem consultar os filhos, porque sen\u00e3o voc\u00ea teria um loop (o filho depende do tamanho do pai, o tamanho do pai depende do filho).<\/p>\n<h3>A analogia que ajuda, e onde ela quebra<\/h3>\n<p>Pense numa loja de shopping. A media query \u00e9 o gerente que decide o layout inteiro do shopping olhando pelo telhado: hoje \u00e9 s\u00e1bado, ent\u00e3o abre corredor extra, muda o palco central de lugar, ativa ilumina\u00e7\u00e3o de fim de semana. Ele n\u00e3o sabe o que est\u00e1 acontecendo dentro de cada loja espec\u00edfica.<\/p>\n<p>A container query \u00e9 o gerente da loja individual. Ele n\u00e3o liga se o shopping \u00e9 grande ou pequeno. Ele mede o pr\u00f3prio ponto comercial dele e decide: aqui cabem duas prateleiras lado a lado, ou s\u00f3 uma empilhada. A decis\u00e3o \u00e9 local, e vale s\u00f3 ali dentro.<\/p>\n<p>Onde a analogia quebra: no shopping, cada loja escolhe o pr\u00f3prio layout sem ningu\u00e9m obrigar. No CSS, o container precisa ser <em>declarado<\/em> explicitamente com <code>container-type<\/code>, sen\u00e3o o filho n\u00e3o tem como consultar nada. Se voc\u00ea esquecer essa declara\u00e7\u00e3o, o <code>@container<\/code> simplesmente n\u00e3o dispara, e o pior \u00e9 que n\u00e3o d\u00e1 erro vis\u00edvel. Falha silenciosa \u00e9 o pior tipo de falha, porque o navegador aceitou seu c\u00f3digo e n\u00e3o te avisou onde parou.<\/p>\n<h2>O que muda na pr\u00e1tica: componente reutiliz\u00e1vel<\/h2>\n<p>O cen\u00e1rio que justifica container query \u00e9 o componente que aparece em mais de um contexto. Um card que existe no grid principal com 800px de largura, e tamb\u00e9m no sidebar com 280px. Com media query, esse card n\u00e3o tem como saber onde ele est\u00e1. Voc\u00ea acaba escrevendo variantes: <code>.card--wide<\/code>, <code>.card--sidebar<\/code>, e passando a decis\u00e3o para quem monta a p\u00e1gina. Isso funciona, mas empurra complexidade para fora do componente.<\/p>\n<p>Com container query, o card se resolve sozinho:<\/p>\n<pre><code>&lt;div class=\"card-slot\"&gt;\n &lt;article class=\"card\"&gt;\n &lt;img src=\"...\" alt=\"...\"&gt;\n &lt;div class=\"card-body\"&gt;\n &lt;h3&gt;T\u00edtulo&lt;\/h3&gt;\n &lt;p&gt;Texto&lt;\/p&gt;\n &lt;\/div&gt;\n &lt;\/article&gt;\n&lt;\/div&gt;<\/code><\/pre>\n<pre><code>.card-slot {\n container-type: inline-size;\n}\n\n.card {\n display: block;\n}\n\n@container (min-width: 420px) {\n .card {\n display: grid;\n grid-template-columns: 120px 1fr;\n gap: 1rem;\n }\n}<\/code><\/pre>\n<p>Repare que o container \u00e9 o <code>.card-slot<\/code>, n\u00e3o o <code>.card<\/code>. Isso \u00e9 obrigat\u00f3rio: um elemento n\u00e3o pode consultar a si mesmo. Voc\u00ea sempre precisa de um wrapper que sirva de refer\u00eancia de tamanho. Se voc\u00ea tentar botar <code>container-type<\/code> no pr\u00f3prio <code>.card<\/code> e consultar dentro, o navegador ignora e voc\u00ea fica horas procurando o bug.<\/p>\n<h3>Unidades de container: cqi, cqw, cqb<\/h3>\n<p>Junto com container queries vieram unidades relativas ao container, an\u00e1logas ao <code>vw<\/code> e <code>vh<\/code>. A mais \u00fatil no dia a dia \u00e9 <code>cqi<\/code>, que \u00e9 1% do inline-size do container mais pr\u00f3ximo. Isso permite tipografia que escala com o componente:<\/p>\n<pre><code>.card-title {\n font-size: clamp(1rem, 0.5rem + 3cqi, 2rem);\n}<\/code><\/pre>\n<p>Aqui a fonte tem ch\u00e3o de 1rem, teto de 2rem, e no meio escala com 3% do inline-size do container. Se o card est\u00e1 num sidebar de 300px, a fonte fica no ch\u00e3o. Se est\u00e1 num grid de 900px, encosta no teto. Sem depender do tamanho da janela.<\/p>\n<p>Isso resolve um problema que atormentava tipografia responsiva: voc\u00ea usava <code>vw<\/code>, o componente ia parar num sidebar, e a fonte ficava min\u00fascula porque a janela continuava grande mas o espa\u00e7o real era pequeno. A responsividade estava ancorada no lugar errado.<\/p>\n<p>Aqui vale um caso que vivi. Publicando design system e style guide de interface, uma das primeiras dores que aparece \u00e9 justamente essa: o mesmo componente precisa viver em contextos com larguras muito diferentes, e antes de container queries a \u00fanica sa\u00edda era gerar variantes tipadas do componente. Isso funciona, mas o custo de manter as variantes coerentes cresce em cada tela nova. Container query encolhe esse custo porque o componente vira respons\u00e1vel pela pr\u00f3pria adapta\u00e7\u00e3o, e o design system fica com menos regras condicionais de composi\u00e7\u00e3o.<\/p>\n<h2>Onde container queries quebram<\/h2>\n<h3>Consultar o eixo block colapsa o layout<\/h3>\n<p>Se voc\u00ea usar <code>container-type: size<\/code> em vez de <code>inline-size<\/code>, o navegador aplica containment nos dois eixos. E a\u00ed o container passa a ignorar os filhos para calcular a altura. Sem altura expl\u00edcita, o container fica com 0px, e o layout desmonta. Sim, d\u00e1 para consultar altura, mas voc\u00ea precisa usar container-type: size em vez de inline-size. O containment de tamanho total se aplica em ambas as dimens\u00f5es, o que impede o container de derivar sua altura dos filhos. Use isso apenas quando realmente precisar de consultas baseadas em altura, como em pain\u00e9is de dashboard redimension\u00e1veis pelo usu\u00e1rio. Regra pr\u00e1tica: use <code>inline-size<\/code> por padr\u00e3o, e s\u00f3 suba para <code>size<\/code> quando voc\u00ea tem uma altura fixa ou <code>aspect-ratio<\/code> definida.<\/p>\n<h3>Custom properties n\u00e3o funcionam como valor de query<\/h3>\n<p>Voc\u00ea n\u00e3o consegue fazer isto:<\/p>\n<pre><code>:root { --breakpoint-lg: 1600px; }\n\n\/* N\u00c3O FUNCIONA *\/\n@container (min-width: var(--breakpoint-lg)) {\n .card { display: flex; }\n}<\/code><\/pre>\n<p>A raz\u00e3o \u00e9 estrutural: custom properties cascateiam pela \u00e1rvore do DOM, e uma query que depende de custom property poderia disparar uma mudan\u00e7a que altera essa mesma custom property. O sistema declara onde ele para em vez de tentar resolver o loop. \u00c9 a coisa certa a fazer, mas quebra a expectativa de quem quer centralizar breakpoints em vari\u00e1veis.<\/p>\n<h3>Style queries com custom properties ainda s\u00e3o limitadas<\/h3>\n<p>Existem tamb\u00e9m style queries, que consultam estilos computados do container em vez do tamanho. Mas o estado ainda n\u00e3o \u00e9 uniforme: quanto a container style queries usando custom properties como condi\u00e7\u00e3o, cabe ao Firefox adicionar suporte. Eu estou otimista de que veremos suporte chegar no Firefox em 2026. Se voc\u00ea quer aplicar estilos com base nos estilos do container, voc\u00ea precisa esperar at\u00e9 que a disponibilidade limitada entre navegadores melhore. Se voc\u00ea n\u00e3o pode escolher o navegador do usu\u00e1rio, style queries com custom properties ainda s\u00e3o territ\u00f3rio de progressive enhancement.<\/p>\n<h3>Quando n\u00e3o vale a pena<\/h3>\n<p>Se o componente s\u00f3 existe num contexto (por exemplo, o header principal do site, que s\u00f3 aparece uma vez e sempre com a largura total da janela), container query s\u00f3 adiciona uma camada de indire\u00e7\u00e3o sem benef\u00edcio. Media query resolve, e voc\u00ea economiza um wrapper. N\u00e3o \u00e9 para substituir todas as media queries por container queries. Use media queries para decis\u00f5es de layout no n\u00edvel da p\u00e1gina e container queries para responsividade no n\u00edvel do componente. Muitos projetos se beneficiam de ambos: um grid de topo troca colunas com @media, enquanto cards individuais dentro desse grid se adaptam com @container.<\/p>\n<h2>O que ainda n\u00e3o d\u00e1 para afirmar<\/h2>\n<p>Duas coisas o material n\u00e3o esclarece bem.<\/p>\n<p>Primeiro, o custo de performance de ter muitos containers ativos numa p\u00e1gina. Cada <code>container-type: inline-size<\/code> aplica containment, que envolve isolamento de layout. Em teoria isso pode ajudar performance (o navegador pode recalcular menos coisas), mas em p\u00e1ginas com centenas de containers ningu\u00e9m publicou benchmark claro. N\u00e3o testei em escala e o artigo do Smashing n\u00e3o entra nesse ponto.<\/p>\n<p>Segundo, a intera\u00e7\u00e3o com frameworks que fazem hidrata\u00e7\u00e3o parcial ou streaming SSR. Se o container \u00e9 renderizado depois do filho, a primeira medida pode disparar estilos que somem no pr\u00f3ximo frame. Isso \u00e9 problema resolv\u00edvel, mas n\u00e3o vi ainda um padr\u00e3o consolidado.<\/p>\n<h2>Como testar isso voc\u00ea mesmo<\/h2>\n<p>Um caminho pequeno para experimentar em 15 minutos:<\/p>\n<ul>\n<li>Crie um HTML com dois wrappers: um com <code>width: 300px<\/code> e outro com <code>width: 800px<\/code>. Dentro de cada um, coloque o mesmo componente card com imagem e texto.<\/li>\n<li>Aplique <code>container-type: inline-size<\/code> nos wrappers.<\/li>\n<li>Escreva um <code>@container (min-width: 500px)<\/code> que muda o card de <code>display: block<\/code> para <code>display: grid<\/code> com duas colunas.<\/li>\n<li>Abra no navegador. O card no wrapper de 300px vai ficar empilhado. O de 800px vai ficar em duas colunas. Sem tocar em media query, sem redimensionar a janela.<\/li>\n<li>Agora abra o DevTools do Chrome, inspecione um dos wrappers, e observe que aparece um badge de container. Voc\u00ea consegue redimensionar direto ali e ver o breakpoint disparando.<\/li>\n<\/ul>\n<p>Feito isso, o modelo mental gruda. O componente para de perguntar sobre a janela e passa a perguntar sobre o pr\u00f3prio espa\u00e7o. \u00c9 uma mudan\u00e7a pequena de sintaxe, e uma mudan\u00e7a grande de responsabilidade.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Como container queries diferem de media queries no CSS, quando usar cada uma, exemplos com inline-size, unidades cq e onde a t\u00e9cnica quebra.<\/p>\n","protected":false},"author":2,"featured_media":726,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-727","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/yellowkode.com\/blog\/wp-json\/wp\/v2\/posts\/727","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/yellowkode.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/yellowkode.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/yellowkode.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/yellowkode.com\/blog\/wp-json\/wp\/v2\/comments?post=727"}],"version-history":[{"count":0,"href":"https:\/\/yellowkode.com\/blog\/wp-json\/wp\/v2\/posts\/727\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/yellowkode.com\/blog\/wp-json\/wp\/v2\/media\/726"}],"wp:attachment":[{"href":"https:\/\/yellowkode.com\/blog\/wp-json\/wp\/v2\/media?parent=727"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/yellowkode.com\/blog\/wp-json\/wp\/v2\/categories?post=727"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/yellowkode.com\/blog\/wp-json\/wp\/v2\/tags?post=727"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}