OKLCH w CSS – kompletny przewodnik dla webdeveloperów
Jeśli pracujesz z kolorami w CSS dłużej niż pięć minut, prawdopodobnie zauważyłeś pewien problem. Tworzysz paletę kolorów w HSL, wszystkie mają tę samą wartość jasności (powiedzmy 50%), a mimo to żółty wygląda jakby świecił jak słońce, podczas gdy niebieski jest ciemny jak noc. Frustrujące, prawda?
To nie Twoja wina. To fundamentalny problem z przestrzenią barw HSL, która nie odzwierciedla tego, jak nasze oczy faktycznie postrzegają kolory. Na szczęście CSS w końcu otrzymał narzędzie, które rozwiązuje ten problem raz na zawsze – OKLCH.
Czym właściwie jest OKLCH?
OKLCH to przestrzeń barw oparta na percepcji wzrokowej człowieka. Te trzy litery pochodzą od „OK” (z modelu OKLab, stworzonego przez Björna Ottosson w 2020 roku) oraz „LCH” (Lightness, Chroma, Hue). W przeciwieństwie do HSL czy RGB, które zostały zaprojektowane z myślą o technologii wyświetlaczy, OKLCH został stworzony z myślą o… nas. O naszych oczach.
Kiedy specyfikacja CSS Color Level 4 wprowadzała nowe przestrzenie barw, zespół W3C stanął przed wyborem. Mogliby kontynuować z przestrzeniami technicznymi, które są łatwe do implementacji, ale trudne w użyciu. Zamiast tego wybrali przestrzenie perceptualne, gdzie matematyka jest bardziej skomplikowana, ale dla nas, developerów, wszystko staje się prostsze i bardziej przewidywalne.
Anatomia składni OKLCH
background: oklch(70% 0.15 260);
/* ↑ ↑ ↑
L C H
(Lightness)(Chroma)(Hue)
*/
L – Lightness (Jasność)
Wartość od 0% do 100%, gdzie 0% to absolutna czerń, a 100% to absolutna biel. Ale tutaj dzieje się magia – w przeciwieństwie do HSL, ta wartość faktycznie odpowiada temu, jak jasny kolor postrzegamy wzrokowo.
.colors {
/* Te kolory są NAPRAWDĘ równie jasne dla ludzkiego oka */
--yellow: oklch(95% 0.21 110);
--blue: oklch(95% 0.13 250);
--red: oklch(95% 0.17 25);
}
W HSL musielibyśmy użyć kompletnie różnych wartości lightness, żeby osiągnąć ten sam efekt wizualny. To jak porównywać termometr Celsjusza z termometrem, który pokazuje różne temperatury w zależności od koloru pomieszczenia – jeden ma sens, drugi nie.
C – Chroma (Nasycenie)
Wartość zazwyczaj od 0 do około 0.4, choć teoretycznie może być wyższa dla niektórych kolorów. Zero oznacza brak koloru (szarość), a wyższe wartości to bardziej intensywne, nasycone kolory.
.saturation-demo {
/* Od szarości do pełnego nasycenia */
--gray: oklch(60% 0 260); /* Szary */
--muted: oklch(60% 0.05 260); /* Stonowany fiolet */
--normal: oklch(60% 0.15 260); /* Standardowy fiolet */
--vivid: oklch(60% 0.25 260); /* Intensywny fiolet */
}
Ciekawostka: maksymalna wartość chroma różni się w zależności od odcienia i jasności. Dla żółtego może sięgać 0.35, podczas gdy dla niebieskiego zwykle kończy się na 0.31. To naturalne ograniczenie ludzkiego widzenia, nie wada formatu.
H – Hue (Odcień)
Wartość od 0 do 360 stopni, reprezentująca pozycję na kole kolorów. To działa identycznie jak w HSL, więc jeśli znasz tamten system, będziesz czuł się jak w domu.
| Stopnie | Kolor |
|---|---|
| 0° / 360° | Czerwony |
| 30° | Pomarańczowy |
| 60° | Żółty |
| 120° | Zielony |
| 180° | Cyjan |
| 240° | Niebieski |
| 300° | Magenta |
OKLCH vs HSL – bitwa na przykładach
Stwórzmy zestaw przycisków w różnych kolorach. Chcemy, żeby wszystkie były równie jasne, żeby interfejs wyglądał harmonijnie.
Podejście HSL (problematyczne):
.button-red { background: hsl(0, 70%, 50%); } /* Wygląda OK */
.button-yellow { background: hsl(60, 70%, 50%); } /* Za jasny! */
.button-green { background: hsl(120, 70%, 50%); } /* Trochę ciemny */
.button-blue { background: hsl(240, 70%, 50%); } /* Zdecydowanie za ciemny */
Wszystkie mają L=50%, ale wizualnie są kompletnie różnej jasności. Żółty przycisk praktycznie świeci, podczas gdy niebieski znika w tle. Musiałbyś ręcznie dostosowywać każdą wartość lightness, testować, poprawiać, testować znowu…
Podejście OKLCH (przewidywalne):
.button-red { background: oklch(60% 0.2 30); }
.button-yellow { background: oklch(60% 0.2 100); }
.button-green { background: oklch(60% 0.2 140); }
.button-blue { background: oklch(60% 0.2 250); }
Wszystkie mają L=60% i C=0.2, zmieniamy tylko odcień. Rezultat? Przyciski, które faktycznie wyglądają na równie jasne. Żadnych niespodzianek, żadnego męczącego dostosowywania. Chris Coyier na swoim blogu CSS-Tricks podsumował to słowami: „It just works the way your brain thinks it should work.”
Praktyczne zastosowania OKLCH
Automatyczne generowanie wariantów kolorów
To jest miejsce, gdzie OKLCH naprawdę błyszczy. Możesz stworzyć cały system kolorów z jednego bazowego koloru.
:root {
--primary: oklch(60% 0.2 260);
}
.primary-50 {
background: oklch(from var(--primary) 95% c h);
}
.primary-100 {
background: oklch(from var(--primary) 90% c h);
}
.primary-500 {
background: var(--primary);
}
.primary-900 {
background: oklch(from var(--primary) 25% c h);
}
Zwróć uwagę na składnię oklch(from var(--primary) 95% c h). To relative color syntax – bierzemy wszystkie składowe z --primary (stąd c i h bez wartości), ale nadpisujemy jasność na 95%. Genialnie proste.
Tworzenie dostępnych palet
WCAG wymaga określonego kontrastu między tekstem a tłem. Z OKLCH możesz to kontrolować matematycznie.
:root {
/* Kolor bazowy */
--brand-color: oklch(55% 0.18 270);
/* Automatycznie jasny tekst (L > 85% gwarantuje dobry kontrast) */
--text-on-brand: oklch(from var(--brand-color) 92% calc(c * 0.3) h);
/* Automatycznie ciemny tekst dla jasnych tłach */
--text-dark: oklch(25% 0.02 270);
}
.card {
background: var(--brand-color);
color: var(--text-on-brand);
}
Interpolacja kolorów w animacjach
Czy kiedykolwiek animowałeś przejście z niebieskiego w żółty i otrzymałeś… szarość pośrodku? To problem interpolacji w RGB lub HSL. OKLCH rozwiązuje to elegancko.
.button {
background: oklch(60% 0.2 240); /* Niebieski */
transition: background 0.5s in oklch;
}
.button:hover {
background: oklch(60% 0.2 100); /* Żółty */
}
Słowo kluczowe in oklch mówi przeglądarce, żeby interpolowała w przestrzeni OKLCH. Rezultat? Płynne, naturalne przejście przez zielenie i cyany, bez szarego błota.
Mieszanie kolorów z color-mix()
.element {
/* Zmiesz niebieski z białym w proporcji 70/30 */
background: color-mix(in oklch, blue 70%, white);
/* Stwórz półprzezroczystą wersję koloru */
border: 2px solid color-mix(in oklch, var(--primary) 50%, transparent);
/* Przyciemnij kolor przez mieszanie z czernią */
box-shadow: 0 4px 8px color-mix(in oklch, var(--primary) 80%, black);
}
Tabela porównawcza przestrzeni barw
| Cecha | RGB | HSL | OKLCH | Zwycięzca |
|---|---|---|---|---|
| Perceptualna jasność | ✗ | ✗ | ✓ | OKLCH |
| Łatwa manipulacja | ✗ | ✓ | ✓ | HSL/OKLCH |
| Naturalne mieszanie | ✗ | ✗ | ✓ | OKLCH |
| Szeroki gamut kolorów | Ograniczony | Ograniczony | Pełny | OKLCH |
| Browser support (2025) | 100% | 100% | 92%+ | RGB/HSL |
| Czytelność kodu | Średnia | Dobra | Dobra | HSL/OKLCH |
Pułapki i ograniczenia
Nie wszystko jest idealne. OKLCH ma swoje wyzwania, o których powinieneś wiedzieć.
Problem gamut clipping
OKLCH może reprezentować kolory spoza zakresu sRGB (standardowa przestrzeń kolorów dla większości monitorów). Jeśli zapiszesz oklch(70% 0.4 140), przeglądarka może „przyciąć” ten kolor do najbliższego dostępnego w sRGB.
/* Ten kolor może być poza gamut */
.vivid {
background: oklch(70% 0.35 140);
}
/* Bezpieczniejsza wersja z fallbackiem */
.vivid-safe {
background: rgb(50 200 50); /* Fallback dla starszych przeglądarek */
background: oklch(70% 0.25 140);
}
Browser support
Na początku 2025 roku OKLCH jest wspierany w:
- Chrome/Edge 111+
- Safari 15.4+
- Firefox 113+
To około 92% użytkowników globalnie. Ale zawsze powinieneś mieć fallback dla starszych przeglądarek.
.element {
background: #3498db; /* Fallback */
background: oklch(60% 0.15 240);
}
Nie wszystkie narzędzia to wspierają
Photoshop, Figma, Sketch – większość narzędzi designerskich wciąż pracuje w RGB lub HSL. Możesz potrzebować konwertera, żeby przekładać kolory z designu na OKLCH. Na szczęście są dostępne narzędzia online jak oklch.com czy color.js.
Praktyczny workflow z OKLCH
Oto jak ja podchodzę do tworzenia systemu kolorów w nowym projekcie:
Zaczynam od wybrania bazowego koloru marki w OKLCH – zazwyczaj ustawiam L między 50-60% dla dobrej czytelności. Potem generuję warianty automatycznie: jasne wersje (L=80-95%) do tła, ciemne (L=20-35%) do tekstu, stonowane (C≈0.05) do subtekstów. Wszystko z tego jednego bazowego koloru.
:root {
/* Jeden bazowy kolor */
--base-hue: 260;
/* System skali jasności */
--color-50: oklch(97% 0.05 var(--base-hue));
--color-100: oklch(93% 0.08 var(--base-hue));
--color-200: oklch(86% 0.12 var(--base-hue));
--color-500: oklch(60% 0.2 var(--base-hue));
--color-700: oklch(45% 0.18 var(--base-hue));
--color-900: oklch(28% 0.12 var(--base-hue));
}
Następnie testuję kontrast – OKLCH ułatwia to, bo mogę po prostu sprawdzić różnicę w wartościach L. Jeśli różnica jest większa niż 40-50 punktów procentowych, kontrast zazwyczaj jest OK.
Kiedy NIE używać OKLCH?
Paradoksalnie, są sytuacje, gdzie OKLCH może być przesadą. Jeśli pracujesz z gotowym design systemem, który został stworzony w HSL, konwersja może być czasochłonna i niekoniecznie przyniesie wymierne korzyści. Jeśli wspierasz starsze przeglądarki i nie chcesz mnożyć fallbacków, HSL wciąż jest solidnym wyborem.
Dla prostych projektów, gdzie masz 3-4 kolory ręcznie dobrane przez designera i nie planujesz ich programatycznego generowania, różnica może być niezauważalna. OKLCH błyszczy tam, gdzie masz system, skalę, automatyzację.
Przyszłość to OKLCH
Adobe w swoim State of Color Report z 2024 roku zauważył rosnący trend w stronę przestrzeni barw opartych na percepcji. Specyfikacja CSS Color Level 5 już teraz eksploruje jeszcze bardziej zaawansowane możliwości związane z HDR i szerokimi gamutami. OKLCH to nie tylko chwilowy trend – to fundamentalny krok w stronę bardziej intuicyjnego, ludzkiego podejścia do koloru w web designie.
Jeśli zaczynasz nowy projekt w 2025 roku, OKLCH powinien być Twoim domyślnym wyborem. Jeśli masz istniejący projekt, zastanów się nad stopniową migracją – szczególnie dla komponentów, gdzie tworzysz warianty kolorów programatycznie. Czas przestać walczyć z matematyką kolorów i zacząć używać narzędzia, które faktycznie rozumie, jak widzimy świat.
Kolory w CSS w końcu mają sens. I to jest piękne.


Nazywam się Arek Meszka. Prowadzę tego bloga, aby podzielić się wiedzą i wnieść coś do internetowej społeczności. Tworzę strony internetowe.