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 (
#121212ou similar). - Contraste de Texto: Texto branco puro em fundo preto pode causar fadiga ocular (halation). Reduza a opacidade do texto para 87% ou 90%.