A capacidade de consultar o tamanho inline de um elemento pai e os valores da unidade de consulta do contêiner recentemente alcançaram suporte estável em todos os motores de navegador modernos.
No entanto, a especificação de contenção inclui mais do que apenas consultas de tamanho. Ela também permite consultar os valores de estilo de um elemento pai. No Chromium 111, você poderá aplicar a contenção de estilo aos valores de propriedades personalizadas e consultar um elemento pai para o valor de uma propriedade personalizada.
Isso significa que temos um controle ainda mais lógico dos estilos no CSS e permite uma melhor separação da lógica e da camada de dados de um aplicativo dos estilos.
A especificação do módulo de contenção do CSS no nível 3, que abrange consultas de tamanho e estilo, permite que qualquer estilo seja consultado de um elemento pai, incluindo pares de propriedade e valor, como font-weight: 800
. No entanto, no lançamento desse recurso, as consultas de estilo só funcionam com valores de propriedades personalizadas do CSS. Isso ainda é muito útil para combinar estilos e separar dados do design. Vamos conferir como usar consultas de estilo com propriedades personalizadas de CSS:
Introdução às consultas de estilo
Digamos que temos o seguinte HTML:
<ul class="card-list">
<li class="card-container">
<div class="card">
...
</div>
</li>
</ul>
Para usar consultas de estilo, primeiro configure um elemento de contêiner. Isso requer uma abordagem um pouco diferente, dependendo se você está consultando um pai direto ou indireto.
Consultar familiares responsáveis diretos
Ao contrário das consultas de estilo, não é necessário aplicar a contenção usando a propriedade container-type
ou container
para .card-container
para que .card
possa consultar os estilos do pai direto. No entanto, precisamos aplicar os estilos (valores de propriedade personalizados, neste caso) a um contêiner (.card-container
, neste caso) ou a qualquer elemento que contenha o elemento que estamos estilizando no DOM. Não é possível aplicar estilos que estamos consultando no elemento direto que estamos estilizando usando essa consulta, porque isso pode causar loops infinitos.
Para consultar um familiar responsável diretamente, escreva:
/* styling .card based on the value of --theme on .card-container */
@container style(--theme: warm) {
.card {
background-color: wheat;
border-color: brown;
...
}
}
Você pode ter notado que a consulta de estilo envolve a consulta com style()
. Isso serve para eliminar o conflito entre os valores de tamanho dos estilos. Por exemplo, é possível escrever uma consulta para a largura do contêiner como @container (min-width: 200px) { … }
. Isso aplicaria estilos se o contêiner pai tivesse pelo menos 200 px de largura. No entanto, min-width
também pode ser uma propriedade CSS, e você pode consultar o valor CSS de min-width
usando consultas de estilo. É por isso que você usaria o wrapper style()
para deixar a diferença clara: @container style(min-width: 200px) { … }
.
Estilos de familiares responsáveis não diretos
Se você quiser consultar estilos para qualquer elemento que não seja um pai direto, é necessário atribuir a ele um container-name
. Por exemplo, é possível aplicar estilos a .card
com base nos estilos de .card-list
, atribuindo a .card-list
um container-name
e referenciando-o na consulta de estilo.
/* styling .card based on the value of --moreGlobalVar on .card-list */
@container cards style(--moreGlobalVar: value) {
.card {
...
}
}
Geralmente, é uma prática recomendada dar nomes aos contêineres para deixar claro o que você está consultando e desbloquear a capacidade de acessar esses contêineres com mais facilidade. Um exemplo de quando isso é útil é quando você quer estilizar elementos diretamente em .card
. Sem um contêiner nomeado em .card-container
, não é possível fazer consultas diretamente.
Mas tudo isso faz muito mais sentido na prática. Confira alguns exemplos:
Consultas de estilo em ação
As consultas de estilo são particularmente úteis quando você tem um componente reutilizável com várias variações ou quando não tem controle sobre todos os estilos, mas precisa aplicar mudanças em determinados casos. Este exemplo mostra um conjunto de cards de produtos que compartilham o mesmo componente. Alguns cards de produtos têm detalhes/notas adicionais, como "Novo" ou "Estoque baixo", acionados por uma propriedade personalizada chamada --detail
. Além disso, se um produto estiver com "Estoque baixo", ele terá um plano de fundo com borda vermelha. Esse tipo de informação provavelmente é renderizado pelo servidor e pode ser aplicado aos cards usando estilos inline, como este:
<div class="product-list">
<div class="product-card-container" style="--detail: new">
<div class="product-card">
<div class="media">
<img .../>
<div class="comment-block"></div>
</div>
</div>
<div class="meta">
...
</div>
</div>
<div class="product-card-container" style="--detail: low-stock">
...
</div>
<div class="product-card-container">
...
</div>
...
</div>
Com esses dados estruturados, é possível transmitir valores para --detail
e usar essa propriedade personalizada do CSS para aplicar os estilos:
@container style(--detail: new) {
.comment-block {
display: block;
}
.comment-block::after {
content: 'New';
border: 1px solid currentColor;
background: white;
...
}
}
@container style(--detail: low-stock) {
.comment-block {
display: block;
}
.comment-block::after {
content: 'Low Stock';
border: 1px solid currentColor;
background: white;
...
}
.media-img {
border: 2px solid brickred;
}
}
O código acima permite aplicar um ícone para --detail: low-stock
e --detail: new
, mas você pode ter notado alguma redundância no bloco de código. No momento, não há como consultar apenas a presença de --detail
com @container style(--detail)
, o que permitiria um melhor compartilhamento de estilos e menos repetição. Esse recurso está em discussão no grupo de trabalho.
Cards do clima
O exemplo anterior usava uma única propriedade personalizada com vários valores possíveis para aplicar estilos. No entanto, você pode misturar as coisas usando e consultando várias propriedades personalizadas. Confira este exemplo de card de clima:
Para definir o estilo dos gradientes de plano de fundo e dos ícones desses cards, procure características do clima, como "nublado", "chuvoso" ou "ensolarado":
@container style(--sunny: true) {
.weather-card {
background: linear-gradient(-30deg, yellow, orange);
}
.weather-card:after {
content: url(<data-uri-for-demo-brevity>);
background: gold;
}
}
Assim, você pode estilizar cada card com base nas características únicas dele. No entanto, você também pode estilizar combinações de características (propriedades personalizadas) usando o combinador and
da mesma forma que nas consultas de mídia. Por exemplo, um dia nublado e ensolarado seria:
@container style(--sunny: true) and style(--cloudy: true) {
.weather-card {
background: linear-gradient(24deg, pink, violet);
}
.weather-card:after {
content: url(<data-uri-for-demo-brevity>);
background: violet;
}
}
Separar dados do design
Em ambas as demonstrações, há um benefício estrutural em separar a camada de dados (DOM que seria renderizado na página) dos estilos aplicados. Os estilos são escritos como possíveis variantes que ficam no estilo dos componentes, enquanto um endpoint pode enviar os dados que seriam usados para estilizar o componente. É possível usar um único valor, como no primeiro caso, atualizando o valor --detail
, ou várias variáveis, como no segundo caso (definindo --rainy
ou --cloudy
ou --sunny
. E a melhor parte é que você também pode combinar esses valores. Verificar --sunny
e --cloudy
pode mostrar um estilo parcialmente nublado.
A atualização de valores de propriedades personalizadas pelo JavaScript pode ser feita sem problemas, seja ao configurar o modelo DOM (ou seja, ao criar o componente em um framework) ou atualizada a qualquer momento usando <parentElem>.style.setProperty('--myProperty’, <value>)
. I
Confira uma demonstração que, em algumas linhas de código, atualiza o --theme
de um botão e aplica estilos usando consultas de estilo e essa propriedade personalizada (--theme
):
Dê estilo ao card usando consultas de estilo. O JavaScript usado para atualizar os valores da propriedade personalizada é:
const themePicker = document.querySelector('#theme-picker')
const btnParent = document.querySelector('.btn-section');
themePicker.addEventListener('input', (e) => {
btnParent.style.setProperty('--theme', e.target.value);
})
Os recursos detalhados neste artigo são apenas o começo. As consultas de contêiner podem ajudar você a criar interfaces dinâmicas e responsivas. No caso das consultas de estilo, ainda há alguns problemas pendentes. Uma delas é a implementação de consultas de estilo para estilos CSS além das propriedades personalizadas. Isso já faz parte do nível de especificação atual, mas ainda não foi implementado em nenhum navegador. A avaliação de contexto booleano será adicionada ao nível de especificação atual quando o problema for resolvido. Já a consulta de intervalos está prevista para o próximo nível da especificação.