10 pontos por GN⁺ 2026-04-20 | 1 comentários | Compartilhar no WhatsApp
  • Da funcionalidade nativa do navegador até media queries em JavaScript, uma organização em 8 níveis que amplia gradualmente o escopo de implementação do modo escuro
  • A forma mais simples é configurar o documento para seguir a preferência de esquema de cores do usuário apenas com a declaração <meta name="color-scheme" content="light dark"> ou color-scheme: light dark
  • Em níveis mais altos, a função light-dark(), @media (prefers-color-scheme: dark) e stylesheets separadas por esquema permitem ajustes amplos não só nas cores, mas também em imagens e sombras
  • Também é possível criar um seletor com três opções — Automatic, light e dark — em vez de seguir apenas a configuração do sistema do usuário, e identificar o tema com base em :has() e no elemento meta real
  • Inclui ainda as limitações de acessibilidade do Safari e observações sobre o comportamento de prefers-color-scheme na impressão, mostrando como os recursos recentes de CSS tornaram bem mais fácil embutir modos claro e escuro

Implementação do modo escuro por nível

  • Level 1: Barebone

    • É possível ativar a distinção entre light/dark mesmo sem uma linha de CSS; basta adicionar <meta name="color-scheme" content="light dark"> ao head do documento para que o navegador passe a seguir a preferência de esquema de cores do usuário
    • A ordem dos itens no atributo content teoricamente tem significado, e usuários que não definiram preferência de esquema de cores recebem o primeiro valor da lista separada por espaços
    • Como as configurações atuais dos sistemas operacionais não oferecem uma opção para não escolher esquema de cores, na prática o resultado acaba coincidindo com o esquema definido no sistema operacional
    • Também é possível especificar apenas um valor em content; nesse caso, o esquema correspondente é forçado sem considerar a preferência do usuário
    • Essa meta tag funciona, em certa medida, como a abordagem via HTML correspondente ao método em CSS do nível seguinte
  • Level 2: Basic

    • Em CSS, é possível aplicar a distinção entre modo claro/escuro com a declaração html { color-scheme: light dark; }
    • Se já houver uma meta tag no DOM, essa declaração não é necessária; se você puder controlar o HTML, recomenda-se usar a meta tag, pois ela permite que o navegador conheça a instrução antes mesmo de analisar o CSS
    • Ambas as abordagens permitem aproveitar os estilos padrão do user agent e o modo claro/escuro incluído neles
    • Se você adicionar CSS aqui, mas limitar-se principalmente ao uso de CSS system colors, já é possível obter um design bastante organizado
    • Diferentemente da meta tag, que sempre se aplica ao documento inteiro, a declaração CSS color-scheme também pode ser definida em outros lugares além do elemento raiz, o que abre espaço para usos adicionais
  • Level 3: Benign

    • A função de cor light-dark() do CSS, adicionada relativamente recentemente, permite ajustes simples para modo claro/escuro
    • No exemplo, ela é usada como background-color: light-dark(black, white); e color: light-dark(white, black);; o primeiro argumento se aplica ao modo claro e o segundo ao modo escuro
    • Os argumentos podem ser cores literais ou custom properties interpretadas como cor
    • Em todo o artigo, este era o único nível que, no momento da escrita, ainda não tinha suporte de navegador suficiente
  • Level 4: Bold

    • É possível implementar a troca para modo escuro com a media query tradicional @media (prefers-color-scheme: dark)
    • Consultando light ou dark, é possível alcançar o nível máximo de customização, sem se limitar a simples mudanças de cor
    • Dá para, por exemplo, dessaturar imagens com filtros no modo escuro ou substituir sombras de caixa por contornos
  • Level 5: Bisectional

    • Media queries também podem ser usadas em HTML, inseridas no atributo media de elementos link, permitindo separar stylesheets por esquema
    • O exemplo mostra light.css e dark.css ligados respectivamente a prefers-color-scheme: light e prefers-color-scheme: dark
    • Quando o grau de customização é grande, faz sentido usar arquivos dedicados, e o navegador pode ignorar o arquivo CSS que não corresponde à consulta, reduzindo potencialmente um download
  • Level 6: Ballistic

    • Em JavaScript, é possível usar a media query de esquema de cores com window.matchMedia('(prefers-color-scheme:dark)')
    • Como em outras media queries, é possível consultar se o esquema é claro ou escuro e, com base no resultado, executar o comportamento desejado
    • Em implementações reais, é possível combinar as técnicas dos níveis anteriores em vez de se prender a apenas uma delas

Seletor do usuário e padrões avançados

  • Level 7: Beyond

    • Não é necessário depender apenas da preferência do sistema; também é possível criar um color scheme switcher
    • Esse seletor não é um simples booleano, pois precisa de um modo Automatic que, por padrão, siga prefers-color-scheme
    • Ao adicionar esse seletor, o usuário pode escolher entre três modos: Automatic, light e dark
  • Level 8: Beguiling

    • Ao implementar o seletor do Level 7, é comum adicionar uma classe .dark ao HTML ou um atributo como data-theme="dark"
    • Como alternativa, é possível usar :has() para consultar diretamente a existência de <meta name="color-scheme" content="dark">
    • No exemplo, sob o seletor html:has(meta[name="color-scheme"][content="dark"]), variáveis CSS como --color-bg e --color-text são definidas com valores do modo escuro
    • Assim, é possível identificar o tema com base no elemento meta real, sem classes ou atributos de dados separados

Discussões e observações adicionais

  • Observação do CSS Naked Day

    • Ao visitar quase todos os sites sem estilos, a ausência de modo escuro ficou evidente, o que levou a essa classificação por níveis
    • O texto também comenta que, ao criar um site novo do zero e escrever estilos novos, os recursos recentes do CSS tornam muito fácil embutir modos claro e escuro
  • Problemas de acessibilidade no Safari

    • O texto aponta que, até relativamente pouco tempo atrás, o Safari não fornecia cores de link acessíveis no modo escuro
    • Menciona também a experiência de ter detectado esse problema em um CSS Naked Day anterior e, então, removido a meta tag para usar apenas o esquema de cores claro
    • Depois, a meta tag foi adicionada novamente, mas com a consciência de que usuários de versões antigas do Safari podem sofrer perda de acessibilidade
    • Também foi observada a ausência de borda visível em caixas de texto no modo escuro do Safari
    • Como os estilos padrão do user agent, sozinhos, não garantem acessibilidade completa nem mesmo com HTML semântico correto, o autor considera manter estilos suficientes também em futuros CSS Naked Day
  • Impressão e a condição screen and

    • No exemplo Bisectional, o uso de screen and ... é explicado como uma forma de excluir impressoras
    • Parte-se da premissa de que existe uma stylesheet principal independente de tema ou uma stylesheet de impressão dedicada, e de que separar isso com segurança evita que o modo escuro consuma muita tinta ao imprimir
    • Em testes reais, mesmo imprimindo com o modo escuro do sistema ativado, saíram apenas texto preto e papel branco, sugerindo que os navegadores não aplicam esses estilos de modo escuro à impressão
    • Em testes adicionais, na visualização de impressão prefers-color-scheme sempre foi reportado como light, tanto no Firefox quanto no Chromium
    • O texto ainda inclui uma observação em tom de brincadeira sobre como seria uma pena para quem tivesse uma impressora que usa papel preto e tinta branca

1 comentários

 
GN⁺ 2026-04-20
Comentários do Hacker News
  • Se você faz muita customização, um arquivo dedicado até faz sentido, mas a explicação de que CSS que não corresponde à media query nem chega a ser baixado me parece diferente do comportamento real dos navegadores. Pela minha experiência, o navegador acaba baixando tudo e só dá prioridades diferentes
  • Fiquei me perguntando se ainda não existe um jeito de evitar aquele clarão tipo flashbang que acontece enquanto se espera o conteúdo inicial do servidor
    • Acho razoável a abordagem de definir background-color no userContent.css do Firefox
    • Eu simplesmente diminuí o brilho da tela e desliguei o modo escuro, e o flashbang sumiu. De quebra, a bateria também passou a durar mais
  • Achei que este texto seria sobre preferência pela intensidade do preto no fundo do modo escuro. Já ouvi dizer que preto puro é melhor para a bateria em OLED, e também conheço gente que prefere um cinza menos carregado do que preto absoluto. Ainda assim, não sei se realmente precisa chegar a seis níveis; para mim, no máximo 3 ou 4 níveis seriam perceptíveis na prática
    • Achei que uma solução mais universal seria padronizar a compatibilidade com Reader Mode. Em vez do problema n x m de cada site tentar atender todas as preferências de todos os usuários, me parece melhor uma estrutura em que o site oferece apenas uma visualização simples de conteúdo e o navegador cuida das configurações individuais por cima disso
    • Eu tendo a preferir preto puro em OLED. Sinto que, quanto menos os pixels acendem, menor é a preocupação com burn-in e, já que a vida útil de qualquer forma é limitada, no longo prazo eu gostaria de usar um monitor por mais de 5 anos, não só por 2 ou 3
  • No meu caso, o nível máximo é 9, ou então 0, que é simplesmente desligar o computador e ir dormir
  • Fiquei feliz de ver que o OP implementou corretamente um toggle de 3 estados
  • Achei que seria mais divertido se os níveis fossem aplicados dinamicamente conforme a pessoa fosse descendo a página
    • Ou então também seria legal se o leitor pudesse escolher o nível em pontos apropriados da página
  • Para mim, isso parece mais um sistema de 8 níveis
  • Deu uma sensação bem de 2024
  • O que veio à mente nessa situação foi, claro, xkcd 3227