# Tema com variáveis CSS: claro, escuro e cores da marca

[Canonical HTML page](https://gradiently.design/pt-br/guide/css-custom-properties-theming)

Temas dão errado quando as cores recebem nomes pelo que parecem em vez do que fazem. Nomeie os papéis, aponte-os para uma paleta, e modo claro, modo escuro e uma segunda marca viram poucas linhas cada.

## The short version

- 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.

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](https://gradiently.design/pt-br/guide/design-tokens), expressa direto em CSS.

| Camada | Exemplo | Quem lê | Muda quando |
| --- | --- | --- | --- |
| Paleta | `--violet-600: #7c3aed` | Só a camada de papéis | A marca é redesenhada |
| Papel | `--color-accent: var(--violet-600)` | Todo componente | O tema ou o modo muda |
| Componente | `--button-bg: var(--color-accent)` | Um componente | Um único componente precisa de um ajuste local |

A camada de componente é opcional. Use só onde um componente realmente precise diferir do papel.

```css
: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); }
```

Os componentes nunca mencionam violeta nem tinta. Essa única regra é o que torna o tema trocável.

- fundo: #faf8f5
- superfície: #f1ede6
- texto: #14121f
- texto suave: #6b6880
- destaque: #6d28d9

Os papéis do tema claro. Um fundo de papel quente, em vez de branco puro, deixa o destaque violeta mais calmo.

### 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.

```css
: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);
}
```

Os valores escuros aparecem duas vezes: uma para a preferência do sistema e outra para uma escolha explícita. Um mixin de pré-processador ou o `light-dark()` elimina a repetição.

- fundo: #0d0b16
- superfície: #17142a
- texto: #f2f0fa
- texto suave: #a5a1bd
- destaque: #c4b5fd

Os papéis do tema escuro. O destaque sobe para um violeta mais claro, porque o violeta do modo claro é escuro demais para ler sobre um fundo quase preto.

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](https://gradiently.design/pt-br/guide/dark-mode-design) e [gradientes para modo escuro](https://gradiently.design/pt-br/guide/dark-mode-gradients) 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.

```html
<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>
```

Roda antes da primeira pintura. O botão do seletor só precisa então definir `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 `light` ou `dark`; 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](https://gradiently.design/pt-br/guide/css-color-mix).

```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); }
```

Gradientes também podem ser tokens. Guarde o valor inteiro em uma variável e o hero muda com a marca.

- Hero Harbour: `linear-gradient(150deg, #042f2e 0%, #0f766e 55%, #5eead4 100%)`
- Hero Ember: `linear-gradient(150deg, #431407 0%, #c2410c 55%, #fdba74 100%)`

Os dois tokens de hero do código acima. Mesma estrutura, mesmo ângulo, marca diferente.

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.

> **Gradientes não têm transição sozinhos** Mudar uma variável de gradiente troca o fundo na hora. Para animar entre dois gradientes, registre os pontos de cor com `@property`, explicado em [CSS @property](https://gradiently.design/pt-br/guide/css-property-animation).

## 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](https://gradiently.design/pt-br/guide/how-to-choose-brand-colors).

## FAQ

### 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`.
