color theoryMay 3, 202613 min read

Sistemas de Cores para Dark Mode: Como Construir uma Paleta que Funciona às 2 da Manhã

Um guia prático de sistemas de cores para dark mode. O modelo de elevação de superfícies, a regra da dessaturação, a calibragem de acento e as sete marcas que entregam as paletas dark mais limpas em 2026.

By Boone
XLinkedIn
dark mode color systems

Sistemas de Cores para Dark Mode: Como Construir uma Paleta que Funciona às 2 da Manhã

Um dark mode é um sistema paralelo, e os produtos que só viram um interruptor no modo claro são os que parecem quebrados quando as luzes se apagam.

Esse é o artigo inteiro em uma frase. O motivo pelo qual a maioria dos dark modes falha é mais específico: designers partem para o "inverter a paleta clara" e acabam com planícies de cinza sobre cinza ou com um coral elétrico que queima retinas. A solução é arquitetural, não cosmética. Construa um sistema paralelo com seu próprio modelo de elevação, suas próprias regras de dessaturação e sua própria calibragem de acento, e o resultado parece intencional porque é.


Um dark mode é um sistema paralelo, não uma inversão

Sua paleta clara tem tokens de background, surface, borda, texto e acento. Sua paleta dark precisa de todos os mesmos tokens, e os valores não são o inverso dos valores claros. O croma se comporta de forma diferente em baixa luminosidade. Mudanças de matiz acontecem no limite perceptual. O que lê como um coral limpo em L 0.62 no modo claro vira um neon vibrante em L 0.72 no dark mode, contra uma superfície quase preta.

As equipes que entregam dark modes limpos não mexem em um toggle. Elas desenham uma segunda paleta, mapeiam para a mesma camada de token semântico e conectam as duas por uma troca de modo na raiz do tema. Dá mais trabalho. É a única abordagem que não te envergonha.


O modelo de elevação de superfícies

Background. Surface. Surface-elevated. Surface-overlay. Toda UI de dark mode design que funciona tem esses quatro níveis, e pular o terceiro é o motivo mais comum de UIs dark parecerem chapadas.

No modo claro, a elevação é óbvia: cards brancos sobre fundos cinza, sombras são baratas e a profundidade sai de graça. No dark mode, as sombras desaparecem contra superfícies escuras. A elevação precisa viver na luminosidade da própria superfície. Cada nível é um passo pequeno e deliberado para cima em luminosidade, não um salto.

Os quatro níveis não são escolhas estéticas. São estrutura de sustentação. Todo componente do seu sistema fica em um desses níveis, e a legibilidade de cada par texto-sobre-superfície depende de onde na pilha você o coloca.


O background define o piso

O background é o nível mais profundo. A regra: nunca use preto puro (oklch(0 0 0)) em saturação total. Use um quase preto levemente tingido, em torno de 8 a 10 por cento de luminosidade. O tom é quase sempre quente, porque pretos frios parecem mais baratos e mais gélidos do que o produto merece.

Um valor como oklch(0.10 0.012 30) entrega um carvão quente e escuro que lê como "preto" em qualquer tela, mas evita a sensação de vácuo morto do preto puro. O croma de 0.012 e o ângulo de matiz de 30 graus (uma leve inclinação quente) bastam. Mais que isso e fica barrento. Menos e fica sem vida.


A surface segura o conteúdo

A surface é o nível onde fica a maior parte do conteúdo, levemente elevada em relação ao background. O passo de luminosidade do background para a surface costuma ser de 3 a 5 pontos em OKLCH. Essa diferença é o primeiro sinal que o olho lê: é aqui que o conteúdo vive, o background está atrás.

oklch(0.14 0.010 30) contra oklch(0.10 0.012 30) já é separação visual suficiente sem borda nem sombra. O croma cai um pouco porque, conforme a luminosidade sobe em superfícies escuras, o croma precisa recuar para evitar uma mistura barrenta com o background. É sutil na renderização e completamente errado quando você pula essa etapa.


Surface-elevated e surface-overlay

Superfícies elevadas seguram cards e painéis. Superfícies overlay seguram modais e sheets. A progressão de luminosidade continua: surface-elevated em aproximadamente oklch(0.18 0.008 30), surface-overlay em oklch(0.22 0.007 30). O croma cai a cada passo porque mais alto na pilha significa mais perto do observador, e essas superfícies precisam parecer limpas.

O motivo pelo qual a maioria das UIs dark vira um mingau cinza chapado é que designers usam dois níveis: background e surface. Cards vivem no background, texto vive na surface, e tudo lê na mesma profundidade. Adicione o terceiro e o quarto nível e a UI ganha legibilidade na hora, sem uma única drop shadow.


A regra da dessaturação

Cores saturadas que funcionam no claro queimam à noite. A regra: dessature os acentos em 15 a 25 por cento e reduza o croma de texto e bordas ainda mais. Não se trata de apagar a marca. Trata-se de como o olho processa croma sob pouca luz ambiente.

Com muita luz ambiente (o escritório ao meio-dia), croma vívido lê como vibrante. Com pouca luz ambiente (a mesa à meia-noite), esse mesmo croma lê como agressivo, com halo e fisicamente desconfortável. A solução não é ter medo de cor. É calibrá-la. A marca continua reconhecível. O produto para de machucar.


Por que texto branco puro está errado

Branco puro sobre quase preto não é alto contraste, é contraste demais. O efeito de halo, em que texto brilhante parece vazar para o entorno escuro, é um fenômeno óptico documentado que deixa UIs dark mais difíceis de ler, não mais fáceis.

O valor certo para o texto primário no dark mode fica em torno de 90 a 95 por cento de luminosidade, com um toque de tom quente. oklch(0.93 0.005 60) lê como "branco" mas não faz halo. O texto secundário cai para oklch(0.70 0.010 60), ainda legível em tamanho de corpo, visualmente recessivo frente ao texto primário. O off-white é o valor que designers mais erram, porque parece uma concessão e na verdade é o valor correto.


A calibragem de acento mantém a marca reconhecível

Os acentos da marca precisam ler no dark mode sem perder identidade. A calibragem é um aumento de luminosidade mais uma redução de croma, não uma troca de matiz. Se o acento no modo claro é oklch(0.62 0.22 25), o acento no dark mode é oklch(0.72 0.17 25). Mesmo matiz. Luminosidade maior para se destacar contra superfícies escuras. Croma menor para não fazer halo.

O erro é tratar o dark mode como um lugar onde os acentos são apagados. Apagar mata o reconhecimento da marca. Subir a luminosidade e baixar o croma preserva a sensação da paleta de cores da marca enquanto evita a queimação visual. O usuário não percebe o ajuste. Ele percebe que o produto está bonito.


Conceito em voxel mostrando uma cor de acento da marca com luminosidade elevada e croma reduzido para o dark mode, preservando a identidade do matiz e eliminando o halo visual
Conceito em voxel mostrando uma cor de acento da marca com luminosidade elevada e croma reduzido para o dark mode, preservando a identidade do matiz e eliminando o halo visual

A checagem de contraste que a WCAG não faz

As razões de contraste da WCAG 2.1 aprovam muita UI dark feia. Uma razão de 4.5:1 entre uma superfície escura e um texto cinza apagado pode passar na WCAG e ainda ser genuinamente difícil de ler em condições ambientes reais. A segunda checagem é o APCA, que modela a percepção de luminosidade com mais precisão, especialmente na distinção luz sobre escuro.

Depois do APCA, faça o teste do olhômetro. Shimmer é a vibração que você vê quando duas cores de luminosidade parecida e croma diferente ficam lado a lado. Halo é o vazamento de elementos brilhantes para o entorno escuro. Bloom é o brilho percebido em acentos saturados. Se qualquer um desses estiver presente, o par falha, independentemente da razão. Corrija os valores, não a razão. Para uma análise mais profunda da mecânica de contraste de cor acessível, a metodologia completa cobre casos de borda que a auditoria no modo claro não revela.


Sete marcas entregando paletas dark limpas

Linear, Notion, Vercel, Stripe, GitHub, Arc e Raycast resolvem o dark mode cada uma de um jeito. Os padrões que elas compartilham são os que valem ser roubados.

MarcaModelo de superfícieEstratégia de acentoO que acertam
LinearQuatro níveis de verdade, passos curtosRoxo elevado, croma ~0.15Passos tão curtos que a profundidade parece contínua
NotionTrês níveis com overlayUso mínimo de acento no darkQuase nenhum croma, toda a profundidade
VercelBinário (background + elevated)Somente brancoBrutalmente simples; funciona porque se compromete
StripeQuatro níveis, tom quenteAzul calibrado, não reduzidoDados densos leem limpos em todos os níveis
GitHubTrês temas nomeados (dark, dimmed, high-contrast)Azul-esverdeado, dessaturado"Dimmed" é o padrão correto
ArcTingimento personalizado por espaçoMatiz totalmente definido pelo usuárioElevação por mudança de matiz, não de luminosidade
RaycastDois níveis com blur pesadoAcento laranja, agressivamente elevadoO blur cria elevação implícita

A Linear é a implementação de referência. Os passos de superfície são estreitos o bastante para a UI ler como um único campo escuro com profundidade real. O acento roxo é identificável como o roxo da Linear sem nunca queimar. A hierarquia tipográfica depende de passos de luminosidade nos tokens de texto, não só de tamanho.

A Vercel prova que o modelo binário funciona se você se comprometer por completo. Sem terceira superfície. Sem estados cinza. Tudo é ou background profundo ou superfície levemente elevada, e o compromisso monocromático faz parecer uma decisão de design, não uma limitação. A maioria das equipes não consegue fazer isso porque tem cores de status, ilustrações e momentos de marca que precisam de elevação.

A opção "Dimmed" do GitHub é o insight correto aplicado ao escopo errado. Eles a construíram como uma variante de tema, mas a lição real é que uma superfície dark de tom quente é mais confortável para leitura prolongada do que o padrão mais frio. Todo dark mode deveria rodar quente por padrão.


Quer um dark mode que pareça intencional às 2 da manhã em vez de invertido ao meio-dia? A Brainy desenha sistemas de cores dark paralelos, com o modelo de elevação, a calibragem de acento e o mapa de tokens OKLCH prontos para entrar no Figma e no CSS. Contrate a Brainy.


O mapa de tokens de dark mode que funciona

O mapa de tokens abaixo entrega um dark mode real em coordenadas OKLCH. Primitivos são os valores brutos. Semânticos são os papéis. Coloque os primitivos em uma coleção de variáveis do Figma como valores brutos. Mapeie os semânticos para os primitivos como aliases. Essa arquitetura de duas camadas é o sistema de tokens inteiro.

TokenPapelValor OKLCHHex aprox.
--color-bgPiso do backgroundoklch(0.10 0.012 30)#191512
--color-surfaceSuperfície de conteúdo padrãooklch(0.14 0.010 30)#221e1a
--color-surface-elevatedCards, painéisoklch(0.18 0.008 30)#2c2723
--color-surface-overlayModais, menus, sheetsoklch(0.22 0.007 30)#35302c
--color-text-primaryTexto de corpo, títulosoklch(0.93 0.005 60)#edeae5
--color-text-secondaryLegendas, rótulos, metadadosoklch(0.70 0.010 60)#b0a89e
--color-text-disabledEstados desabilitadosoklch(0.45 0.005 60)#6e6860
--color-border-subtleDivisores, linhas finasoklch(0.22 0.008 30)#36302b
--color-border-defaultBordas de input, bordas de cardoklch(0.28 0.010 30)#433d37
--color-accentCTA principal, estados ativosoklch(0.72 0.17 25)#e0816a
--color-accent-mutedHover, acento secundáriooklch(0.65 0.12 25)#c27060
--color-accent-subtleFundo tingido atrás de elementos de acentooklch(0.16 0.04 25)#2a1e1a

O matiz roda de 25 a 30 graus o tempo todo (território de coral quente). O sistema fica coeso porque a temperatura é consistente do piso ao teto. Trocar o matiz para 250 graus te dá uma paleta estilo Linear. Trocar para 200 graus te dá uma paleta próxima da Vercel. A estrutura não muda. Só o matiz.

Na implementação, a tabela inteira vira propriedades customizadas de CSS em :root[data-theme="dark"]. No Figma, cada linha é uma variável em uma coleção de modo "Dark". Essa arquitetura de duas coleções é o que faz um design system escalar entre superfícies.


Conceito em voxel ilustrando uma arquitetura de tokens de dark mode em duas camadas: valores primitivos OKLCH ligados por alias a tokens semânticos de superfície, texto e acento
Conceito em voxel ilustrando uma arquitetura de tokens de dark mode em duas camadas: valores primitivos OKLCH ligados por alias a tokens semânticos de superfície, texto e acento

Troca de modo: a implementação que não pisca

Trocar de modo sem um flash do tema errado se resolve definindo o esquema de cores no elemento html antes de qualquer JavaScript rodar. Qualquer outra abordagem está errada em pelo menos um caso de borda.

O padrão: leia o localStorage em busca de uma preferência salva em uma tag <script> inline bloqueante dentro do <head>. Aplique data-theme="dark" ou data-theme="light" ao elemento html de forma síncrona, antes de o CSS que referencia as propriedades customizadas renderizar. Sem React. Sem useEffect. Sem flash.

html
<script> const saved = localStorage.getItem('theme'); const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; document.documentElement.dataset.theme = saved ?? (prefersDark ? 'dark' : 'light'); </script>

Esse script é bloqueante por design. Ele roda antes da renderização. O flash de conteúdo sem estilo é causado por aplicar o tema em JavaScript depois da primeira pintura, e esse único script bloqueante o elimina por completo.


Preferência do sistema, padrão e override

O padrão deve seguir a preferência do SO. O override do usuário deve persistir no localStorage. O toggle deve expor três estados: sistema, claro e escuro.

Um toggle de dois estados é um erro de design. O usuário que coloca o SO no escuro e quer que o app acompanhe não quer gerenciar um segundo interruptor. O toggle precisa de um estado "sistema" que limpe o override salvo e deixe a preferência do SO mandar. A maioria dos apps constrói dois estados e depois recebe um ticket de suporte toda vez que alguém muda o tema do SO e se pergunta por que o app não acompanhou.


FAQ

Usar cores de acento no dark mode prejudica a bateria em OLED?

Cores de acento cobrem uma área pequena em uma UI típica. A economia de bateria do dark mode em OLED vem quase toda das áreas de superfície escura. Um botão de CTA coral sobre fundo escuro não muda de forma relevante o consumo de bateria. Fundos de preto puro importam. Ilustrações saturadas em tela cheia importam. Um botão não.

Posso usar a cor da marca do modo claro diretamente como acento do dark mode?

Não sem calibragem. Se a cor da sua marca no modo claro está em L 0.55 a 0.65 em OKLCH, usá-la diretamente sobre uma superfície escura vai ou render pouco (apagada demais para se destacar) ou fazer halo (vívida demais contra o ambiente escuro). Suba a luminosidade em 8 a 12 pontos. Reduza o croma em 20 a 30 por cento. Mantenha o matiz. Esse é o acento calibrado para dark mode.

Qual é o dark mode mínimo viável para um sistema que ainda não tem um?

Background, surface, surface-elevated, texto primário, texto secundário, acento. Seis tokens. Não é completo, mas é um sistema. Todo componente pode ser mapeado para um desses seis valores, o modelo de elevação está pronto para expansão e você consegue entregar sem passar vergonha. Comece por aí, não com cem tokens e nenhuma estrutura.

Um dark mode gerado automaticamente é aceitável alguma vez?

Para protótipos, ferramentas internas e produtos com um único designer ativo, uma inversão automática com ajustes de saturação é aceitável como ponto de partida. Como dark mode entregue de um produto com padrões de marca e usuários reais, não. Dark modes automáticos falham em cores de acento, falham em ilustração e falham em estados de componente. São um esboço inicial, não um sistema finalizado.

O OKLCH facilita construir um dark mode?

De forma dramática. O eixo de luminosidade perceptualmente uniforme do OKLCH faz com que os passos de luminosidade entre níveis de elevação se comportem como esperado em todos os matizes. No HSL, um passo de 5 pontos no laranja parece diferente de um passo de 5 pontos no azul. No OKLCH, não. Construir o modelo de elevação em OKLCH significa que os passos parecem consistentes, seja qual for o matiz do acento. O argumento completo a favor de OKLCH cobre a matemática em profundidade.

Os tokens semânticos devem diferir entre claro e escuro, ou só os primitivos?

Os primitivos diferem. Os semânticos ficam iguais. --color-surface significa "a superfície de conteúdo padrão" nos dois modos. O primitivo para o qual ele aponta é diferente no dark mode. Esse é o ponto da arquitetura de duas camadas. Componentes referenciam semânticos. Semânticos referenciam primitivos. A troca de modo reatribui os primitivos. Os componentes se atualizam de forma automática e correta.


A mudança que os sistemas de dark mode realmente destravam

Um dark mode de verdade é uma superfície de design paralela. Não é um detalhe de última hora. Não é um toggle de configurações. É uma segunda superfície com estrutura própria, restrições próprias e decisões de ofício próprias. As equipes que a tratam assim entregam produtos que parecem intencionais às 2 da manhã. As equipes que viram um interruptor entregam produtos que parecem ter sido abandonados antes de ficarem prontos.

O modelo de elevação é a fundação. A regra da dessaturação e a calibragem de acento são a camada de ofício. O mapa de tokens OKLCH é a implementação. O toggle de três estados com troca de modo sem flicker é a condição de entrega. Cada peça se conecta. Nenhuma é opcional se você quer que o resultado seja bom.

Construa o sistema paralelo. Entregue o mapa. A diferença aparece.


Quer um dark mode que pareça intencional às 2 da manhã em vez de invertido ao meio-dia? A Brainy desenha sistemas de cores dark paralelos, com o modelo de elevação, a calibragem de acento e o mapa de tokens OKLCH prontos para entrar no Figma e no CSS. Contrate a Brainy.


Agora salvando em drafts/dark-mode-color-systems.md.

Want a dark mode that looks intentional at 2 a.m. instead of inverted at noon? Brainy designs parallel dark color systems with the elevation model, accent calibration, and the OKLCH token map ready to drop into Figma and CSS.

Get Started

More from Brainy Papers

Keep reading