# Bygg ett tema med CSS-variabler: ljust, mörkt och varumärkesfärger

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

Teman går fel när färger namnges efter hur de ser ut i stället för vad de gör. Namnge rollerna, peka dem mot en palett, så blir ljust läge, mörkt läge och ett andra varumärke några rader vardera.

## The short version

- Ett tema med CSS-variabler fungerar bäst i två lager: palettvariabler som rymmer råa färger och semantiska variabler som beskriver vad varje färg är till för.
- Komponenter ska bara läsa semantiska variabler som --color-text eller --color-surface, aldrig palettvärden direkt.
- Mörkt läge blir då en fråga om att peka de semantiska variablerna mot andra palettvärden, under en mediefråga eller ett dataattribut.
- Funktionen light-dark() och egenskapen color-scheme låter en deklaration rymma båda lägena i aktuella webbläsare.
- Ett litet inbäddat skript i head som sätter det sparade temat innan sidan ritas förhindrar blixten av fel tema.

Ett **tema med CSS-variabler** är en uppsättning anpassade egenskaper, som `--color-surface` och `--color-text`, som varje komponent läser i stället för hårdkodade färger. För att byta tema ändrar du variablerna, oftast på `:root` eller på ett `data-theme`-attribut, och hela gränssnittet följer. Knepet som får det att skala är att dela variablerna i två lager: en palett av råa färger och semantiska roller som pekar mot den paletten.

## Två lager: palett och roller

Palettvariabler namnges efter vad de är: `--violet-600`, `--ink-900`. Semantiska variabler namnges efter vad de gör: `--color-accent`, `--color-text-muted`. Komponenter läser bara den andra sorten. När mörkt läge kommer pekar du om rollerna och lämnar varje komponent orörd. Det är samma idé som [designtokens](https://gradiently.design/sv/guide/design-tokens), uttryckt direkt i CSS.

| Lager | Exempel | Vem som läser det | Ändras när |
| --- | --- | --- | --- |
| Palett | `--violet-600: #7c3aed` | Bara rollagret | Varumärket designas om |
| Roll | `--color-accent: var(--violet-600)` | Varje komponent | Temat eller läget ändras |
| Komponent | `--button-bg: var(--color-accent)` | En komponent | En enskild komponent behöver en lokal vändning |

Komponentlagret är valfritt. Använd det bara där en komponent verkligen behöver skilja sig från rollen.

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

Komponenter nämner aldrig violett eller bläck. Den enda regeln är det som gör temat utbytbart.

- bg: #faf8f5
- surface: #f1ede6
- text: #14121f
- text-muted: #6b6880
- accent: #6d28d9

Det ljusa temats roller. En varm pappersbotten i stället för rent vitt gör att den violetta accenten känns lugnare.

### Namnge roller som överlever en omdesign

Ett rollnamn ska fortfarande vara sant när färgerna ändras. `--light-grey` slutar vara ljus i mörkt läge, och `--blue` ljuger den dag varumärket blir grönt. Namnge jobbet och paret i stället, så att den som läser stilmallen härnäst vet vilken färg som hör ihop med vilken.

### Namn som går sönder

- `--blue`, `--purple-button`
- `--light-grey-bg`
- `--white-text`
- `--dark-border`

### Namn som håller

- `--color-accent`, `--color-on-accent`
- `--color-surface`
- `--color-text`
- `--color-border`

## Lägg till mörkt läge med CSS-variabler

Mörkt läge pekar om rollerna. Respektera operativsystemets inställning som standard och låt ett `data-theme`-attribut åsidosätta den när läsaren väljer. Sätt också `color-scheme`, så att rullningslister, formulärkontroller och standardduken matchar.

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

De mörka värdena förekommer två gånger: en för systeminställningen och en för ett uttryckligt val. En preprocessor-mixin eller `light-dark()` tar bort upprepningen.

- bg: #0d0b16
- surface: #17142a
- text: #f2f0fa
- text-muted: #a5a1bd
- accent: #c4b5fd

Det mörka temats roller. Accenten lyfts till en ljusare violett, eftersom det ljusa lägets violett är för mörk för att läsas på en nästan svart botten.

Mörkt läge är inte ett inverterat ljust läge. Ytor blir ljusare ju högre de ligger, accenter ljusnar och skuggor viker för kantlinjer. [Design för mörkt läge](https://gradiently.design/sv/guide/dark-mode-design) och [gradienter för mörkt läge](https://gradiently.design/sv/guide/dark-mode-gradients) tar upp den visuella sidan.

### Genvägen light-dark()

Aktuella webbläsare stöder `light-dark()`, som tar ett ljust värde och ett mörkt värde och väljer ett utifrån elementets `color-scheme`. Sätt `color-scheme: light dark` på roten för att följa systemet, eller tvinga ett med attributet, så blir varje roll en enda rad: `--color-bg: light-dark(var(--paper-50), var(--night-950))`. Behåll den längre formen om du måste stödja webbläsare från före 2024.

## En temaväxlare som inte blinkar

Om det sparade valet tillämpas efter att sidan ritats ser läsare som valt mörkt en vit blixt vid varje laddning. Sätt attributet i ett pyttelitet inbäddat skript i `head`, innan någon stilmall målar kroppen.

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

Körs före första ritningen. Växlingsknappen behöver sedan bara sätta `dataset.theme` och spara värdet i `localStorage`.

1. **Erbjud tre val** Ljust, mörkt och system. Att ta bort attributet ger kontrollen tillbaka till `prefers-color-scheme`.
2. **Spara bara uttryckliga val** Lagra `light` eller `dark`; ta bort nyckeln för system, så att en senare ändring i operativsystemet respekteras.
3. **Undvik övergångar vid laddning** Om färger har övergångar, aktivera övergången först efter första ritningen, annars animeras sidan från ljus till mörk medan den laddas.

## Varumärkesteman bortom ljust och mörkt

Samma två lager hanterar flera varumärken i en kodbas. Varje varumärke ger sina egna palett- och rollvärden under ett `data-brand`-attribut, och lägena fungerar fortfarande ovanpå. Med `color-mix()` kan du härleda hovringslägen och toner från en accent per varumärke, som visas i [color-mix() i CSS](https://gradiently.design/sv/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); }
```

Gradienter kan också vara tokens. Lagra hela värdet i en variabel så ändras heron med varumärket.

- Hamnhero: `linear-gradient(150deg, #042f2e 0%, #0f766e 55%, #5eead4 100%)`
- Glödhero: `linear-gradient(150deg, #431407 0%, #c2410c 55%, #fdba74 100%)`

De två herotokens från koden ovan. Samma struktur, samma vinkel, olika varumärke.

Eftersom anpassade egenskaper ärvs behöver ett tema inte täcka hela sidan. Lägg `data-theme="dark"` på en sektion, som ett kampanjband eller en sidfot, så läser allt inuti den de mörka rollerna medan resten av sidan förblir ljus. Skriv den mörka väljaren som `[data-theme="dark"]` i stället för `:root[data-theme="dark"]` om du vill att det ska fungera, och sätt `color-scheme` på sektionen också.

> **Gradienter övergår inte av sig själva** Att ändra en gradientvariabel byter bakgrunden direkt. För att animera mellan två gradienter, registrera färgstoppen med `@property`, förklarat i [CSS @property](https://gradiently.design/sv/guide/css-property-animation).

## Håll webben och dina designer på en palett

Ett tema i CSS är bara halva ett varumärke. Samma färger ska finnas i dina sociala inlägg, presentationer och e-postmeddelanden. Gradiently varumärkeskit rymmer dina paletter, logotyper och rubrik- och brödtypsnitt, och Designer tillämpar det när den lägger ut en design, så att inlägget du gör på måndagen använder samma accent som din webbplats. Om du fortfarande väljer färgerna, börja med [hur du väljer varumärkesfärger](https://gradiently.design/sv/guide/how-to-choose-brand-colors).

## FAQ

### Hur gör jag ett tema med CSS-variabler?

Definiera palettvariabler med råa färger och sedan semantiska variabler som `--color-bg` som pekar mot dem. Komponenter läser bara de semantiska, och teman pekar om dem.

### Hur lägger jag till mörkt läge med CSS-variabler?

Åsidosätt de semantiska variablerna inuti `@media (prefers-color-scheme: dark)` och under en `[data-theme="dark"]`-väljare för läsare som väljer det.

### Hur stoppar jag att temat blinkar vid sidladdning?

Läs det sparade temat i ett litet inbäddat skript i `head` och sätt attributet innan stilmallen ritar sidan.

### Vad gör light-dark() i CSS?

Den returnerar sitt första värde i ljust läge och sitt andra i mörkt läge, utifrån elementets `color-scheme`. Den fungerar i aktuella större webbläsare.

### Kan jag lagra en gradient i en CSS-variabel?

Ja. Lagra hela gradienten som värde och använd den i `background`. För att animera mellan gradienter, registrera stoppen med `@property`.
