12k
All articles

Quando Usar CSS `if()` vs Container Style Queries

Compare CSS if() e container style queries: quando usar cada uma, erros de sintaxe, range syntax e suporte dos navegadores em 2026.

OpenReplay Team
OpenReplay Team
Quando Usar CSS `if()` vs Container Style Queries

Use a função CSS if() quando um único elemento deve decidir seu próprio valor de forma inline — tokens de tema, estados de componente, um ajuste pontual de propriedade responsiva. Recorra a uma container style query (@container style(...)) quando o estilo de um elemento pai deve controlar um conjunto de regras em vários descendentes. O modelo mental em uma linha: if() produz um valor condicional local ao elemento; uma container style query estabelece contexto, aplicando blocos de regras condicionais de um pai para seus filhos.

Ambos são mecanismos de CSS condicional que leem custom properties, ambos utilizam a mesma primitiva style(), e suas capacidades se sobrepõem o suficiente para que escolher o errado resulte em código confuso. Este artigo resolve essa sobreposição: o que cada um faz, a diferença mecânica que determina qual usar, as duas armadilhas de sintaxe que pegam as pessoas de surpresa (ponto e vírgula e a notação de dois-pontos vs. sinal de igual), a sintaxe de intervalo agora presente em ambos, uma tabela de decisão por cenário, e como publicar qualquer um deles considerando que o suporte dos navegadores está dividido em três frentes em meados de 2026.

Principais Conclusões

  • if() lê custom properties declaradas na mesma regra do mesmo elemento e retorna um valor; @container style() sempre olha para cima na cascata e aplica blocos de regras inteiros aos descendentes.
  • Dentro de if(), ponto e vírgula (não vírgulas) separam os pares condição–valor, e else fornece o fallback; sem nenhuma condição correspondente e sem else, a função retorna um valor garantidamente inválido que resolve para o valor inicial da propriedade.
  • Dentro de style(), a notação de dois-pontos (style(--n: 3)) faz correspondência de tokens/strings sem matemática, enquanto a notação com operador de comparação (style(--n = 3)) analisa ambos os lados numericamente e avalia calc() primeiro.
  • Em meados de 2026, o suporte diverge: container style queries básicas estão disponíveis nos quatro principais engines (Chrome 111+, Edge 111+, Safari 18+, Firefox 151+), enquanto if() e a sintaxe de intervalo ativada por padrão permanecem exclusivas do Chromium.
  • Como if() é exclusivo do Chromium, toda declaração if() precisa de um fallback na mesma propriedade antes dela ou de um guard @supports.

O que cada mecanismo é, de forma mínima

A função if() é um condicional em nível de valor que você coloca dentro de qualquer propriedade. Seu argumento é uma lista de pares condição–valor separados por ponto e vírgula, onde cada condição é separada do seu valor por dois-pontos, e um else opcional fornece o padrão:

.badge {
  color: if(
    style(--variant: danger): white;
    style(--variant: muted): #555;
    else: black;
  );
}

Cada condição é um de três tipos de query:

  • style() testa uma custom property no elemento atual;
  • media() executa uma media query inline;
  • supports() executa uma feature query.

A referência do MDN documenta os três com a mesma gramática de ponto e vírgula — por exemplo, flex-direction: if(media(orientation: landscape): row; else: column;) alterna uma única propriedade com base em um resultado de media.

Uma container style query é uma at-rule @container cuja condição é uma ou mais notações style() lendo as custom properties de um elemento contêiner. Ela envolve um bloco de regras em vez de produzir um único valor:

.card { --status: active; }

@container style(--status: active) {
  .card-title { font-weight: 700; }
  .card-icon { opacity: 1; }
  .card-meta { color: green; }
}

Conforme o guia de container queries do MDN, todo elemento é um style container por padrão — ao contrário das size queries, definir um container-type não é necessário para style queries. Isso elimina o principal atrito de configuração que as pessoas esperam das container queries.

A distinção central que determina o uso

A diferença mecânica está no escopo de leitura. if() lê custom properties declaradas na mesma regra do mesmo elemento e é autocontido, enquanto @container style() sempre olha para cima na cascata em direção a um contêiner ancestral. O MDN afirma isso diretamente: usar uma style query dentro de if() permite segmentar um elemento com base em se uma custom property está definida nele, em vez de verificar estilos em um pai. Os dois são explicitamente apresentados como complementares, não redundantes.

Essa diferença no escopo de leitura tem três consequências práticas:

  1. Granularidade de saída. if() define exatamente um valor. @container aplica um bloco de regras inteiro — múltiplas declarações em múltiplos seletores — quando sua condição é verdadeira. Como o MDN coloca, você só pode definir valores de propriedade única com style queries em if(), enquanto queries @container aplicam condicionalmente conjuntos inteiros de regras.

  2. Direção. if() pode ler uma propriedade declarada no próprio elemento que está estilizando. @container não pode ler o valor do seu próprio elemento para estilizá-lo; ele lê o de um ancestral e estiliza os descendentes.

  3. Escopo. Apenas container style queries podem definir escopo por container-name. Nomeie um contêiner e a query é avaliada apenas em relação a esse contêiner; se o contêiner nomeado não definir a propriedade consultada, o bloco simplesmente não é executado. if() não tem controle de escopo equivalente — ele sempre resolve em relação ao elemento em que está.

Portanto, o critério de desempate na zona de sobreposição é: se uma propriedade em um elemento deve ser alternada, if() tem menos indireção. Se vários descendentes devem reagir a um valor pai, @container expressa isso com uma única condição em vez de repetir if() em cada filho.

As armadilhas de sintaxe que pegam as pessoas de surpresa

Ponto e vírgula, não vírgulas, separam os pares em if(). Isso tropeça todo mundo que vem do JavaScript ou de funções CSS separadas por vírgula como rgb(). A gramática é if(condição-1: valor-1; condição-2: valor-2; else: fallback), com o ponto e vírgula após o último par sendo opcional. Também não deve haver espaço entre if e o parêntese de abertura, ou toda a declaração é inválida. E quando nenhuma condição corresponde e você omitiu else, if() retorna um valor garantidamente inválido — em um contexto de propriedade normal, isso resolve para o valor inicial da propriedade, o que raramente é o que você quer. Sempre inclua else.

A distinção entre dois-pontos e sinal de igual dentro de style() é o detalhe sutil e de alto valor que quase ninguém explica. Tanto if() quanto container style queries aceitam duas notações com comportamentos genuinamente diferentes, agora documentadas no MDN.

A notação simples (dois-pontos) faz correspondência de tokens/strings de valores computados e não realiza matemática. A notação de intervalo (operador) — usando =, <, <=, > ou >= — resolve cada lado, analisa ambos como tipo numérico, avalia qualquer calc() e compara numericamente. A consequência, diretamente do exemplo do próprio MDN:

.box { --n: calc(6 / 2); }

/* FALSO: o valor computado de --n é a string "calc(6/2)",
   que não é o token "3" */
@container style(--n: 3) { /* … */ }

/* VERDADEIRO: ambos os lados são analisados como <number>, calc(6/2) computa para 3,
   e 3 = 3 */
@container style(--n = 3) { /* … */ }

Portanto, style(--n: 3) falha contra --n: calc(6/2), enquanto style(--n = 3) tem sucesso. Mais duas regras importam. Com a notação simples, o nome da custom property deve estar à esquerda sem var()style(var(--n): 3) é inválido — enquanto a notação de intervalo aceita um nome, var(), literal ou calc() em qualquer lado em qualquer ordem. E valores equivalentes (como blue e #0000ff) só correspondem com a notação de dois-pontos se a propriedade for registrada com @property e um descritor syntax. A conclusão: use a notação de dois-pontos para correspondência de palavras-chave/strings (style(--theme: dark)), e a notação de operador para comparação numérica (style(--columns >= 3)).

A sintaxe de intervalo agora existe em ambos

A sintaxe de intervalo estende ambos os mecanismos além da correspondência exata para comparação numérica, extraindo operandos de custom properties, attr() ou valores literais. Conforme as notas de lançamento do Chrome 142, uma comparação só resolve quando ambos os lados resolvem para o mesmo tipo de dado, limitado a sete tipos numéricos: <length>, <number>, <percentage>, <angle>, <time>, <frequency> e <resolution>. A forma de intervalo com três valores também funciona — @container style(0 < --n < 10) — com ambos os comparadores apontando na mesma direção.

A sintaxe de intervalo é o que torna padrões como um badge de notificação limpos. Leia uma contagem de um atributo e ramifique em limites:

@container style(--count > 99) {
  .badge::after { content: "99+"; }
}

Como a notação de intervalo analisa numericamente, style(--s = new) é falso para uma palavra-chave como new, enquanto style(--s: new) é verdadeiro — mais um motivo pelo qual a escolha da notação é determinante.

Qual usar, por cenário

CenárioUtilizePor quê
Token de tema → uma propriedade (ex.: color de --theme)if()Um elemento decide seu próprio valor inline
Estado de componente altera vários estilos filhos (ativo/erro)@container style()Um valor pai controla um bloco de regras nos descendentes
Ajuste responsivo em uma única propriedadeif() com media()Lógica localizada por propriedade; sem necessidade de bloco @media
Limites de badge de contagem de notificaçõesQualquer um, via sintaxe de intervalo@container se irmãos também reagem; if() se apenas o badge muda
Texto com contraste adaptado em um pai com tema@container style()Filhos leem o tema do pai e se reestilizam juntos
Valor com feature gate (ex.: lch() com fallback)if() com supports()Troca de valor único por suporte
Mudança de layout com múltiplas propriedades em um breakpoint@media (nenhum dos dois)Ambos são a ferramenta errada para grandes mudanças de layout

A regra geral: um valor condicional em um elemento é trabalho para if(); um contexto condicional que reestiliza uma subárvore é trabalho para uma container query.

Publicando em 2026

O suporte dos navegadores está dividido em três frentes, e a antiga visão de “CSS condicional é exclusivo do Chromium” não é mais precisa. Suporte dos navegadores em junho de 2026:

RecursoChrome / EdgeSafariFirefox
Container style queries (custom properties, sintaxe simples)111+18+151+
Função if()137+Não disponívelNão disponível
Sintaxe de intervalo em style() / if()142+ (ativada por padrão)Não disponível151, atrás de layout.css.attr.enabled

Container style queries básicas agora são genuinamente cross-engine. Foram lançadas no Chrome e Edge 111, chegaram ao WebKit no Safari 18.0, e chegaram ao Firefox 151, lançado em 19 de maio de 2026, que adicionou suporte a queries style() do @container baseadas em custom properties de um contêiner. A função if(), por outro lado, permanece exclusiva do Chromium — o MDN a sinaliza como experimental com disponibilidade limitada — e a sintaxe de intervalo está ativada por padrão apenas no Chromium. O Firefox 151 inclui a sintaxe de intervalo style() do @container, mas desativada por padrão, atrás da preferência layout.css.attr.enabled.

A conclusão prática: if() não degrada graciosamente, portanto escreva uma declaração padrão primeiro e deixe os navegadores com suporte sobrescrevê-la, ou envolva a regra em um guard @supports. Um padrão cobre ambos os mecanismos:

/* fallback primeiro — todo navegador aplica isso */
.card-title { font-weight: 400; }

/* progressive enhancement: apenas engines com suporte a style query aplicam isso */
@supports (container-type: normal) {
  @container style(--status: active) {
    .card-title { font-weight: 700; }
  }
}

/* if(): valor estático primeiro, depois o override condicional */
.badge { padding: 0.25em; }
.badge { padding: if(style(--size: lg): 0.5em; else: 0.25em); }

Como if() e a sintaxe de intervalo ativada por padrão ainda renderizam pelo caminho de fallback no Firefox e Safari — navegadores que um desenvolvedor que usa Chrome raramente abre durante o desenvolvimento — a reprodução de sessão cross-browser é uma técnica útil para realmente observar o branch de fallback renderizando em um navegador real de um usuário, em vez de presumir que está correto. Para os padrões mais profundos de calc() e aninhamento dentro de if(), o guia orientado a decisões do LogRocket vai além do que cabe aqui.

Escolha pela intenção, não pela novidade: um valor condicional em um elemento é para if(); um contexto condicional que reestiliza uma subárvore a partir de um pai é para uma container style query. Publique qualquer um com um fallback hoje, verifique novamente a matriz de suporte antes de confiar em if() em produção, e os dois cobrirão cada vez mais o espaço de CSS condicional que antes exigia hacks com custom properties e JavaScript.

Perguntas Frequentes

Container style queries podem ler a custom property do próprio elemento, como if() faz?

Não. Uma container style query sempre olha para cima na cascata em direção a um contêiner ancestral e aplica suas regras aos descendentes, portanto não pode ler uma custom property no próprio elemento que estilizaria. A função if() é o oposto: ela lê custom properties declaradas na mesma regra do mesmo elemento e resolve um valor inline. Se você precisa que um elemento ramifique com base em sua própria propriedade, use if(); se o valor de um pai deve reestilizar seus filhos, use uma container style query.

Container style queries exigem a definição de um container-type, como as size queries exigem?

Não. Todo elemento é um style container por padrão, portanto style queries em custom properties funcionam sem declarar container-type. Isso difere das container size queries, que exigem container-type (como inline-size) no ancestral consultado antes que qualquer condição de tamanho possa ser resolvida. Isso está documentado no guia de container queries do MDN e elimina a principal etapa de configuração que os desenvolvedores esperam ao usar pela primeira vez a at-rule @container.

Por que minha style query com calc() nunca corresponde?

Porque a notação simples de dois-pontos faz correspondência de tokens e strings sem matemática. Uma propriedade definida como calc(6 / 2) computa para a string 'calc(6/2)', que nunca corresponde ao token 3, portanto style(--n: 3) retorna falso. Para comparar numericamente, use a notação com operador de comparação, style(--n = 3), que resolve cada lado, avalia calc(), analisa ambos como tipo numérico e compara numericamente, retornando verdadeiro. Use a forma de dois-pontos para correspondência de palavras-chave e a forma de operador para comparação numérica.

if() degrada graciosamente no Safari e no Firefox?

Não. Em meados de 2026, if() está disponível apenas em navegadores Chromium (Chrome e Edge 137+), portanto Safari e Firefox ignoram qualquer declaração que o contenha e recorrem ao valor que estava aplicado antes. Escreva uma declaração estática padrão primeiro e deixe os navegadores com suporte sobrescrevê-la, ou envolva a regra condicional em um guard @supports. Container style queries básicas são mais seguras cross-engine, disponíveis no Chrome 111+, Edge 111+, Safari 18+ e Firefox 151+, mas a sintaxe de intervalo ativada por padrão permanece exclusiva do Chromium.

Open-source session replay

Complete picture for complete understanding

Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.