Dark Mode com variáveis de luminosidade invertida

Conheça uma técnica incrível para fazer Dark Mode com variáveis de luminosidade invertidas usando o espaço de cores HLC.

Ir para o artigo

Já mostramos o jeito mais fácil de fazer dark mode com CSS, uma técnica que usa variáveis CSS para armazenar valores de cores e faz a diferenciação entre dark mode e light mode através de uma classe.

Neste artigo, abordamos uma técnica interessantíssima para fazer Dark Mode com variáveis de luminosidade invertidas, algo tão incrível, mas tão recente, que nem todos os navegadores dão suporte (ainda), mas que, em breve, pode se tornar a maneira padrão para implementar dark mode em qualquer projeto Web.

É possível usar variáveis CSS para componentes de cores individuais para evitar a repetição das mesmas coordenadas de cores várias vezes ao longo de um tema.

Dá até para usar a mesma variável para vários componentes, por exemplo, com HSL Hue e Lightness:

Aqui está uma página simples feita com essa técnica:

See the Pen Custom property for theme hue & saturation by Lea Verou (@leaverou) on CodePen.

Ao contrário das variáveis de pré-processadores, é possível até mesmo substituir localmente a variável para ter blocos com uma cor de destaque diferente:

Como pode ser visto neste exemplo:

See the Pen Custom property for theme hue & saturation, local override by Lea Verou (@leaverou) on CodePen.

Dark Mode entra em jogo

Tudo isso é ótimo e elegante, até que dark mode entre em jogo.

A ideia de usar propriedades personalizadas para facilitar a adaptação de um tema ao modo escuro não é nova. No entanto, na maioria dos artigos pelas webs, a estratégia sugerida é criar várias propriedades personalizadas, uma para cada cor, e substituí-las através de media queries.

Não deixa de ser uma abordagem interessante, mas, mesmo nos designs mais disciplinados, nem todas as cores são variáveis CSS.

Freqüentemente, encontram-se cores declaradas inline. Isso significa que lidar com dark mode é desgastante o suficiente para que a maioria simplesmente deixe para depois…

A boa notícia é que isso pode ser mitigado ao usar Dark Mode com variáveis de luminosidade invertidas (HSL)!

Saiba, de antemão, que não é um processo ótimo, e você deve, eventualmente, ajustá-lo para criar um modo escuro adequado — já que fazer um tema escuro não se trata apenas de trocar cores –, mas é melhor do que nada e pode servir como uma excelente base.

Explicando a técnica

A ideia-base é usar propriedades personalizadas (variáveis CSS) para a luminosidade (lightness) das cores, ao invés da cor inteira. Então, no dark mode, substituir essas variáveis com 100% - lightness.

Geralmente, essa técnica produz cores claras para cores escuras, cores médias para cores médias e cores escuras para cores claras e ainda permite definir cores embutidas, em vez de forçar o uso de uma variável para cada cor.

O código do exemplo:

A diferença entre o modo claro e escuro fica assim:

Dark Mode: diferença entre modo claro e modo escuro usando variáveis de cor HSL.
Light mode e dark mode, gerados “automaticamente”, lado-a-lado.

Observe que toda a informação sobre lightnesses foi substituída por variáveis de luminosidade — o que, na verdade, não precisa ser obrigatório e tão abrangente.

Por exemplo, os títulos dos artigos teriam uma aparência melhor e teriam melhor contraste se simplesmente fossem mantidos iguais:

Dark Mode: diferença entre modo claro e modo escuro com pequenas adaptações.
Comparação do modo escuro com cada claridade se tornando uma variável versus uma abordagem mais refinada, com exceções feitas conforme necessário (neste caso, as cores de fundo e de texto para article > h2).

Essas são decisões fáceis de tomar enquanto se analisa o CSS, substituindo as porcentagens de luminosidade por variáveis e visualizando o resultado.

O problema com HSL

Mas por que os cabeçalhos dos artigos foram mais fáceis de ler com suas cores originais do que com a claridade invertida? A principal causa é que a Luminosidade de HSL não corresponde realmente ao que os nós, humanos, percebemos como luminosidade, e essa diferença pode produzir discrepâncias perceptivas acentuadas.

Esse é o grande problema com esta abordagem: ela assume que a luminosidade de HSL realmente significa algo, mas, como discutido neste artigo, não significa. Por exemplo, amarelo e azul têm a mesma luminosidade HSL de 50%… Além disso, nota-se que as cores escuras têm diferenças menores entre elas do que as cores claras, porque o HSL não é perceptivelmente uniforme.

Isso significa, então, que a técnica de Dark Mode com variáveis de luminosidade invertidas não é útil para nada além de um placeholder enquanto se desenvolve um dark mode real?

A resposta é: não. :)

Em breve, será possível trabalhar com cores LCH diretamente nos navegadores. A primeira implementação foi lançada recentemente no Safari e também há atividade nesse sentido entre os outros vendors.

LCH é um espaço de cores muito melhor para essa técnica, já que sua luminosidade na verdade significa algo, não apenas em diferentes tonalidades da mesma cor, mas em diferentes matizes e cores.

Este próximo exemplo precisa (na data de publicação deste artigo) do Safari TP 120+. Compare esses 2 degradês, o superior mostrando várias cores HSL, todas com leveza de 50%, e o inferior, várias cores LCH, todas com leveza de 50%:

See the Pen LCH vs HSL colors for the same lightness by Lea Verou (@leaverou) on CodePen.

Eis um screenshot com a diferença para aqueles que não têm acesso ao Safari TP 120+:

Dark Mode: diferença entre cores HSL e LCH.

Perceba que, em HSL, algumas cores (como amarelo e ciano) são muito mais claras do que outras. No LCH, todas as cores com a mesma luminosidade têm… A mesma luminosidade.

Tenha em mente que o croma de LCH não corresponde realmente à luminosidade de HSL, então, embora esteja definido com o mesmo número, ele não corresponde à mesma coisa.

Mas, nesse caso, como essa a técnica de Dark Mode com variáveis de luminosidade invertidas funcionaria com cores LCH? Vamos experimentar!

Foi usada esta ferramenta para converter as cores HSL existentes para LCH; depois, ajustados os valores um pouco manualmente, já que as cores inicialmente convertidas não pareciam boas em todas as luminosidades LCH — observe que as cores HSL com as mesmas matiz e saturação podem ter matizes diferentes e chromas em LCH.

Esta é a aparência desta técnica com as cores LCH (no momento, Safari TP 120+ ou posterior para visualizar):

See the Pen Lightness variables, for easy basic dark mode, LCH version by Lea Verou (@leaverou) on CodePen.

Um screenshot, caso você não tenha conseguido ver direto no navegador:

Dark Mode: diferença entre modo claro e modo escuro usando variáveis de cor LCH.
Light mode e dark mode, gerados “automaticamente” com com variáveis de luminosidade invertidas LCH.

Não apenas o dark mode fica muito melhor, mas, mesmo no light mode, as 2 cores alternativas parecem mais uniformes, pois têm a mesma luminosidade LCH.

Aqui está uma comparação dos 2 dark modes:

Comparação dos 2 dark modes gerados automaticamente via claridade HSL (esquerda) e claridade LCH (direita).
Comparação dos 2 dark modes gerados “automaticamente” via claridade HSL (esquerda) e claridade LCH (direita).

Na verdade, até que as cores LCH sejam suportadas de forma confiável em todos os lugares, você precisa fornecer um substituto por meio de @supports, mas, para ser breve, isso não foi incluído nesse demo.

Automatizando a geração de variáveis de luminosidade

Se estiver usando um pré-processador que suporta loops, como Sass, você pode automatizar a geração dessas variáveis e torná-las ainda mais granulares, por exemplo, com steps de 5%:

Dá para fazer variáveis de luminosidade sem tanta repetição?

Através dos exemplos, houve muita repetição de valores, sendo preciso declarar, por exemplo, --l-40 como 40% e, em seguida, definindo-o para 60% no dark mode. Será que não é possível derivá-lo de alguma forma, subtraindo o valor que já se tem de 100%?

Aqueles com alguma experiência em programação podem arriscar algo como:

Entretanto, isso não funcionará. CSS não é uma linguagem imperativa; não possui etapas de cálculo, em qu as variáveis possuem valores diferentes antes e depois de cada etapa. Não existe tal conceito de tempo; todas as declarações que são aplicadas atualmente, precisam ser verdadeiras ao mesmo tempo.

É mais semelhante à avaliação reativa (reactive evaluation) de fórmulas de planilhas do que à computação em JS e outras linguagens de programação populares (existem linguagens de programação reativas de propósito geral, mas são menos conhecidas).

Então, declarações como a acima são consideradas ciclos: uma vez que --l-40 não pode se referir a si mesmo, isso é um erro, e --l-40 seria definido com seu valor inicial como um mecanismo de recuperação de erro (já que o CSS não pode lançar erros).

Mas, então, existe ou não uma maneira de evitar declarar variáveis de claridade 2 vezes, uma para o modo claro e outra para o modo escuro?

Existe. Mas, talvez, não seja tão recomendada. Isso torna o código mais complicado de ler e compreender, com poucos benefícios. Mas por uma questão de diversão intelectual, vamos ver como é.

Em vez de definir --l-40 para 40%, vamos defini-lo em termos de sua diferença de 50%, (i.e., -10%). Então, calc(50% + var(--l-40)) retorna 40% e calc(50% - var(--l-40)) retorna 60%, os 2 valores de que precisamos. Podemos, portanto, declarar uma variável que é -1 no dark mode e 1 no light mode e apenas multiplicar com isso.

Eis um subconjunto de como o código ficaria:

Ficou mais claro porque não é tão recomendado? Torna o uso muito mais complicado e dificílimo de ser lido. É esse tipo de adesão obsessiva à DRY que, com o tempo, os programadores acabamos percebendo que é contraproducente.

Conclusão

Lembremo-nos que Dark Mode é somente uma opção estética, não um milagre da acessibilidade que muda vidas ou aumenta a produtividade, como muitos divulgam.

Independentemente disso, fato é que é preciso saber implementar modo escuro, especialmente nesses dias, em que grandes empresas e produtos estão aderindo à opção estética cada vez mais — em outras palavras, o assunto está “hypado”.

No momento, a técnica de fazer dark mode com variáveis de luminosidade invertidas LCH não tem amplo suporte dos navegadores, mas, brevemente, essa realidade mudará e, o quanto antes você souber técnicas variadas para implementar dark mode de maneira eficiente, melhor para você e para a Web.

Usamos cookies para melhorar sua experiência e para ajudar a entender como nosso site é usado. Ao utilizar este site, você aceita o uso de cookies. Consulte nossa política de privacidade para obter mais informações.