Dlaczego deweloperzy przechodzą z RGB na HSL dla kolorów UI

Porównanie modeli kolorów RGB i HSL z edytorem kodu i próbkami kolorów

Model kolorów HSL (barwa, nasycenie, jasność) daje deweloperom znacznie bardziej czytelny sposób pracy z kolorami w CSS niż RGB. Zamiast zgadywać, która kombinacja wartości czerwonego, zielonego i niebieskiego da pożądany odcień, HSL pozwala opisywać kolory tak, jak myśli o nich ludzki mózg: wybierasz kolor, decydujesz jak bardzo ma być żywy, a potem jak jasny lub ciemny. To właśnie ta zmiana podejścia sprawia, że coraz więcej deweloperów porzuca rgb() na rzecz hsl() .

RGB vs HSL - Podstawowa różnica

RGB definiuje kolor przez mieszanie trzech kanałów świetlnych: czerwonego, zielonego i niebieskiego, każdego w skali od 0 do 255. Problem polega na tym, że to sposób, w jaki ekrany renderują piksele, a nie sposób, w jaki ludzie postrzegają kolory. Jeśli chcesz uzyskać nieco jaśniejszy niebieski w RGB, musisz zwiększyć wszystkie trzy kanały w odpowiednich proporcjach - nie ma jednego prostego parametru do przestawienia.

HSL odwzorowuje to, jak ludzie opisują kolory w codziennej rozmowie:

  • Barwa (Hue) - właściwy kolor, wyrażony jako stopień na kole barw o pełnym obrocie 360 stopni. Czerwony to 0, zielony to 120, niebieski to 240.
  • Nasycenie (Saturation) - jak żywy lub wyblakły jest kolor, od 0% (czysty szary) do 100% (maksymalnie nasycony).
  • Jasność (Lightness) - jak jasny lub ciemny jest kolor, od 0% (czarny) do 100% (biały), przy czym 50% to kolor "czysty".

Oto ten sam średni niebieski zapisany w obu formatach:

/* RGB - what do these numbers even mean at a glance? */
color: rgb(70, 130, 180);

/* HSL - instantly readable: blue hue, moderate saturation, medium lightness */
color: hsl(207, 44%, 49%);

Oba dają ten sam stalowy niebieski. Ale tylko wersja HSL mówi ci coś użytecznego na pierwszy rzut oka. Barwa wynosi 207 (niebieskawy odcień), nasycenie jest umiarkowane - 44%, a jasność plasuje się pośrodku na poziomie 49%. Możesz to przeanalizować bez otwierania próbnika kolorów.

Właściwość RGB HSL
Czytelność dla człowieka Rzadko Tak
Rozjaśnienie/przyciemnienie koloru Zmiana 3 wartości Zmiana tylko jasności
Zmiana nasycenia Przeliczenie wszystkich 3 Zmiana tylko nasycenia
Tworzenie palety kolorów Metodą prób i błędów Obrót barwy o stopnie
Motywy z CSS custom properties Nieczytelne Czyste i przewidywalne

Składnia HSL w CSS

Funkcja CSS hsl() jest obsługiwana od CSS3. Nowoczesna składnia (CSS Color Level 4) pozwala też na podanie czwartego parametru alfa bezpośrednio wewnątrz hsl() , co sprawia, że hsla() jest dziś w dużej mierze zbędne:

/* Classic syntax */
color: hsl(207, 44%, 49%);

/* With alpha (transparency) - old way */
color: hsla(207, 44%, 49%, 0.8);

/* Modern CSS Color Level 4 syntax - commas optional, alpha with slash */
color: hsl(207 44% 49%);
color: hsl(207 44% 49% / 0.8);
color: hsl(207 44% 49% / 80%);

Wszystkie główne przeglądarki obsługują obie składnie. Wersja bez przecinków to kierunek, w którym zmierza CSS, ale wersja z przecinkami działa wszędzie, włącznie z Internet Explorer 9+.

Dlaczego HSL wygrywa w tworzeniu UI

Prawdziwa siła HSL ujawnia się w momencie, gdy potrzebujesz wygenerować warianty koloru - a to w pracy nad interfejsem zdarza się nieustannie.

Budowanie palety kolorów w kilka sekund

Powiedzmy, że kolor marki to żywa zieleń przy hsl(140, 70%, 45%) . Potrzebujesz stanu hover, stanu nieaktywnego i jasnego tła. W HSL za każdym razem zmieniasz tylko jedną wartość:

--color-base:     hsl(140, 70%, 45%);  /* base green */
--color-hover:    hsl(140, 70%, 38%);  /* darker - just lower lightness */
--color-disabled: hsl(140, 20%, 65%);  /* washed out - lower saturation */
--color-tint:     hsl(140, 70%, 92%);  /* very light background tint */

Spróbuj zrobić to samo przewidywalnie w RGB bez otwartego próbnika kolorów. To naprawdę trudne, bo nie ma izolowanej osi do regulacji.

Kolory analogiczne i dopełniające

Ponieważ barwa to stopień na kole barw, generowanie harmonijnych palet to zwykła arytmetyka. Kolory analogiczne są w odległości do 30 stopni od siebie. Kolory dopełniające dzieli 180 stopni:

--primary:       hsl(210, 80%, 50%);   /* blue */
--analogous-1:   hsl(180, 80%, 50%);   /* cyan - 30 degrees left */
--analogous-2:   hsl(240, 80%, 50%);   /* purple - 30 degrees right */
--complementary: hsl(30, 80%, 50%);    /* orange - 180 degrees opposite */

Nasycenie i jasność pozostają identyczne, więc kolory tworzą spójną rodzinę. Dokładnie w ten sposób systemy projektowe takie jak Tailwind CSS i Material Design generują swoje skale kolorów programowo.

Praktyczne przykłady w CSS

CSS custom properties z komponentami HSL

Jednym z najpotężniejszych wzorców w HSL jest rozdzielenie trzech wartości na osobne CSS custom properties. Dzięki temu możesz je składać w dowolnym miejscu i na bieżąco modyfikować poszczególne kanały:

:root {
  --brand-h: 210;
  --brand-s: 80%;
  --brand-l: 50%;
  --brand-color: hsl(var(--brand-h), var(--brand-s), var(--brand-l));
}

.button {
  background-color: var(--brand-color);
}

.button:hover {
  /* Just override lightness - no need to redefine the whole color */
  background-color: hsl(var(--brand-h), var(--brand-s), 40%);
}

.button:disabled {
  background-color: hsl(var(--brand-h), 20%, 70%);
}
Uwaga dotycząca składni: Przy używaniu CSS custom properties wewnątrz hsl() wymagane są przecinki: hsl(var(--h), var(--s), var(--l)) . Nowoczesna składnia bez przecinków nie działa jeszcze z var() wewnątrz hsl() we wszystkich przeglądarkach.

Generowanie pełnej skali tonalnej

Systemy projektowe często potrzebują 9-10 odcieni jednego koloru (jak skala od 50 do 950 w Tailwind). Z HSL możesz wygenerować całą skalę, stopniując jasność w równych odstępach przy stałej barwie i nasyceniu:

:root {
  --blue-50:  hsl(210, 80%, 95%);
  --blue-100: hsl(210, 80%, 87%);
  --blue-200: hsl(210, 80%, 76%);
  --blue-300: hsl(210, 80%, 65%);
  --blue-400: hsl(210, 80%, 55%);
  --blue-500: hsl(210, 80%, 50%);  /* base */
  --blue-600: hsl(210, 80%, 43%);
  --blue-700: hsl(210, 80%, 36%);
  --blue-800: hsl(210, 80%, 26%);
  --blue-900: hsl(210, 80%, 16%);
}

Jeśli chcesz lepiej zrozumieć, jak formaty kolorów odnoszą się do siebie nawzajem, przewodnik po konwersji HEX na RGB przedstawia pełny obraz formatów kolorów CSS, w tym kiedy każdy z nich jest właściwym narzędziem.

Stany hover, motywy i tryb ciemny

Stany hover i focus

HSL sprawia, że stany hover stają się banalne. Zamiast definiować zupełnie osobny kolor, wystarczy przesunąć jasność:

.btn-primary {
  background: hsl(210, 80%, 50%);
  transition: background 0.2s ease;
}

.btn-primary:hover  { background: hsl(210, 80%, 43%); }
.btn-primary:active { background: hsl(210, 80%, 36%); }
.btn-primary:focus-visible {
  outline: 3px solid hsl(210, 80%, 70%);
}

Każdy stan jest wyraźnie powiązany z kolorem bazowym. Kolega czytający ten kod od razu rozumie zależności między stanami.

Motywy z zmiennymi HSL

HSL stanowi fundament nowoczesnych motywów CSS. Wystawiając samą barwę jako zmienną, możesz pozwolić użytkownikom lub administratorom zmienić cały schemat kolorystyczny aplikacji przez modyfikację jednej liczby:

/* Default theme: blue */
:root {
  --theme-hue: 210;
}

/* Green theme - just swap the hue */
[data-theme="green"] {
  --theme-hue: 140;
}

/* Purple theme */
[data-theme="purple"] {
  --theme-hue: 270;
}

/* All components use the same hue variable */
.button      { background: hsl(var(--theme-hue), 75%, 50%); }
.link        { color: hsl(var(--theme-hue), 75%, 40%); }
.badge       { background: hsl(var(--theme-hue), 75%, 92%); color: hsl(var(--theme-hue), 75%, 25%); }
.focus-ring  { outline-color: hsl(var(--theme-hue), 75%, 65%); }

Tryb ciemny z HSL

Tryb ciemny to miejsce, gdzie HSL naprawdę błyszczy. Zamiast utrzymywać dwie zupełnie osobne palety kolorów, odwracasz wartości jasności w obrębie tej samej barwy:

:root {
  --bg:   hsl(210, 20%, 98%);   /* near-white background */
  --text: hsl(210, 20%, 15%);   /* near-black text */
  --card: hsl(210, 20%, 93%);   /* slightly darker card */
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg:   hsl(210, 20%, 10%);  /* flip: near-black background */
    --text: hsl(210, 20%, 90%);  /* flip: near-white text */
    --card: hsl(210, 20%, 15%);  /* slightly lighter card in dark */
  }
}

Zwróć uwagę, że barwa (210) i nasycenie (20%) nigdy się nie zmieniają. Odwraca się tylko jasność. Dzięki temu tryb ciemny wygląda jak ten sam projekt, tylko odwrócony - a właśnie tak powinien wyglądać dobry tryb ciemny.

Wsparcie przeglądarek i kompatybilność

HSL cieszy się doskonałym wsparciem przeglądarek. Funkcja hsl() jest dostępna od:

  • Chrome 1 (2008)
  • Firefox 1 (2004)
  • Safari 3.1 (2008)
  • Internet Explorer 9 (2011)
  • Edge 12 (2015)

Nowoczesna składnia bez przecinków ( hsl(210 80% 50%) ) oraz składnia ze slash dla kanału alfa ( hsl(210 80% 50% / 0.5) ) są częścią specyfikacji CSS Color Level 4 i są obsługiwane przez wszystkie nowoczesne przeglądarki od 2023 roku. Jeśli musisz wspierać IE11 (co jest dziś rzadkością), trzymaj się składni z przecinkami.

Bezpieczne do użycia już dziś: hsl() z przecinkami działa w każdej przeglądarce, z której korzystają twoi użytkownicy. Nowoczesna składnia z separatorami spacjami działa w Chrome 90+, Firefox 89+ i Safari 14.1+, obejmując ponad 95% globalnego ruchu przeglądarek.

Możesz zawsze skorzystać z próbnika kolorów , aby konwertować między formatami HSL, RGB i HEX, gdy potrzebujesz skrzyżować wartości lub przekazać kolory do narzędzi obsługujących tylko jeden format.

HSL vs OKLCH - Co dalej?

Jeśli chcesz wyjść poza HSL, OKLCH jest wart uwagi. To percepcyjnie jednolita przestrzeń kolorów, co oznacza, że równe kroki numeryczne w jasności lub chrominancji naprawdę wyglądają jak równe kroki dla ludzkiego oka - czego HSL nie gwarantuje w pełni.

Problem z HSL polega na tym, że dwa kolory o tej samej wartości jasności mogą wyglądać bardzo różnie pod względem postrzeganej jasności. Na przykład hsl(60, 100%, 50%) (żółty) wygląda znacznie jaśniej niż hsl(240, 100%, 50%) (niebieski), mimo że oba mają 50% jasności. OKLCH koryguje ten problem.

/* HSL - same lightness, different perceived brightness */
color: hsl(60, 100%, 50%);   /* yellow - looks very bright */
color: hsl(240, 100%, 50%);  /* blue - looks much darker */

/* OKLCH - same lightness, actually looks the same to the eye */
color: oklch(0.75 0.18 90);   /* yellow-ish */
color: oklch(0.75 0.18 260);  /* blue-ish - genuinely similar perceived brightness */

OKLCH obsługuje również kolory szerokiej gamy (wide-gamut) (kolory wyświetlaczy P3) wykraczające poza zakres sRGB, do którego ograniczone jest HSL. Wsparcie przeglądarek dla oklch() jest solidne w 2024 roku: Chrome 111+, Firefox 113+, Safari 15.4+.

W przypadku większości projektów HSL jest dziś praktycznym złotym środkiem: czytelny, łatwy w utrzymaniu, powszechnie obsługiwany i ogromnie lepszy od RGB. OKLCH to właściwy wybór, gdy budujesz system projektowy wymagający matematycznie spójnych współczynników kontrastu lub chcesz celować w wyświetlacze szerokiej gamy.

Jeśli chcesz wizualnie eksplorować zależności kolorów podczas budowania palety, narzędzie do eksploracji kolorów pozwala eksperymentować z wartościami HSL i obserwować w czasie rzeczywistym, jak wzajemnie oddziałują obroty barwy, zmiany nasycenia i przesunięcia jasności.

Próbnik kolorów HSL pokazujący suwaki barwy, nasycenia i jasności

Dobieraj kolory HSL bez zgadywania

Nasz próbnik kolorów pozwala wizualnie ustawiać wartości barwy, nasycenia i jasności, a następnie skopiować gotowy wynik modelu kolorów HSL bezpośrednio do CSS - bez żadnych obliczeń w głowie.

Wypróbuj próbnik kolorów →

Nie musisz robić pełnego przepisania, ale warto przechodzić na HSL przy każdej nowej definicji koloru, szczególnie gdy używasz CSS custom properties. Największe korzyści pojawiają się przy budowaniu lub utrzymywaniu systemu projektowego, tworzeniu stanów hover albo wdrażaniu trybu ciemnego. Mieszanie RGB i HSL w tym samym projekcie to całkowicie poprawny CSS - przeglądarki obsługują oba formaty bez żadnej różnicy w wydajności.

Nie, nie ma żadnej istotnej różnicy w wydajności. Przeglądarka konwertuje wszystkie formaty kolorów CSS do wewnętrznej reprezentacji podczas parsowania, więc bez względu na to, czy napiszesz hsl(207, 44%, 49%) czy rgb(70, 130, 180) , silnik renderujący traktuje je identycznie po tym początkowym kroku parsowania. Wybór formatu dotyczy wyłącznie wygody dewelopera i łatwości utrzymania kodu, a nie wydajności w czasie wykonania.

Tak, i to jedno z najmocniejszych zastosowań HSL w JavaScript. Możesz przechowywać barwę, nasycenie i jasność jako osobne liczby, a następnie dynamicznie konstruować string koloru: element.style.color = `hsl(${hue}, ${saturation}%, ${lightness}%)` . Dzięki temu animacje, przełączanie motywów i interaktywne kontrolki kolorów są znacznie prostsze do zaimplementowania niż przy pracy z kanałami RGB, gdzie do osiągnięcia tych samych efektów potrzebowałbyś matematyki konwersji.

HSL (barwa, nasycenie, jasność) i HSB/HSV (barwa, nasycenie, jasność/wartość) to różne modele kolorów, mimo że mają wspólną oś barwy. W HSL jasność na poziomie 50% daje czysty, w pełni nasycony kolor. W HSB jasność na poziomie 100% daje czysty kolor. Oba modele dają różne wyniki dla tych samych wartości nasycenia i jasności. CSS używa konkretnie HSL - HSB/HSV jest powszechny w narzędziach projektowych takich jak Photoshop i Figma, ale nie jest natywnym formatem CSS.

Konwersja z HEX na HSL przebiega przez pośredni krok RGB: najpierw konwertujesz pary HEX na wartości RGB (0-255), normalizujesz je do zakresu 0-1, a następnie stosujesz wzór konwersji HSL. W praktyce większość deweloperów używa do tego próbnika kolorów, narzędzia projektowego jak Figma lub próbnika kolorów w DevTools przeglądarki, zamiast liczyć ręcznie. DevTools przeglądarki pozwalają kliknąć dowolną próbkę koloru i przełączać się między reprezentacjami HEX, RGB i HSL.

Tak, OKLCH jest bardziej niezawodny w pracy nad dostępnością, ponieważ jest percepcyjnie jednolity - równe kroki w kanale jasności odpowiadają równym zmianom postrzeganej jasności. Dzięki temu łatwiej budować palety kolorów, w których współczynniki kontrastu są przewidywalne dla różnych barw. W HSL żółty przy 50% jasności wygląda znacznie jaśniej niż niebieski przy 50% jasności, co może prowadzić do nieoczekiwanych problemów z dostępnością. Przy zapewnianiu zgodności z WCAG, OKLCH daje bardziej przewidywalne wyniki podczas budowania dostępnych skal kolorów.