Categorias
Projetos

CSS Style Queries

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.

2 wireframes de baixa fidelidade lado-a-lado, evidenciando a diferença de atuação de media queries versus container queries.

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:

.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:

@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.

@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:

@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:

@container style(border-color: lightblue) {
button {
border-color: royalblue;
}
}

Exemplos de aplicação de style queries em um card.

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:

@container style(--theme: dark) {
.card {
background: royalblue;
border-color: navy;
color: white;
}
.card button {
border-color: navy;
background-color: dodgerblue;
color: white;
}
}

Exemplos de aplicação de style queries em um card usando variáveis CSS.

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.

/* 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;
}
}

Exemplos de aplicação de style queries em um card usando estados (hover).

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:

@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.