Como Criar Dark Mode e Menu Mobile com JavaScript Puro e Tailwind
📌 Navegue por tópicos
No artigo anterior, vimos como estruturar o visual HTML e Tailwind CSS do header do AqGoEs DeV. No entanto, um layout limpo só cumpre seu papel se a experiência do usuário for fluida.
Nesta etapa, vamos adicionar a camada de comportamento (interatividade) com JavaScript puro (Vanilla JS). Vamos resolver dois problemas vitais de front-end: o evento de clique do menu hambúrguer no celular e a navegação em Modo Escuro/Claro persistida no navegador do usuário.
Por que Usar LocalStorage para o Tema?
Quando um usuário escolhe o tema escuro em um site, ele espera que essa preferência seja mantida ao navegar entre as páginas ou ao retornar no dia seguinte.
A API de localStorage do navegador permite salvar pares de chave-valor diretamente no dispositivo do leitor. Isso evita o incômodo efeito de “tela piscando” (FOUC — Flash of Unstyled Content) no momento em que a página recarrega.
Código JavaScript Completo do Header
Abaixo está o script estruturado para manipular exatamente os elementos do nosso HTML:
document.addEventListener('DOMContentLoaded', () => {
// --- 1. ELEMENTOS DO DOM ---
const themeToggleBtn = document.getElementById('theme-toggle');
const lightIcon = document.getElementById('theme-toggle-light-icon');
const darkIcon = document.getElementById('theme-toggle-dark-icon');
const menuToggleBtn = document.getElementById('menu-toggle');
const mobileMenu = document.getElementById('mobile-menu');
// --- 2. LÓGICA DO TEMA (DARK / LIGHT) ---
const applyTheme = (isDark) => {
if (isDark) {
document.documentElement.classList.add('dark');
lightIcon.classList.remove('hidden');
darkIcon.classList.add('hidden');
} else {
document.documentElement.classList.remove('dark');
lightIcon.classList.add('hidden');
darkIcon.classList.remove('hidden');
}
};
// Verifica a preferência salva ou o padrão do sistema operacional
const savedTheme = localStorage.getItem('theme');
const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
const initialIsDark = savedTheme ? savedTheme === 'dark' : systemPrefersDark;
applyTheme(initialIsDark);
// Evento de clique para trocar o tema
themeToggleBtn.addEventListener('click', () => {
const isCurrentlyDark = document.documentElement.classList.contains('dark');
const newThemeIsDark = !isCurrentlyDark;
applyTheme(newThemeIsDark);
localStorage.setItem('theme', newThemeIsDark ? 'dark' : 'light');
});
// --- 3. LÓGICA DO MENU MOBILE ---
menuToggleBtn.addEventListener('click', () => {
mobileMenu.classList.toggle('hidden');
});
});
Entendendo a Lógica Passo a Passo
Para garantir que a implementação seja clara, analisaremos os blocos de código principais:
| Funcionalidade | Métodos/Propriedades | O que faz na prática |
| O que faz na prática | localStorage.getItem('theme') | Lê do navegador se o usuário já salvou o tema no passado. |
| Preferência do Sistema | window.matchMedia('(prefers-color-scheme: dark)') | Se não houver nada salvo, detecta se o celular/PC do usuário já usa modo escuro. |
| Troca de Ícones | .classList.toggle('hidden') | Alterna a visibilidade do Sol e da Lua sem usar bibliotecas externas. |
| Menu Hambúrguer | mobileMenu.classList.toggle('hidden') | Exibe ou esconde o dropdown ao clicar no botão no celular. |
Destaques de Execução Técnica
💡 Dica de Ouro: Coloque o trecho que verifica a preferência do tema no
<head>do seu HTML (ou execute antes do carregamento do body). Isso garante que a classedarkseja injetada na tag<html>antes mesmo da renderização visual, eliminando completamente a piscada de luz ao trocar de página.
O Poder do matchMedia
Muitos desenvolvedores esquecem que o usuário já configurou o próprio sistema operacional com seu tema preferido. Ao usar window.matchMedia, seu blog respeita a escolha global do usuário logo no primeiro acesso.
Código Enxerto e Performático
Não utilizamos bibliotecas pesadas de terceiros para controlar a lógica da página. Com menos de 50 linhas de JavaScript puro, garantimos máxima velocidade de carregamento e pontuação alta no Google Lighthouse.
Conclusão
Com este script, o header do projeto AqGoEs DeV passa a ser interativo, acessível e otimizado para a experiência do usuário em qualquer tipo de tela ou momento do dia.