Resumindo
- Um tema com variáveis CSS funciona melhor em duas camadas: variáveis de paleta com as cores brutas e variáveis semânticas que descrevem para que serve cada cor.
- Os componentes só devem ler variáveis semânticas, como --color-text ou --color-surface, nunca valores de paleta diretamente.
- O modo escuro passa a ser só apontar as variáveis semânticas para outros valores da paleta, sob uma media query ou um atributo de dados.
- A função light-dark() e a propriedade color-scheme permitem que uma só declaração guarde os dois modos nos navegadores atuais.
- Um pequeno script inline no head que define o tema salvo antes de a página ser pintada evita o flash do tema errado.
Nesta página
Um tema com variáveis CSS é um conjunto de propriedades personalizadas, como --color-surface e --color-text, que todo componente lê em vez de cores fixas no código. Para trocar o tema você muda as variáveis, em geral em :root ou em um atributo data-theme, e a interface inteira acompanha. O truque que faz isso escalar é dividir as variáveis em duas camadas: uma paleta de cores brutas e papéis semânticos que apontam para essa paleta.
Duas camadas: paleta e papéis
As variáveis de paleta recebem nome pelo que são: --violet-600, --ink-900. As semânticas, pelo que fazem: --color-accent, --color-text-muted. Os componentes leem só as do segundo tipo. Quando o modo escuro chega, você reaponta os papéis e deixa cada componente intacto. É a mesma ideia dos design tokens, expressa direto em CSS.
--violet-600: #7c3aedQuem lê
Muda quando
--color-accent: var(--violet-600)Quem lê
Muda quando
Exemplo
--button-bg: var(--color-accent)Quem lê
Muda quando
:root {
/* Palette: raw values, named for what they are */
--paper-50: #faf8f5;
--paper-100: #f1ede6;
--ink-900: #14121f;
--ink-700: #3d3a4f;
--ink-500: #6b6880;
--violet-600: #6d28d9;
--violet-300: #c4b5fd;
--night-950: #0d0b16;
--night-900: #17142a;
--night-800: #221e3a;
/* Roles: what each colour is for (light mode) */
--color-bg: var(--paper-50);
--color-surface: var(--paper-100);
--color-text: var(--ink-900);
--color-text-muted: var(--ink-500);
--color-border: color-mix(in oklab, var(--ink-900) 12%, transparent);
--color-accent: var(--violet-600);
--color-on-accent: #ffffff;
}
body { background: var(--color-bg); color: var(--color-text); }
.card { background: var(--color-surface); border: 1px solid var(--color-border); }
.button { background: var(--color-accent); color: var(--color-on-accent); }Nomes de papéis que sobrevivem a um redesenho
O nome de um papel deve continuar verdadeiro depois que as cores mudam. --light-grey deixa de ser claro no modo escuro, e --blue mente no dia em que a marca vira verde. Nomeie a função e o par, para quem ler a folha de estilo depois saber que cor vai onde.
Nomes que quebram
--blue,--purple-button--light-grey-bg--white-text--dark-border
Nomes que duram
--color-accent,--color-on-accent--color-surface--color-text--color-border
Adicionando modo escuro com variáveis CSS
O modo escuro reaponta os papéis. Respeite por padrão a configuração do sistema operacional e deixe um atributo data-theme sobrescrevê-la quando o leitor escolher. Defina também color-scheme, para barras de rolagem, controles de formulário e o canvas padrão combinarem.
:root { color-scheme: light; }
/* Follow the system unless the reader picked light */
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
color-scheme: dark;
--color-bg: var(--night-950);
--color-surface: var(--night-900);
--color-text: #f2f0fa;
--color-text-muted: #a5a1bd;
--color-border: color-mix(in oklab, #ffffff 12%, transparent);
--color-accent: var(--violet-300);
--color-on-accent: var(--ink-900);
}
}
/* The reader picked dark explicitly */
:root[data-theme="dark"] {
color-scheme: dark;
--color-bg: var(--night-950);
--color-surface: var(--night-900);
--color-text: #f2f0fa;
--color-text-muted: #a5a1bd;
--color-border: color-mix(in oklab, #ffffff 12%, transparent);
--color-accent: var(--violet-300);
--color-on-accent: var(--ink-900);
}light-dark() elimina a repetição.O modo escuro não é o modo claro invertido. As superfícies ficam mais claras conforme se elevam, os destaques clareiam e as sombras dão lugar a bordas. Design de modo escuro e gradientes para modo escuro tratam do lado visual.
O atalho light-dark()
Os navegadores atuais aceitam light-dark(), que recebe um valor claro e um escuro e escolhe um conforme o color-scheme do elemento. Defina color-scheme: light dark na raiz para seguir o sistema, ou force um com o atributo, e cada papel vira uma só linha: --color-bg: light-dark(var(--paper-50), var(--night-950)). Mantenha a forma mais longa se precisar dar suporte a navegadores anteriores a 2024.
Um seletor de tema que não pisca
Se a escolha salva é aplicada depois de a página renderizar, quem escolheu escuro vê um flash branco a cada carregamento. Defina o atributo em um pequeno script inline no head, antes de qualquer folha de estilo pintar o body.
<head>
<script>
(function () {
var saved = localStorage.getItem("theme");
if (saved === "light" || saved === "dark") {
document.documentElement.dataset.theme = saved;
}
})();
</script>
<link rel="stylesheet" href="/styles.css">
</head>dataset.theme e salvar o valor no localStorage.- 1
Ofereça três opções
Claro, escuro e sistema. Remover o atributo devolve o controle ao
prefers-color-scheme. - 2
Salve só escolhas explícitas
Guarde
lightoudark; apague a chave para sistema, para que uma mudança posterior no sistema operacional seja respeitada. - 3
Evite transições no carregamento
Se as cores têm transição, ative-a só depois da primeira pintura, senão a página anima de claro para escuro ao carregar.
Temas de marca além de claro e escuro
As mesmas duas camadas atendem várias marcas em uma única base de código. Cada marca fornece a própria paleta e os valores de papel sob um atributo data-brand, e os modos continuam funcionando por cima. Com o color-mix() você deriva estados de hover e tons claros a partir de um destaque por marca, como mostra color-mix() no CSS.
[data-brand="harbour"] {
--color-accent: #0f766e;
--gradient-hero: linear-gradient(150deg, #042f2e 0%, #0f766e 55%, #5eead4 100%);
}
[data-brand="ember"] {
--color-accent: #c2410c;
--gradient-hero: linear-gradient(150deg, #431407 0%, #c2410c 55%, #fdba74 100%);
}
.button:hover { background: color-mix(in oklab, var(--color-accent), black 12%); }
.hero { background: var(--gradient-hero); }Como as propriedades personalizadas são herdadas, um tema não precisa cobrir a página toda. Coloque data-theme="dark" em uma seção, como uma faixa promocional ou um rodapé, e tudo dentro dela lê os papéis escuros enquanto o resto da página fica claro. Escreva o seletor escuro como [data-theme="dark"] em vez de :root[data-theme="dark"] se quiser que isso funcione, e defina color-scheme também na seção.
Mantenha a web e seus designs na mesma paleta
Um tema em CSS é só metade de uma marca. As mesmas cores devem aparecer nos seus posts, apresentações e e-mails. O brand kit do Gradiently guarda suas paletas, logos e fontes de título e de texto, e o Designer o aplica ao diagramar um design, então o post que você faz na segunda usa o mesmo destaque do seu site. Se ainda está escolhendo essas cores, comece por como escolher as cores da marca.
Perguntas frequentes
Como faço um tema com variáveis CSS?
Defina variáveis de paleta com as cores brutas e depois variáveis semânticas, como --color-bg, que apontam para elas. Os componentes leem só as semânticas, e os temas as reapontam.
Como adiciono modo escuro com variáveis CSS?
Sobrescreva as variáveis semânticas dentro de @media (prefers-color-scheme: dark) e sob um seletor [data-theme="dark"] para quem escolher.
Como evito que o tema pisque ao carregar a página?
Leia o tema salvo em um pequeno script inline no head e defina o atributo antes de a folha de estilo pintar a página.
O que o light-dark() faz no CSS?
Devolve o primeiro valor no modo claro e o segundo no modo escuro, conforme o color-scheme do elemento. Funciona nos principais navegadores atuais.
Posso guardar um gradiente em uma variável CSS?
Sim. Guarde o gradiente inteiro como valor e use em background. Para animar entre gradientes, registre os pontos com @property.
Escrito pelo Gradiently
A equipe por trás do Gradiently, uma ferramenta de design criada em torno dos Marks: gradientes vivos que fazem tudo o que você cria ter a sua cara.
Ver nosso perfil