
A busca por um light-dark()
que funcione com qualquer valor.
A função que criei em https://brm.us/css-custom-functions é um costume --light-dark()
que pode ser usado para retornar valores dependendo se o modo claro ou escuro está sendo usado.
@function --light-dark(--light, --dark) {
result: var(--light);
@media (prefers-color-scheme: dark) {
result: var(--dark);
}
}
Diferentemente do built-inlight-dark()
, esta função personalizada não é limitada a <color>
valores e funciona com qualquer tipo de valor. Mas também diferentemente light-dark()
dela não pode responder ao color-scheme
valor local e pode responder somente à preferência de mídia clara/escura.
Conforme sugerido no final do post, essa limitação pode ser removida quando o suporte para consultas de contêineres aninhados e/ou CSS if()
for adicionado ao Chrome… e esse dia chegou!
Um costume --light-dark()
usando consultas de contêiner
ℹ️ Como esse código usa consultas de contêiner, você sempre precisa de um elemento wrapper. A próxima seção que usaif()
não precisa desse elemento wrapper extra.
Desde meu post anterior, o protótipo no Chrome foi expandido para também suportar consultas de contêineres aninhados dentro de funções personalizadas. Isso abre o caminho para permitir uma preferência de claro/escuro por elemento, assim:
- Defina um esquema de cores preferencial em um elemento usando uma propriedade personalizada chamada
--scheme
- Retrabalhe
--light-dark()
para usar uma consulta de estilo para responder ao valor de--scheme
Os valores possíveis para --scheme
são light
, dark
, e system
. Quando --scheme
é definido como um dos dois primeiros, o color-scheme
é forçado para esse valor.
A função se parece com isso:
@function --light-dark(--light, --dark) {
/* Default to the --light value */
result: var(--light);
/* If the container is set to "dark", use the --dark value */
@container style(--scheme: dark) {
result: var(--dark);
}
}
Dentro de @function
, os valores --light
e --dark
são passados como argumentos para a função. A --scheme
propriedade personalizada, no entanto, é lida do elemento no qual a função é invocada.
Para garantir que haja algum valor para --scheme
, eu o defino em :root
dependendo do prefers-color-scheme
valor. O prefers-color-scheme
valor também é duplicado em a --root-scheme
para habilitar o suporte para um --scheme
valor de system
, mas falaremos mais sobre isso depois.
:root {
--root-scheme: light;
--scheme: light;
@media (prefers-color-scheme: dark) {
--root-scheme: dark;
--scheme: dark;
}
}
Para permitir a definição de um esquema de cores preferencial por elemento, recorri ao uso de um data-scheme
atributo HTML que analiso para um valor em CSS usando attr()
. Quando o valor é light
ou dark
eu uso o valor diretamente. Quando o valor é system
, o código usa o --root-scheme
valor da propriedade. Para jogar bem com contextos claro/escuro aninhados, o código usa @scope
.
/* Allow overriding the --scheme from the data-scheme HTML attribute */
@scope ([data-scheme]) {
/* Get the value from the attribute */
:scope {
--scheme: attr(data-scheme type(<custom-ident>));
}
/* When set to system, use the --root-scheme value (which is determined by the MQ) */
:scope[data-scheme="system"] {
--scheme: var(--root-scheme);
}
/* This allows the native light-dark() to work as well */
:scope > * {
color-scheme: var(--scheme);
}
/* Because the elements with the attribute are extra wrapper elements, we can just display its contents */
display: contents;
}
Para aprender sobre isso attr()
, vá ler CSS attr()
recebe uma atualização . Quanto a @scope
, é suficiente ler a introdução rápida em@scope
.
Com todas as peças no lugar, é hora de usá-lo.
Em CSS:
[data-scheme] > * {
color: light-dark(#333, #e4e4e4);
background-color: light-dark(aliceblue, #333);
border: 4px --light-dark(dashed, dotted) currentcolor;
font-weight: --light-dark(500, 300);
font-size: --light-dark(16px, 18px);
transition: all 0.25s ease, border-style 0.25s allow-discrete;
}
Em HTML:
<div data-scheme="light">
<div class="stylable-thing">
…
</div>
</div>
Aqui está uma demonstração ao vivo. Lembre-se de que você precisa do Chrome Canary com o Experimental Web Platform Features Flag para ver o código em ação.
Um costume --light-dark()
usando Inlineif()
A partir do Chrome Canary 135.0.7022.0, o inlineif()
também está disponível atrás do sinalizador Experimental Web Platform Features. Graças a essa função, você pode omitir o elemento extra do contêiner que a abordagem de consultas do contêiner precisa, pois você pode selecionar condicionalmente um valor diretamente em uma declaração.
Como a if()
função também aceita consultas de estilo como uma das condições, a abordagem geral permanece a mesma: use uma propriedade personalizada e responda ao seu valor. O código resultante, no entanto, é muito mais curto:
@function --light-dark(--light, --dark) {
result: if(
style(--scheme: dark): var(--dark);
else: var(--light)
);
}
Nota lateral: Você sabia que inline if()
pode aceitar múltiplas condições? Assim:
color: if(
style(--scheme: dark): var(--dark-color);
style(--scheme: dim): var(--dim-color);
else: var(--light)
);
Esse tipo de uso, no entanto, está além do escopo deste post.
O código para definir --scheme
ou light
também dark
é mais curto, pois é mais fácil retornar ao --root-scheme
valor.
:root {
--root-scheme: light;
--scheme: light;
@media (prefers-color-scheme: dark) {
--root-scheme: dark;
--scheme: dark;
}
}
@scope ([data-scheme]) {
:scope {
--scheme-from-attr: attr(data-scheme type(<custom-ident>));
--scheme: if(
style(--scheme-from-attr: system): var(--root-scheme);
else: var(--scheme-from-attr)
);
color-scheme: var(--scheme); /* To make the native light-dark() work */
}
}
O uso continua o mesmo de antes, com a diferença de que você pode definir os estilos dependentes do esquema de cores diretamente no [data-scheme]
elemento.
[data-scheme] {
color: light-dark(#333, #e4e4e4);
background-color: light-dark(aliceblue, #333);
border: 4px --light-dark(dashed, dotted) currentcolor;
font-weight: --light-dark(500, 300);
font-size: --light-dark(16px, 18px);
transition: all 0.25s ease, border-style 0.25s allow-discrete;
}
<div class="stylable-thing" data-scheme="light">
…
</div>
Aqui está uma demonstração ao vivo para você conferir:
~
Conclusão
Eu já estava muito animado com CSS Custom Functions por si só. Combiná-lo com inline if()
leva isso a um nível ainda mais alto.