Felipe Moacir

Dark Mode Perfeito: CSS Variables e Sem Flicker

CSSDark ModeUX
Dark Mode Perfeito: CSS Variables e Sem Flicker

Implementar Dark Mode parece fácil: media (prefers-color-scheme: dark). Mas em aplicações web reais (SSR), isso pode causar um "piscar" branco antes de ficar escuro (Flicker).

O Problema do SSR

O servidor não sabe a preferência do usuário ou o que está no localStorage. Ele envia o HTML. O navegador renderiza (geralmente branco padrão). O JS hidrata, lê o storage e muda para preto. Esse intervalo é o flicker.

A Solução: Script Bloqueante no Head

A única forma de resolver isso é injetar um script minúsculo no <head> que roda antes do React ser carregado.

Biblioteca recomendada: next-themes.

// Providers.jsx
'use client'
import { ThemeProvider } from 'next-themes'

export function Providers({ children }) {
  return (
    <ThemeProvider attribute="class" defaultTheme="system" enableSystem>
      {children}
    </ThemeProvider>
  )
}

Estratégia de CSS Variables

Não use cores hexadecimais (#000000) hardcoded no seu CSS/Tailwind. Use variáveis semânticas.

:root {
  --background: 0 0% 100%; /* Branco */
  --foreground: 222.2 84% 4.9%; /* Preto */
}

.dark {
  --background: 222.2 84% 4.9%; /* Preto */
  --foreground: 0 0% 100%; /* Branco */
}

No Tailwind:

theme: {
  colors: {
    background: 'hsl(var(--background))',
    foreground: 'hsl(var(--foreground))',
  }
}

Agora, bg-background mudará de cor automaticamente apenas trocando a classe .dark no html.

Considerações de UX

  • Evite Preto Puro (#000000): Causa "smearing" em telas OLED ao rolar. Use cinza muito escuro (#121212 ou similar).
  • Contraste de Texto: Texto branco puro em fundo preto pode causar fadiga ocular (halation). Reduza a opacidade do texto para 87% ou 90%.