Feature queries CSS
As container queries perguntam a largura de um pai. As media queries olham para o viewport. As feature queries fazem outra pergunta: este browser entende este CSS? Com @supports, entregas uma base sólida e só desbloqueias layout ou seletores modernos onde eles funcionam.
Melhoria progressiva, não um jogo de sorte
Uma feature query é um portão de capacidade. Não apagas os estilos antigos — manténs um layout que funciona em todo o lado e, dentro de @supports, acrescentas uma camada mais rica quando o motor consegue fazer parse da funcionalidade (por exemplo display: grid ou gap em flex).
Forma básica de @supports
A forma habitual testa um par propriedade–valor. Se o browser trata essa declaração, as regras aninhadas aplicam-se:
.card-list {
display: block;
}
.card-list .card {
margin-bottom: 1rem;
padding: 1rem;
border: 1px solid #e2e8f0;
border-radius: 0.75rem;
background: #fff;
}
@supports (display: grid) {
.card-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
gap: 1rem;
}
.card-list .card {
margin-bottom: 0;
}
}
Fora do bloco, os cartões empilham com uma margem simples. Dentro de @supports (display: grid), a mesma lista vira uma grelha responsiva — motores antigos mantêm a pilha; os modernos recebem a grelha.
Combinar condições: and, or, not
Podes exigir várias funcionalidades, aceitar alternativas ou inverter um teste:
@supports (display: grid) and (gap: 1rem) {
.toolbar {
display: grid;
grid-auto-flow: column;
gap: 0.75rem;
align-items: center;
}
}
@supports (display: flex) or (display: grid) {
.cluster {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
}
@supports not (display: grid) {
.card-list .card {
max-width: 36rem;
}
}
and aperta o portão (os dois têm de passar). or alarga-o. not estiliza o caminho sem suporte — útil para um fallback deliberado, desde que esse fallback fique legível e completo.
Testar seletores com selector()
Algumas funcionalidades são seletores, não propriedades. Envolve-as em selector() para a query perguntar: «consegues fazer parse deste seletor?»
.nav a {
color: #0f172a;
text-decoration: none;
}
@supports selector(:has(*)) {
.nav:has(a:focus-visible) {
outline: 2px solid #2563eb;
outline-offset: 4px;
}
.card:has(img) .title {
font-weight: 700;
}
}
Sem selector(), um :has() nu dentro de @supports não é o padrão fiável. Com ele, browsers sem :has() simplesmente saltam as regras enriquecidas e mantêm os estilos de link da base.
Quem faz que pergunta?
📊 Media, container, and feature queries
| Pergunta que estás a fazer | Preferir | Ferramenta típica |
|---|---|---|
| Qual a largura do viewport / contexto do dispositivo? | Cascão da página, breakpoints | @media (…) |
| Qual a largura deste pai à volta do componente? | Cartões em slots desiguais | @container (…) depois de container-type |
| O browser suporta este CSS? | Melhoria progressiva | @supports (…) / selector(…) |
Estas ferramentas encaixam bem: media para a página, container para o slot, @supports para capacidade. Não uses @supports para fingir um breakpoint, nem @media para fingir um teste de funcionalidade.
Base primeiro, enriquecimento depois
Um padrão prático mantém o aspeto partilhado fora do portão e melhora o layout dentro:
.feature-panel {
padding: 1.25rem;
border-radius: 0.75rem;
background: #f8fafc;
color: #0f172a;
}
.feature-panel .lead {
margin: 0 0 0.75rem;
font-size: 1.125rem;
line-height: 1.5;
}
.feature-panel .actions {
display: block;
}
.feature-panel .actions a {
display: inline-block;
margin: 0.25rem 0.5rem 0.25rem 0;
padding: 0.5rem 0.875rem;
border-radius: 0.5rem;
background: #e2e8f0;
color: inherit;
text-decoration: none;
}
@supports (display: flex) and (gap: 0.5rem) {
.feature-panel .actions {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.feature-panel .actions a {
margin: 0;
}
}
Todo o browser recebe padding, tipografia e links clicáveis. Flex + gap só aparecem quando ambos são entendidos — sem buraco vazio se um faltar.
Nesting e @supports juntos
As peças do Modern Toolkit combinam-se. O nesting organiza seletores; @supports continua a ser o portão de capacidade:
.pricing {
padding: 1rem;
border: 1px solid #e2e8f0;
}
@supports (display: grid) {
.pricing {
display: grid;
gap: 1rem;
& .tier {
padding: 1rem;
background: #fff;
}
& .tier .price {
font-size: 1.5rem;
font-weight: 700;
}
}
}
Se o próprio nesting não for suportado, mantém um equivalente plano fora ou aceita que a forma aninhada faz parte do caminho enriquecido — a mesma mentalidade de melhoria progressiva.
Experimenta tu
- Estiliza uma lista como pilha vertical simples e envolve um layout Grid em
@supports (display: grid). - Exige
gapcomandpara o espaçamento flex/grid não aplicar a meio. - Acrescenta
@supports not (display: grid)com um fallbackmax-widthclaro — os dois caminhos devem parecer intencionais. - Bloqueia uma regra
:has()com@supports selector(:has(*)). - Resiste a meter todo o visual dentro de
@supports; deixa cor de marca e tipografia na base.
Erros comuns
- Meter o único layout utilizável dentro de
@supportssem base — browsers sem suporte veem a página partida - Escrever
@supports (display)sem valor — feature queries precisam de um par propriedade–valor (ouselector(…)) - Usar
@supportsonde cabe@media(ou o inverso) — capacidade ≠ largura do viewport - Testar uma propriedade que a base já exige — só bloqueia o enriquecimento
- Pilhas profundas de
@supportsaninhados por ganhos pequenos — prefere uma camada enriquecida clara
Resumo
@supportscondiciona CSS à capacidade do browser (feature queries)- Testa com
(property: value), combina comand/or/note usaselector()para seletores - Mantém uma base sólida; enriquece quando há suporte
- Lembra o trio:
@media→ viewport,@container→ tamanho do pai,@supports→ capacidade - O Modern Toolkit termina aqui — módulo seguinte: Acessibilidade e fecho (
accessibility)
🧠 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