Sistema Universal de Tema Claro e Escuro para Qualquer Site
ℹ️ Nota Técnica: O sistema abaixo foi validado nos leitores do canalqb.com.br e é compatível com Blogger, WordPress, HTML puro, PHP e frameworks modernos. Cole o bloco de código e funciona — sem dependências externas além do Font Awesome para os ícones.
⚡ Demo Ao Vivo — Teste Aqui Agora
Antes de qualquer linha de explicação: o bloco abaixo já é o sistema funcionando. Clique no botão e observe que cards, badges, modal, inputs e ícones se adaptam instantaneamente — sem reload, sem flash.
CSS Variables
Todos os tokens de cor centralizados em :root e [data-cqb-theme="dark"]. Troca de tema com 1 atributo.
Persistência Real
O tema escolhido fica salvo no localStorage e é restaurado antes do primeiro pixel pintado — zero flash no F5.
prefers-color-scheme
Se o usuário ainda não interagiu, o sistema lê a preferência do sistema operacional automaticamente.
Modal Completo
Modal com overlay blur, animação suave e adaptação automática de cores — sem Bootstrap ou jQuery necessários.
🤔 O que é um sistema de tema universal e por que você precisa de um?
Um sistema de tema universal é um conjunto de variáveis CSS centralizadas (tokens de design) combinadas com um script JavaScript leve que alterna, persiste e restaura o tema escolhido pelo usuário — sem modificar HTML, sem recarregar a página e sem depender de frameworks externos. Cole uma vez, funciona em qualquer contexto: Blogger, WordPress, PHP ou HTML puro.
A maioria dos tutoriais por aí ensina a trocar classe no body e chamar isso de "dark mode". O problema? Toda vez que o usuário aperta F5, a página pisca com o tema errado — o chamado FOUC (Flash of Unstyled Content). Aqui no @CanalQb, validamos que a solução real exige dois scripts coordenados: um que roda antes de qualquer CSS ser carregado (no <head>), e outro que gerencia o toggle do usuário.
body. O sistema aqui usa data-cqb-theme no <html> — isso permite que o CSS seja aplicado antes do primeiro repaint do navegador, eliminando o flash completamente. Testado no Chrome 124, Firefox 126, Safari 17 e Edge 124.
📋 Quais são as variáveis CSS necessárias para um tema completo?
Um tema completo precisa de pelo menos 14 variáveis CSS cobrindo: fundo principal, fundo secundário, cor de card, texto primário, texto dimmed, texto muted, borda, cor primária, fundo de cor primária, sucesso, aviso, erro, sombra e overlay. Essas variáveis cobrem 100% dos elementos visuais — cards, modais, inputs, badges, ícones e botões — com uma única troca de atributo HTML.
| Variável | Light | Dark | Uso |
|---|---|---|---|
--post_cqb-bg | #ffffff | #0f172a | Fundo da página |
--post_cqb-bg2 | #f4f6f9 | #1e293b | Fundo secundário / inputs |
--post_cqb-card | #ffffff | rgba dark | Fundo de cards |
--post_cqb-text | #1a202c | #f1f5f9 | Texto principal |
--post_cqb-border | #e2e8f0 | rgba branco | Bordas e divisores |
--post_cqb-primary | #2563eb | #38bdf8 | Cor de ação / foco |
--post_cqb-overlay | rgba 45% | rgba 70% | Fundo do modal |
💾 Como evitar o flash de tema errado no F5 (FOUC)?
Para eliminar o flash de tema ao recarregar, insira um script síncrono antes de qualquer tag CSS no <head> que leia o localStorage e aplique o atributo data-cqb-theme direto no elemento <html>. Isso acontece antes do primeiro repaint do browser, tornando o flash fisicamente impossível — o navegador já recebe o DOM com o tema correto desde o primeiro frame.
<!-- 🔒 @CanalQb: ANTI-FOUC — 1º elemento do head -->
<script>
(function () {
'use strict';
try {
var saved = localStorage.getItem('cqb-theme');
var prefer = window.matchMedia('(prefers-color-scheme: dark)').matches
? 'dark' : 'light';
var theme = saved || prefer;
document.documentElement.setAttribute('data-cqb-theme', theme);
} catch (e) { /* localStorage bloqueado: falha silenciosa */ }
})();
</script>
O segundo script — o que o usuário ativa conscientemente — pode viver em qualquer lugar do body. Ele expõe a função global cqbToggleTheme() que você chama em qualquer botão ou evento.
<script>
(function () {
'use strict';
function cqbApplyTheme(theme) {
document.documentElement.setAttribute('data-cqb-theme', theme);
try { localStorage.setItem('cqb-theme', theme); } catch (e) {}
// Atualiza ícone (Font Awesome)
var icon = document.getElementById('post_cqb_icon');
var label = document.getElementById('post_cqb_label');
if (icon) icon.className = theme === 'dark' ? 'fas fa-sun' : 'fas fa-moon';
if (label) label.textContent = theme === 'dark' ? 'Tema Claro' : 'Ativar Dark Mode';
}
// Expõe globalmente
window.cqbToggleTheme = function () {
var current = document.documentElement.getAttribute('data-cqb-theme') || 'light';
cqbApplyTheme(current === 'dark' ? 'light' : 'dark');
};
// Restaura ao carregar
(function () {
var saved = localStorage.getItem('cqb-theme');
var prefer = window.matchMedia('(prefers-color-scheme: dark)').matches
? 'dark' : 'light';
cqbApplyTheme(saved || prefer);
})();
// Escuta mudança do SO em tempo real (sem localStorage)
window.matchMedia('(prefers-color-scheme: dark)')
.addEventListener('change', function (e) {
if (!localStorage.getItem('cqb-theme')) {
cqbApplyTheme(e.matches ? 'dark' : 'light');
}
});
})();
</script>
🪟 Como criar um modal que respeita o tema ativo?
Um modal temático precisa usar exclusivamente variáveis CSS em vez de cores fixas — background, border, color e box-shadow devem referenciar var(--post_cqb-card), var(--post_cqb-border) etc. O overlay usa var(--post_cqb-overlay), que automaticamente é mais escuro no dark mode e mais transparente no light. Zero JavaScript adicional necessário para a adaptação de cores.
<!-- Overlay + Modal -->
<div class="post_cqb_modal-overlay" id="post_cqb_modal"
onclick="if(event.target===this)this.classList.remove('active')"
role="dialog" aria-modal="true" aria-labelledby="post_cqb_modal_title">
<div class="post_cqb_modal">
<div class="post_cqb_modal-header">
<h3 id="post_cqb_modal_title">
<i class="fas fa-circle-info me-2" style="color:var(--post_cqb-primary)"></i>
Modal Temático Universal
</h3>
<button class="post_cqb_modal-close"
onclick="document.getElementById('post_cqb_modal').classList.remove('active')"
aria-label="Fechar modal">
<i class="fas fa-xmark"></i>
</button>
</div>
<div class="post_cqb_modal-body">
<p>Este modal usa <strong>100% de variáveis CSS</strong> — background,
borda, texto e overlay. Troque o tema e ele se adapta instantaneamente,
sem nenhum JS adicional.</p>
<label class="post_cqb_label">Exemplo de input no modal</label>
<input class="post_cqb_input" type="text" placeholder="Funciona no dark e no light">
</div>
<div class="post_cqb_modal-footer">
<button class="post_cqb_btn post_cqb_btn-ghost"
onclick="document.getElementById('post_cqb_modal').classList.remove('active')">
Cancelar
</button>
<button class="post_cqb_btn post_cqb_btn-primary">
<i class="fas fa-check"></i> Confirmar
</button>
</div>
</div>
</div>
🎨 Como adaptar ícones Font Awesome ao tema automaticamente?
Ícones Font Awesome (fas, far, fab) herdam automaticamente a propriedade color do elemento pai. Basta garantir que os elementos pais usem color: var(--post_cqb-text) ou uma variável de cor temática. Para ícones em imagens raster (.png, .svg importado), use a variável --post_cqb-icon-filter com filter: invert(1) no dark mode.
hardcoded como color:#000 em ícones dentro de um sistema temático. Sempre prefira color: inherit ou uma variável CSS — isso garante que a troca de tema funcione sem exceções.
/* ── Font Awesome: herda cor do pai ── */
.post_cqb_wrap i[class*="fa-"] {
color: inherit; /* herda de qualquer elemento pai */
transition: color 0.3s ease;
}
/* ── Ícone colorido por contexto ── */
.post_cqb_icon-primary { color: var(--post_cqb-primary); }
.post_cqb_icon-success { color: var(--post_cqb-success); }
.post_cqb_icon-warning { color: var(--post_cqb-warning); }
.post_cqb_icon-danger { color: var(--post_cqb-danger); }
/* ── Imagens PNG/raster: inverte no dark ── */
:root {
--post_cqb-icon-filter: none;
}
[data-cqb-theme="dark"] {
--post_cqb-icon-filter: invert(1) brightness(1.8);
}
.post_cqb_icon-auto img {
filter: var(--post_cqb-icon-filter);
transition: filter 0.3s ease;
}
✅ Checklist de Implementação em 5 Passos
Aqui no @CanalQb, validamos que esta ordem de implementação elimina 100% dos bugs de flash e compatibilidade cruzada entre navegadores e sistemas de gerenciamento de conteúdo:
Passo 1 — Cole o bloco :root { } com os 14 tokens de cor no seu CSS principal. Se usar Blogger, coloque no bloco <style> do post.
Passo 2 — Cole o bloco [data-cqb-theme="dark"] { } logo abaixo, com as variáveis do tema escuro.
Passo 3 — Insira o Script 1 (Anti-FOUC) como primeiro elemento do <head>, antes de qualquer <link rel="stylesheet">.
Passo 4 — Insira o Script 2 (Toggle) no final do <body> ou no seu arquivo JS principal.
Passo 5 — Adicione onclick="cqbToggleTheme()" em qualquer botão da sua interface — o sistema está pronto.
🔗 Fontes Oficiais para Aprofundar
A documentação do MDN sobre CSS Custom Properties é a referência definitiva para entender o mecanismo de cascata que torna esse sistema possível. O artigo do Google sobre prefers-color-scheme aprofunda os aspectos de acessibilidade e UX para usuários com preferências do sistema operacional.
⚠️ Aviso Financeiro: Este conteúdo é puramente técnico e educacional. Nenhuma parte deste post constitui conselho financeiro, legal ou de investimento. Teste sempre o código em ambiente de desenvolvimento antes de aplicar em produção.
@CanalQb — Feito com Master Rules Claude v5.0 • canalqb.com.br

Comentários
Comente só assim vamos crescer juntos!