Tryb ciemny dla każdej strony — 4 podejścia CSS
Twój system operacyjny od kilku lat ma tryb ciemny. Twoja przeglądarka też. Większość aplikacji to respektuje. A potem otwierasz jakąś dokumentację, blog albo intranet z 2014 roku — i dostajesz w twarz 100% białym backgroundem o 23:00. Cztery metody, żeby raz na zawsze rozwiązać ten problem.
Dlaczego ten problem w ogóle istnieje
Standard prefers-color-scheme CSS jest w Chrome od 2019 roku, w Safari od 2018. Twoje OS zna preferencję, przeglądarka propaguje, strony powinny respektować. Powinny — w praktyce ~40% witryn ignoruje. Powody: stara codebaza, brak budżetu na drugi theme, marketing który chce „spójności brandu", autor jeszcze tego nie odkrył.
Skoro autor nie zrobi za Ciebie — zrób sam. Cztery metody, w kolejności rosnącej elegancji.
Metoda 1 — uniwersalny filter (działa na wszystkim)
Jeden snippet, pasuje do każdej strony, nie wymaga analizy konkretnego CSS-a:
html {
filter: invert(0.92) hue-rotate(180deg);
background: #1a1a1a;
}
/* Odwróć z powrotem obrazki, video i iframe'y żeby
wyglądały naturalnie — inaczej selfie znajomych mają
skórę zieloną. */
img, video, picture, iframe, svg,
[style*="background-image"] {
filter: invert(1) hue-rotate(180deg);
}
Trick: invert(0.92) zamiast pełnego invert(1) daje bardziej miękki czarny niż twardy biały→czarny — łatwiej dla oczu. hue-rotate(180deg) koryguje kolory żeby pomarańcz pozostał pomarańczem (a nie zmienił się w niebieski).
Plus: działa wszędzie, bez analizy.
Minus: drop shadows, gradienty, subtelne odcienie szarości wyglądają dziwnie. Niektóre fixed elementy (sticky header) mogą się rozsynchronizować.
Metoda 2 — wymuszenie prefers-color-scheme: dark
Strony, które mają dark mode, ale tylko reagują na OS-level preference. Co jeśli OS masz w trybie light (bo np. coś rysujesz w Figmie), ale chcesz dokumentację GitHuba na ciemno? Override matchMedia:
// Wymuś prefers-color-scheme: dark w JS
const dark = window.matchMedia('(prefers-color-scheme: dark)');
Object.defineProperty(dark, 'matches', {
get: () => true,
configurable: true,
});
// Powiadom listenerów (sites attached via addEventListener)
dark.dispatchEvent(new Event('change'));
To zadziała na każdej stronie, która używa window.matchMedia('(prefers-color-scheme: dark)') do detekcji — czyli wszystkich nowoczesnych React/Vue apps. Nie zadziała na stronach które robią detekcję raz, przy load (musisz zrefreshować), ani na statycznym CSS-ie bez JS detekcji.
Metoda 3 — override CSS custom properties
Strony zbudowane na CSS variables (czyli ~60% nowoczesnych webapps) zwykle mają tema-tokens jak --bg-primary, --text-primary. Otwierasz DevTools, znajdujesz nazwy, nadpisujesz:
/* Przykład: Stripe Dashboard, gdzie wszystko opiera się o vars */
:root {
--color-canvas-default: #0d1117 !important;
--color-canvas-subtle: #161b22 !important;
--color-fg-default: #c9d1d9 !important;
--color-fg-muted: #8b949e !important;
--color-border-default: #30363d !important;
}
Plus: precyzyjne, nie psuje obrazków i shadowów.
Minus: wymaga 5 minut grzebania w DevTools żeby znaleźć nazwy zmiennych. Strona musi używać CSS vars (sprawdź: document.documentElement.style w konsoli).
Metoda 4 — dedykowany dark theme per witryna
Dla stron, na których spędzasz godziny dziennie — opłaca się 30 minut na własny theme. Selektywne nadpisywanie:
/* Twoja jakaś-tam-firmowa intranet */
body, .page-content, .sidebar, .top-bar {
background: #1a1a1a !important;
color: #e0e0e0 !important;
}
.card, .panel, .modal {
background: #242424 !important;
border-color: #333 !important;
}
a, a:visited { color: #58a6ff !important; }
a:hover { color: #79c0ff !important; }
input, textarea, select {
background: #1a1a1a !important;
color: #e0e0e0 !important;
border-color: #444 !important;
}
/* Tablice — najbardziej krytyczne dla czytelności */
table th { background: #2d2d2d !important; color: #fff !important; }
table tr:nth-child(odd) { background: #1f1f1f !important; }
table tr:nth-child(even) { background: #1a1a1a !important; }
Zaczynasz od głównych kontenerów (body, page), schodzisz do komponentów (cards, modals), kończysz na elementach formularzy i tabelach. Bez !important zwykle się nie obejdzie — strona ma własne style o wyższej specyficzności.
Najczęstsze pułapki
- Inline background-image (np.
style="background: url(...)") — metoda 1 z filtrem nie zawsze łapie. Trzeba dodać[style*="background-image"]osobno. - Drop shadows na ciemnym tle wyglądają jak halo. Albo usuń (
box-shadow: none), albo zamień na lighter accent. - Brand colors (logo, kolorowe ikony) stracą rozpoznawalność po invert. Dodaj wyjątki:
.brand-logo { filter: invert(1) hue-rotate(180deg) !important; }. - Formularze często mają
color: blackhardkodowane w inline style. Nadpisuj wprost:input { color: #e0e0e0 !important; }. - Sticky / fixed elementy przy metodzie filter mogą się rozsynchronizować podczas scrolla. Zwykle akceptowalne, ale warto wiedzieć.
Jak to wpiąć w JustZix
- Zainstaluj JustZix (2 minuty).
- Utwórz katalog „Dark mode".
- Reguła „Dark mode wszędzie": wzorzec URL
*, CSS = Metoda 1. Ustaw nieaktywną domyślnie — odpalasz tylko gdy chcesz. - Reguła per ulubiona strona: wzorzec
https://mojaapka.com/*, CSS = Metoda 3 lub 4 (z konkretnymi tokenami / selektorami). Aktywna na stałe. - Toggluj cały katalog jednym klikiem na pływającym przycisku — światło/cień jednym ruchem.
Co dalej
Tę samą hierarchię (uniwersalny → precyzyjny per-site) używamy w innych kategoriach reguł — patrz Przykłady i Zastosowania. Dark mode jest po prostu najbardziej oczywistym przypadkiem.
Zainstaluj JustZix za darmo i miej w końcu kontrolę nad tym, jak wyglądają strony, na które patrzysz po 8 godzin dziennie.
Oceń ten wpis
Brak ocen — oceń jako pierwszy.