Lekcja 29

Zmienne CSS i design tokens

Zmienne CSS pozwalają nazwać wartości i używać ich w wielu miejscach. Design tokens idą krok dalej: tworzą wspólny język dla kolorów, odstępów, promieni, cieni, typografii i stanów interfejsu.

Cele lekcji

Po ukończeniu tej lekcji będziesz umieć:

  • definiować zmienne CSS przez custom properties,
  • używać funkcji var() z wartością awaryjną,
  • odróżniać tokeny bazowe od tokenów semantycznych,
  • budować proste skale odstępów, promieni i cieni,
  • nadpisywać tokeny lokalnie w komponencie,
  • projektować tokeny tak, aby wspierały spójny system UI.

Kontekst praktyczny

W większym projekcie te same wartości pojawiają się w wielu komponentach. Bez tokenów szybko powstaje kilkanaście podobnych odcieni, promieni i cieni. Z czasem trudno ocenić, która wartość jest aktualna, a która została po jednorazowej poprawce.

W praktyce: design token jest decyzją projektową zapisaną w kodzie. Zamiast pamiętać, że główny kolor to #2563eb, używasz --color-primary albo --color-action-bg.

Custom properties

Zmienne CSS definiuje się jako custom properties, czyli właściwości zaczynające się od dwóch myślników. Najczęściej zapisuje się je w :root, aby były dostępne globalnie.

:root {
  --color-primary: #2563eb;
  --space-md: 1rem;
  --radius-md: .75rem;
}

.button {
  padding: var(--space-md);
  border-radius: var(--radius-md);
  background: var(--color-primary);
}

Custom properties dziedziczą się podobnie jak wiele zwykłych właściwości CSS. To daje dużą elastyczność, ale wymaga konsekwentnych nazw.

var() i fallback

Funkcja var() pobiera wartość zmiennej. Możesz dodać fallback, czyli wartość awaryjną, która zostanie użyta, gdy zmienna nie istnieje.

.alert {
  color: var(--alert-text, #7f1d1d);
  background: var(--alert-bg, #fee2e2);
}

Fallback nie zastępuje dobrej organizacji tokenów. Jest zabezpieczeniem, a nie sposobem na ukrywanie chaosu w nazwach.

Tokeny bazowe

Token bazowy opisuje surową wartość skali: konkretny kolor, odstęp, promień albo cień. Jest blisko systemu wizualnego, ale nie zawsze mówi, gdzie powinien być użyty.

:root {
  --blue-600: #2563eb;
  --green-600: #16a34a;
  --space-4: 1rem;
  --radius-3: .75rem;
}

Tokeny bazowe są przydatne jako fundament, ale w komponentach często lepiej używać tokenów semantycznych.

Tokeny semantyczne

Token semantyczny opisuje rolę wartości w interfejsie. Dzięki temu komponent nie musi wiedzieć, jaki dokładnie odcień reprezentuje akcję, sukces albo powierzchnię.

:root {
  --color-action-bg: var(--blue-600);
  --color-success-bg: #dcfce7;
  --color-surface-default: #ffffff;
  --color-border-subtle: #e2e8f0;
}

Gdy zmieniasz brand albo tryb kolorystyczny, semantyka pozwala wymienić wartości bez przepisywania każdego komponentu.

Skale odstępów i promieni

Design tokens najlepiej działają jako małe skale. Nie potrzebujesz dwudziestu prawie identycznych odstępów. Potrzebujesz kilku nazwanych wartości, które powtarzają się konsekwentnie.

:root {
  --space-xs: .25rem;
  --space-sm: .5rem;
  --space-md: 1rem;
  --space-lg: 1.5rem;
  --radius-sm: .5rem;
  --radius-md: .75rem;
}

Skala nie musi być idealna matematycznie. Ważniejsze, żeby była mała, czytelna i stosowana konsekwentnie.

Lokalne nadpisanie

Custom properties możesz nadpisać lokalnie w komponencie. To dobry wzorzec dla wariantów, bo komponent zachowuje tę samą strukturę, a zmienia tylko zestaw tokenów.

.status-card {
  --status-bg: #eff6ff;
  --status-border: #bfdbfe;
  background: var(--status-bg);
  border-color: var(--status-border);
}

.status-card--success {
  --status-bg: #f0fdf4;
  --status-border: #86efac;
}

Taki komponent jest łatwiejszy do rozszerzania niż kilka wariantów kopiujących pełne zestawy właściwości.

Demo design tokens

Demo pokazuje jeden komponent korzystający z tych samych nazw tokenów. Wariant domyślny i sukcesu różnią się tylko wartościami tokenów lokalnych.

Default

Karta statusu

Komponent korzysta z tokenów dla tła, obramowania, promienia i odstępów.

  • --status-bg#eff6ff
  • --status-border#bfdbfe
  • --status-accent#2563eb
Success

Karta statusu

Wariant nie kopiuje całego CSS. Nadpisuje tylko semantyczne tokeny.

  • --status-bg#f0fdf4
  • --status-border#86efac
  • --status-accent#16a34a

Najczęstsze błędy początkujących

  • Tworzenie tokenów dla każdej pojedynczej wartości bez realnej skali.
  • Nazywanie tokenów tylko po kolorze, gdy komponent potrzebuje znaczenia semantycznego.
  • Mieszanie tokenów globalnych z lokalnymi bez jasnej konwencji.
  • Używanie fallbacków w var() jako sposobu na omijanie braków w systemie.
  • Nadpisywanie tokenów w zbyt wielu miejscach naraz.
  • Dodawanie tokenów, których nikt nie używa w komponentach.

Mini zadanie

Zbuduj mały zestaw tokenów dla kart informacyjnych.

  • Zdefiniuj w :root tokeny dla koloru akcji, sukcesu, powierzchni i obramowania.
  • Dodaj skalę odstępów: --space-sm, --space-md, --space-lg.
  • Dodaj tokeny promienia i cienia.
  • Zbuduj klasę .info-card korzystającą wyłącznie z tokenów.
  • Dodaj wariant .info-card--success, który nadpisuje tylko lokalne tokeny wariantu.

Checklista

  • Potrafię zdefiniować custom property i użyć jej przez var().
  • Rozumiem różnicę między tokenem bazowym i semantycznym.
  • Potrafię zaprojektować małą skalę odstępów, promieni i cieni.
  • Wiem, kiedy użyć fallbacku w var().
  • Potrafię nadpisać token lokalnie dla wariantu komponentu.
  • Nie dodaję tokenów, które nie mają zastosowania w realnym UI.

Podsumowanie lekcji

Zmienne CSS i design tokens pomagają utrzymać spójność wizualną oraz zmniejszają koszt zmian w projekcie. Najważniejsze jest rozdzielenie surowych wartości od semantycznych decyzji UI i konsekwentne stosowanie tokenów w komponentach.

Kolejny krok roadmapy to kaskada, specyficzność i @layer.

Przejdź do Lekcji 30