Lekcja 37
Tryby kolorów, zmienne motywu i dark mode
Dark mode nie polega na odwróceniu kolorów. To system tokenów, który pozwala zdefiniować jasny i ciemny motyw, zachować kontrast, dopasować natywne kontrolki przeglądarki i respektować preferencje użytkownika.
Cele lekcji
Po ukończeniu tej lekcji będziesz umieć:
- wyjaśnić rolę właściwości
color-scheme, - użyć
@media (prefers-color-scheme: dark), - zbudować jasny i ciemny motyw przez semantyczne custom properties,
- rozróżnić preferencję systemową od ręcznego wyboru użytkownika,
- projektować komponenty oparte o lokalne tokeny motywu,
- sprawdzić kontrast, fokus i stany interakcji w obu motywach.
Kontekst praktyczny
Motyw kolorystyczny dotyka całej aplikacji: tła, tekstu, obramowań, cieni, formularzy, linków, przycisków, alertów i stanów focus. Jeśli kolory są wpisane bezpośrednio w dziesiątkach komponentów, dark mode szybko staje się kosztowny i niespójny.
--blue-600 używaj tokenów semantycznych: --color-bg, --color-surface, --color-text, --color-border, --color-accent. Komponent nie musi wtedy wiedzieć, czy działa w jasnym czy ciemnym motywie.color-scheme
color-scheme informuje przeglądarkę, jakie tryby kolorów strona obsługuje. Dzięki temu elementy kontrolowane przez przeglądarkę, na przykład formularze, scrollbary i część natywnych kontrolek, mogą dopasować się do wybranego schematu.
:root {
color-scheme: light dark;
}
/* Opcjonalnie w HTML:
<meta name="color-scheme" content="light dark">
*/
Ta deklaracja nie tworzy sama ciemnego motywu. Mówi tylko, że strona umie działać w obu schematach. Kolory interfejsu nadal definiujesz w CSS.
prefers-color-scheme
Media feature prefers-color-scheme pozwala reagować na preferencję użytkownika ustawioną w systemie lub przeglądarce. To dobry punkt startowy dla automatycznego dark mode.
:root {
--color-bg: #f8fafc;
--color-text: #0f172a;
}
@media (prefers-color-scheme: dark) {
:root {
--color-bg: #0f172a;
--color-text: #e5e7eb;
}
}
To rozwiązanie respektuje system użytkownika, ale nie daje jeszcze ręcznego przełącznika. Jeśli produkt ma przełącznik motywu, potrzebujesz dodatkowej warstwy sterowania.
Tokeny semantyczne
Najważniejsza decyzja architektoniczna to oddzielenie tokenów bazowych od semantycznych. Komponent powinien używać tokenów mówiących o roli koloru, a nie o konkretnej wartości.
:root {
--color-bg: #f8fafc;
--color-surface: #ffffff;
--color-text: #0f172a;
--color-muted: #64748b;
--color-border: #dbe3ef;
--color-accent: #2563eb;
}
[data-theme="dark"] {
--color-bg: #10151f;
--color-surface: #172033;
--color-text: #f8fafc;
--color-muted: #a8b3c7;
--color-border: #2d3a50;
--color-accent: #7dd3fc;
}
Dzięki temu karta, formularz i przycisk nie muszą mieć osobnych zestawów kolorów dla każdego motywu. Wystarczy, że używają tych samych nazw tokenów.
Ręczne przełączanie
Preferencja systemowa jest dobra jako domyślna, ale wielu użytkowników oczekuje ręcznego wyboru. Najprostszy model to atrybut data-theme na elemencie html albo body.
<html lang="pl" data-theme="dark">
[data-theme="light"] {
color-scheme: light;
}
[data-theme="dark"] {
color-scheme: dark;
}
JavaScript może zapisać wybór w localStorage, ale CSS powinien być tak zaprojektowany, aby zmiana atrybutu wystarczyła do przełączenia całej palety.
Komponenty i lokalne tokeny
Komponent może mieć własne lokalne tokeny, które mapują globalny motyw na konkretną rolę komponentu. To szczególnie przydatne dla alertów, kart premium i stanów statusu.
.callout {
--callout-bg: var(--color-surface);
--callout-text: var(--color-text);
--callout-border: var(--color-border);
background: var(--callout-bg);
color: var(--callout-text);
border: 1px solid var(--callout-border);
}
Lokalne tokeny pozwalają zrobić wariant komponentu bez kopiowania całego zestawu reguł. Wariant zmienia tylko mapowanie wartości.
Kontrast i dostępność
Dark mode musi być czytelny. Zbyt jasny tekst na bardzo ciemnym tle może męczyć wzrok, a zbyt niskie kontrasty niszczą dostępność. Testuj tekst, linki, obramowania, fokus, disabled state i komunikaty błędów w obu motywach.
.button:focus-visible {
outline: 3px solid var(--color-focus);
outline-offset: 3px;
}
[data-theme="dark"] {
--color-focus: #fbbf24;
}
Nie zakładaj, że kolor fokusu z jasnego motywu będzie widoczny na ciemnym tle. Fokus i stany interakcji powinny mieć własne tokeny.
Demo dark mode
Demo pokazuje ten sam komponent dashboardu w jasnym i ciemnym motywie. Struktura HTML pozostaje taka sama, a zmieniają się tylko tokeny przypisane do powierzchni, tekstu, obramowania i akcentu.
Panel kursu
Jasny motyw używa spokojnego tła, ciemnego tekstu i niebieskiego akcentu.
Panel kursu
Ciemny motyw zachowuje strukturę, ale używa innych tokenów dla czytelności i kontrastu.
Najczęstsze błędy początkujących
- Tworzenie dark mode przez proste odwrócenie kolorów zamiast zaprojektowania palety.
- Używanie nazw tokenów typu
--whitei--blackw komponentach. - Brak
color-scheme, przez co natywne kontrolki nie pasują do motywu. - Ignorowanie ręcznego wyboru użytkownika i poleganie wyłącznie na preferencji systemowej.
- Testowanie tylko tła i tekstu, bez stanów hover, focus, disabled i error.
- Używanie cieni z jasnego motywu w ciemnym motywie bez korekty przezroczystości.
Mini zadanie
Zbuduj mały system motywu dla karty informacyjnej.
- Zdefiniuj w
:roottokeny--color-bg,--color-surface,--color-text,--color-muted,--color-borderi--color-accent. - Dodaj wariant
[data-theme="dark"]z ciemną paletą. - Ustaw
color-scheme: light darkdla bazowego dokumentu. - Zbuduj komponent
.info-card, który korzysta tylko z tokenów semantycznych. - Dodaj osobny token dla fokusu i sprawdź go w obu motywach.
- Przetestuj kartę w wariantach
data-theme="light"idata-theme="dark"bez zmieniania klas komponentu.
Checklista
- Rozumiem, że
color-schemenie zastępuje własnych tokenów kolorów. - Potrafię użyć
prefers-color-schemejako domyślnej reakcji na preferencję systemową. - Projektuję komponenty na tokenach semantycznych, nie na stałych kolorach.
- Wiem, jak ręcznie nadpisać motyw przez
data-theme. - Sprawdzam kontrast tekstu, linków, fokusu i stanów interakcji w obu motywach.
- Nie zakładam, że cienie, obramowania i błędy z jasnego motywu zadziałają w dark mode.
Podsumowanie lekcji
Profesjonalny dark mode zaczyna się od semantycznych tokenów. prefers-color-scheme pomaga respektować preferencje systemu, data-theme pozwala dodać ręczny wybór, a color-scheme synchronizuje natywne elementy przeglądarki z motywem strony.
Kolejny krok roadmapy to pierwszy praktyczny projekt końcowy: responsywna karta profilu.
Przejdź do Lekcji 38