Como Criar um Alternador de Modo Escuro com CSS e JavaScript
O modo escuro tornou-se essencial para sites modernos. Os utilizadores esperam poder alternar entre temas com base no seu ambiente, hora do dia ou preferência pessoal. Este tutorial mostra-lhe como criar um alternador de modo escuro robusto que respeita as preferências do sistema, memoriza as escolhas do utilizador e aproveita funcionalidades modernas de CSS para desempenho otimizado.
Pontos-Chave
- Criar um alternador de modo escuro que respeita as preferências do sistema e persiste as escolhas do utilizador
- Utilizar propriedades personalizadas CSS e a propriedade color-scheme para tematização eficiente
- Implementar JavaScript que previne o flash de conteúdo sem estilo no carregamento da página
- Aplicar boas práticas de acessibilidade para navegação por teclado e leitores de ecrã
Configurar a Estrutura HTML
Comece com HTML semântico que inclui um botão de alternância e declara o tema inicial:
<!DOCTYPE html>
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="color-scheme" content="light dark">
<title>Dark Mode Toggle Demo</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<button type="button" id="theme-toggle" aria-label="Toggle dark mode">
<span class="toggle-text">Dark</span>
</button>
<!-- Your content here -->
</body>
</html>
O atributo data-theme no elemento HTML controla o nosso tema. A meta tag color-scheme indica ao navegador para adaptar elementos nativos da interface como barras de deslocamento e controlos de formulários.
Implementar CSS com Funcionalidades Modernas
Utilizar Propriedades Personalizadas CSS e color-scheme
Defina os seus tokens de cor usando propriedades personalizadas CSS e, em seguida, aproveite a propriedade CSS color-scheme para tematização de elementos nativos:
:root {
color-scheme: light dark;
/* Light theme colors (default) */
--bg-color: #ffffff;
--text-color: #213547;
--accent-color: #0066cc;
}
[data-theme="dark"] {
--bg-color: #1a1a1a;
--text-color: #e0e0e0;
--accent-color: #66b3ff;
}
body {
background-color: var(--bg-color);
color: var(--text-color);
transition: background-color 0.3s ease, color 0.3s ease;
}
Respeitar as Preferências do Sistema com prefers-color-scheme
Adicione suporte para prefers-color-scheme para corresponder automaticamente às configurações do sistema:
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
--bg-color: #1a1a1a;
--text-color: #e0e0e0;
--accent-color: #66b3ff;
}
}
A Função Moderna light-dark()
Para navegadores que suportam a função light-dark(), pode simplificar as definições de cores:
:root {
color-scheme: light dark;
}
body {
background-color: light-dark(#ffffff, #1a1a1a);
color: light-dark(#213547, #e0e0e0);
}
Esta função seleciona automaticamente a cor apropriada com base no esquema de cores ativo, reduzindo a duplicação de código.
Discover how at OpenReplay.com.
JavaScript para Alternância e Persistência
Prevenir o Flash de Tema no Carregamento
Coloque este script imediatamente após a tag de abertura <body> para prevenir o flash de conteúdo sem estilo:
<script>
// Apply saved theme immediately to prevent flash
(function() {
const saved = localStorage.getItem('theme');
if (saved) {
document.documentElement.setAttribute('data-theme', saved);
} else if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.documentElement.setAttribute('data-theme', 'dark');
}
})();
</script>
Implementação Completa do Modo Escuro
Adicione este JavaScript para a funcionalidade de alternância:
const toggle = document.getElementById('theme-toggle');
const html = document.documentElement;
// Get current theme
function getTheme() {
return html.getAttribute('data-theme') ||
(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
}
// Set theme and update UI
function setTheme(theme) {
html.setAttribute('data-theme', theme);
localStorage.setItem('theme', theme);
updateToggleText(theme);
}
// Update button text
function updateToggleText(theme) {
const text = toggle.querySelector('.toggle-text');
text.textContent = theme === 'dark' ? 'Light' : 'Dark';
toggle.setAttribute('aria-label', `Switch to ${theme === 'dark' ? 'light' : 'dark'} mode`);
}
// Initialize
updateToggleText(getTheme());
// Handle toggle click
toggle.addEventListener('click', () => {
const current = getTheme();
setTheme(current === 'dark' ? 'light' : 'dark');
});
// Listen for system preference changes
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
if (!localStorage.getItem('theme')) {
setTheme(e.matches ? 'dark' : 'light');
}
});
Acessibilidade e Boas Práticas
Funcionalidades Essenciais de Acessibilidade
O seu alternador de modo escuro deve ser acessível por teclado e devidamente etiquetado:
#theme-toggle:focus-visible {
outline: 2px solid var(--accent-color);
outline-offset: 2px;
}
Garanta contraste de cor suficiente em ambos os temas. Modo escuro não significa baixo contraste—mantenha pelo menos os padrões WCAG AA (4.5:1 para texto normal).
O Que Evitar
Não use filter: invert(1) na página inteira—inverte imagens e media desnecessariamente. Evite fundos preto puro (#000000) no modo escuro. Use cinzas escuros (#1a1a1a) para melhor legibilidade. Nunca dependa apenas de JavaScript sem fallbacks CSS.
Testar a Sua Implementação
Teste o seu alternador de modo escuro em diferentes cenários:
- Limpe o localStorage e verifique se a deteção de preferências do sistema funciona
- Alterne o tema e atualize para confirmar a persistência
- Altere as preferências do sistema enquanto o site está aberto
- Verifique os rácios de contraste usando as DevTools do navegador
- Teste a navegação por teclado e anúncios de leitores de ecrã
Conclusão
Uma solução de modo escuro bem implementada respeita as preferências do utilizador, persiste escolhas e aproveita funcionalidades modernas de CSS. Ao combinar a propriedade color-scheme, propriedades personalizadas e JavaScript mínimo, cria um alternador de tema que é performante, acessível e fácil de usar. A função light-dark() simplifica a gestão de cores para navegadores modernos enquanto os fallbacks garantem compatibilidade.
Lembre-se: a melhor implementação de modo escuro é invisível para os utilizadores—simplesmente funciona exatamente como eles esperam.
Perguntas Frequentes
Sim, pode usar media queries CSS com prefers-color-scheme para detetar as preferências do sistema. No entanto, JavaScript é necessário para guardar as preferências do utilizador e fornecer um botão de alternância manual que sobrepõe as configurações do sistema.
Isto acontece quando o JavaScript é executado após a página renderizar. Coloque um script imediatamente após a tag body que verifica o localStorage e aplica o tema guardado antes da página pintar para prevenir este flash.
Não, preto puro pode causar fadiga ocular e tornar o texto mais difícil de ler. Use cinzas escuros como #1a1a1a ou #121212 em vez disso. Estas cores reduzem a fadiga enquanto mantêm bons rácios de contraste para acessibilidade.
Evite usar filter invert em imagens. Em vez disso, forneça versões alternativas de imagens para modo escuro ou use PNGs transparentes com cores que funcionam em ambos os fundos. Para gráficos complexos, considere usar máscaras CSS ou SVGs com currentColor.
Truly understand users experience
See every user interaction, feel every frustration and track all hesitations with OpenReplay — the open-source digital experience platform. It can be self-hosted in minutes, giving you complete control over your customer data. . Check our GitHub repo and join the thousands of developers in our community..