Já tratamos aqui no dpw sobre container queries e da nova especificação contain-level-3, mas você já ouviu falar em Style Queries (Style Container Queries), que também faz parte dessa especificação?
Style Queries permitem consultar o estilo de qualquer elemento-pai em uma página e aplicar estilos a seus filhos com base neles.
Parece muito bom, mas, na prática, por que usaríamos isso em algo como uma classe ou atributo data-*
para aplicar os estilos (ambos com muito mais performance, inclusive)?
É interessante saber porque e quando o uso de style queries realmente faz sentido como um recurso anteriormente indisponível para nós, desenvolvedores front end.
Container Queries: recapitulação rápida
TLDR; container queries permitem consultar um seletor-pai por suas informações de tamanho e estilo e permitem que um filho possua sua lógica responsiva intrínseca, não importando onde ele esteja em uma página.
Em vez de depender da viewport para controlar estilos, agora é possível consultar elementos na página (uma ferramenta muito mais refinada), que são mais relevantes e específicos para o elemento de destino dos estilos de UI.
Esse recurso permite que um novo entry-point consulte e injete estilos responsivos e capacita um componente a possuir sua lógica de estilo responsivo.
Isso torna o componente muito mais resiliente, pois a lógica de estilo está intrinsecamente ligada a ele, não importando onde apareça na página.
Para escrever container queries, primeiro se define um contêiner no elemento-pai para ser consultado:
1 2 3 4 5 |
.parent { /* consulta o tamanho da inline-direction deste elemento-pai */ container-type: inline-size; } |
Em seguida, escreve-se os estilos de contêiner no elemento que se deseja:
1 2 3 4 5 6 7 |
@container (min-width: 420px) { .card { /* estilos aplicados quando o container do card é >= 420px */ /* ex: mudar de 1 coluna para 2 */ grid-template-columns: 1fr 1fr; } } |
Style Queries
Assim como as container queries baseadas em tamanho (size-based container queries), é possível consultar o estilo calculado (computed) de um elemento-pai usando style queries (ou consultas de estilo).
Eles devem ser agrupades na diretiva style()
para diferenciar style queries das size queries.
Por quê? Por exemplo, se estiver consultando @container (min-width: 420px)
, deseja-se aplicar estilos se o tamanho renderizado for maior ou igual a 420px
.
Se a consulta for @container style(min-width: 420px)
, o que se está procurando é um valor calculado de min-width
igual a 420px
.
A style query analisa o valor de estilo calculado — não o valor do elemento quando ele é renderizado na página. Estilo e tamanho são tipos diferentes de CSS containment.
1 2 3 4 5 6 7 |
@container style(color: hotpink) { .card { /* estilos a serem aplicados quando o container do card tiver a cor hotpink */ /* ex: mudar a cor de background para branco */ background: white; } } |
Já deu para perceber o poder das style queries, mas a coisa fica ainda melhor em algumas situações em que as style queries fornecem recursos exclusivos.
Exemplo 1 de Style Queries: elemento-pai imediato
Recentemente, foi decidido que se for preciso definir o container-type, todos os elementos serão style containers por padrão.
Isso significa que é possível consultar um pai imediato para aplicar estilos a um filho. Um exemplo de uso de uma consulta de estilo pai imediato é para estilo de texto inline.
Digamos que seja preciso destacar algo inline, como uma citação em itálico em um parágrafo. A frase anterior está em itálico e envolta em uma tag <i>
.
Se houver um elemento dentro dele que é preciso destacar usando a tag <i>
, ele não se destacará porque eles terão a mesma aparência. Este é um elemento. Mas talvez seja preciso colocar um fundo rosa para receber destaque.
Independentemente do tipo de elemento (span
, i
, p
etc.), style queries permitem verificar o estilo específico de qualquer elemento-pai para tomar decisões de estilo. Isso permite “estilos encadeados”, mais ou menos como uma fórmula “se tiver o estilo X, aplique o estilo Y“.
Algo mais ou menos como:
1 2 3 4 5 6 7 |
@container style(font-style: italic) { span, i, .etc { background: lavender; } } |
Exemplo 2 de Style Queries: estilização de propriedades não herdáveis
Este exemplo mostra a seleção de cores com base nos estilos de um elemento-pai, incluindo estilos não herdados. border-color
é um exemplo de uma propriedade que não é herdada.
Com style queries, torna-se possível consultar os estilos não herdáveis de um pai para aplicar a seus filhos.
Por exemplo, consultar uma cor de borda para aplicar estilos a um botão:
1 2 3 4 5 |
@container style(border-color: lightblue) { button { border-color: royalblue; } } |
Ou seja, quando o card tem uma cor de borda lightblue
, o botão dentro do card vai ter a borda de cor royalblue
.
Esse tipo de encadeamento é algo que não se poderia fazer com custom properties, pois são dois valores distintos.
Exemplo 3 de Style Queries: agrupamento de estilos com variáveis
Dando um passo adiante, é possível abstrair esses valores para variáveis CSS (como --theme: light
ou --theme: dark
) e aplicar os estilos em todo o card:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
@container style(--theme: dark) { .card { background: royalblue; border-color: navy; color: white; } .card button { border-color: navy; background-color: dodgerblue; color: white; } } |
Seria possível levar isso adiante e aplicar estados que podem ter a ver com interações ou tipos de card, como --highlight: true
para um cartão que deve ser destacado, ou --type: post
para cards de conteúdo de artigos de blog.
Style Queries e interações CSS
Mais uma maneira que as style queries podem ser realmente úteis é integrá-las com comportamentos que já são usados em CSS para estilizar, como estados :hover
e :focus
.
Seria possível atualizar rápida e facilmente uma variável CSS com um estado CSS e, usando a técnica acima, atualizar um agrupamento de valores em um só lugar.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
/* atualiza o tema no hover */ .card:hover, .card:focus { --theme: darkHover; } /* aplica estilos do tema "darkHover" */ @container style(--theme: darkHover) { .card { background: dodgerblue; border-color: navy; } .card button { border-color: lightblue; background-color: royalblue; } } |
Combinação de consultas (combinator queries)
Para deixar as coisas realmente interessantes, é possível até combinar size queries com style queries para aplicar uma lógica de estilo realmente específica.
Por exemplo, é possível usar a abordagem de variáveis CSS para agrupar estilos (neste exemplo, um cartão “highlight”), com lógica baseada em seu tamanho intrínseco:
1 2 3 |
@container (min-width: 420px) and style(--highlight: true) { /* estilos para componentes "highlight" com largura mínima de 420px */ } |
Conclusão
Os exemplos mostrados são apenas algumas ideias de como usar style queries de forma a permitir uma melhor experiência do desenvolvedor e estilos de componentes mais poderosos e flexíveis.
Essas abordagem modernas realmente atingem seu potencial máximo quando integrados em um sistema maior, onde esses componentes são reutilizados em vários lugares — e, como sabemos, esta é a abordagem indicada no desenvolvimento web moderno.