Contexto e visão geral
Muitas vezes, um autor precisa fazer mudanças contextuais no design de um componente. Antes, os autores precisavam usar seletores para aplicar essas mudanças. Isso geralmente significava que, embora muitos dos tokens de design pudessem existir como propriedades personalizadas, os tokens de design de ordem superior só podiam ser codificados como um padrão de seletor (ou seja, usando uma convenção de nome de classe ou atributo) ou como propriedades/contexto em um framework de JavaScript.
As consultas de estilo de contêiner permitem que os autores estilizem elementos com base no valor da propriedade personalizada calculada de um elemento ancestral. Isso significa que os autores podem escrever valores significativos de tokens de design nas folhas de estilo, em vez de depender de marcação ou JavaScript para apresentação.
Como fazer a implementação
Implementar um token de design reativo usando uma consulta de estilo de contêiner é bem simples:
- Defina o token de design de ordem superior como uma propriedade personalizada em um contêiner. Não é necessário que seja uma propriedade personalizada registrada.
- Use a regra
@container style()para consultar o valor dessa propriedade personalizada. - Aplique os estilos adequados a um elemento descendente dentro do contêiner.
Alguns lembretes:
- O contêiner que está sendo consultado com uma consulta de estilo não precisa ter um
container-typeoucontainer-namedefinido, mas umcontainer-namepode permitir uma consulta mais específica. - O contêiner em si não pode ser estilizado pela consulta de estilo de contêiner.
Confira um exemplo básico das etapas de implementação acima.
<div class="features">
<div class="card"></div>
<div class="card"></div>
</div>
<div class="bugs">
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
</div>
.features {
--density: spacious;
}
.bugs {
--density: compact;
}
@container style(--density: compact) {
.card {
padding: 8px;
}
}
@container style(--density: spacious) {
.card {
padding: 24px;
}
}
Estratégias de fallback
Até que haja suporte do Baseline para consultas de estilo de contêiner, NÃO É RECOMENDADO que elas sejam usadas para recursos principais que precisam estar disponíveis em todos os navegadores, já que não é simples criar um substituto para elas que não prejudique os benefícios ou que tenha as próprias limitações. Por exemplo, se uma preferência do usuário de densidade da interface não for considerada um recurso principal que precisa estar disponível em todas as experiências, as consultas de estilo de contêiner poderão ser usadas para implementar o recurso sem um substituto.
Como usar seletores
Para os recursos principais, use uma abordagem alternativa com seletores. Este exemplo usa um atributo data-density para codificar o token de design de densidade na marcação, em vez de uma propriedade personalizada:
<div class="features" data-density="spacious">
<div class="card"></div>
<div class="card"></div>
</div>
<div class="bugs" data-density="compact">
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
</div>
/* This example uses `:where()` to avoid increasing specificity */
:where([data-density="compact"]) .card {
padding: var(--card-padding-compact);
}
:where([data-density="spacious"]) .card {
padding: var(--card-padding-spacious);
}
Uma limitação importante dessa abordagem de substituição é que ela não oferece suporte a elementos de aninhamento com o conjunto de atributos data-density. Como a especificidade do seletor é a mesma, a ordem de aparecimento será usada para determinar os estilos (ou seja, [data-density="spacious"] sempre terá precedência sobre [data-density="compact"]).
Como usar consultas de estilo como um aprimoramento progressivo
Embora NÃO SEJA RECOMENDADO, se você quiser usar consultas de estilo como um aprimoramento progressivo para um recurso principal, crie algumas propriedades personalizadas para evitar duplicação e inclua as consultas de estilo depois. Verifique se a abordagem substituta usa :where() ao selecionar os elementos do contêiner para evitar o aumento da especificidade.
.card {
--card-padding-compact: 8px;
--card-padding-spacious: 24px;
}
:where([data-density="compact"]) .card {
padding: var(--card-padding-compact);
}
:where([data-density="spacious"]) .card {
padding: var(--card-padding-spacious);
}
/* Use style queries as a progressive enhancement: same specificity, so order of appearance is used */
@container style(--density: compact) {
.card {
padding: var(--card-padding-compact);
}
}
@container style(--density: spacious) {
.card {
padding: var(--card-padding-spacious);
}
}
Verificação de recursos apenas com CSS
Se você precisar verificar se o navegador é compatível com as consultas de estilo de contêiner para mostrar condicionalmente uma interface que depende delas, use uma consulta de estilo:
:root {
--style-queries-supported: check;
}
.density-toggle {
display: none;
}
@container style(--style-queries-supported) {
.density-toggle {
display: revert;
}
}
Verificação de recursos com JavaScript
Para a verificação de recursos com JavaScript, é um pouco mais complicado, já que a interface CSSContainerRule existia antes da adição de consultas de estilo de contêiner, então não é confiável para essa finalidade. Em vez disso, você precisa verificar o valor calculado de uma propriedade conhecida que está sendo definida com uma consulta de estilo.
Este exemplo usa uma propriedade personalizada, já que não terá efeito visual:
:root {
--style-queries-supported: check;
}
@container style(--style-queries-supported: check) {
body {
--style-queries-supported: yes;
}
}
Em seguida, verifique o valor calculado em JavaScript da seguinte forma:
if (getComputedStyle(document.body).getPropertyValue("--style-queries-supported") === "yes") {
// Use container style queries
} else {
// Use fallback strategy
}