Przejdź do próbnika kolorów

CSS color-mix() i kolory względne: rozjaśnienia, hover i przezroczystość

color-mix() miesza dwa kolory w wybranej przez ciebie przestrzeni barw, a składnia kolorów względnych pozwala zmienić jeden kanał istniejącego koloru, na przykład oklch(from var(--brand) calc(l - 0.1) c h). Obie działają w przeglądarce, współpracują ze zmiennymi CSS i zastępują większość funkcji kolorów z Sass. Do rozjaśnień i hovera mieszaj w oklab, do przezroczystości w srgb.

6 min czytania

Jak działa color-mix()

color-mix() przyjmuje przestrzeń barw i dwa kolory z opcjonalnymi procentami, a zwraca kolor pomiędzy nimi. color-mix(in oklab, var(--brand) 90%, black) oznacza 90% koloru marki i 10% czerni, zmieszane w Oklab. Gdy podasz jeden procent, drugi kolor dostaje resztę. Gdy nie podasz żadnego, każdy dostaje 50%.

Przeglądarka liczy wynik w trakcie działania strony, więc działa to z własnymi właściwościami (custom properties), currentColor i przełączaniem motywów. Funkcje Sass wykonują się raz, podczas budowania, i nie widzą wartości var().

Jeśli oba procenty sumują się do mniej niż 100%, wynik staje się też częściowo przezroczysty: color-mix(in srgb, red 30%, blue 30%) to równa mieszanka przy 60% krycia. Trzymaj sumę na 100%, chyba że właśnie tego chcesz.

CSS

.button {
    --brand: #2563eb;
    background: var(--brand);
}

.button:hover {
    background: color-mix(in oklab, var(--brand) 90%, black);
}

.badge {
    background: color-mix(in oklab, var(--brand) 10%, white);
    border-color: color-mix(in srgb, var(--brand) 30%, transparent);
}

W jakiej przestrzeni barw mieszać: srgb, oklab czy oklch

Przestrzeń zmienia wynik bardziej, niż większość osób się spodziewa. Poniżej czysty niebieski #0000ff zmieszany pół na pół z czystym żółtym #ffff00, policzony tą samą matematyką, której używa przeglądarka.

W srgb kanały uśredniają się dokładnie do 128, 128, 128: mieszanka to #808080, szary o zerowej chromie. Oklab też miesza po linii prostej, a niebieski i żółty leżą po jej przeciwnych stronach, więc w dużej mierze się znoszą i dają matowy, szarawy niebieski. Oklch interpoluje zamiast tego kąt barwy, idąc krótszą drogą od 264° do 110°, więc środek to intensywny morski turkus o barwie 187°, który zachowuje chromę obu kolorów wejściowych.

PrzestrzeńNiebieski + żółtyL, C w OKLCHBlue-600 + yellow-400L, C w OKLCH
srgb#8080800.600, 0#9098800.665, 0.035
oklab#6cabc70.710, 0.077#90a3ad0.703, 0.026
oklch#00bdb00.710, 0.262#00bd9e0.703, 0.194

Druga para to #2563eb i #facc15 z Tailwind. Wyniki oklch wypadają poza sRGB, więc chroma jest podana przed mapowaniem gamutu, a hex to najbliższy kolor, jaki potrafi wyświetlić ekran sRGB.

Rzucają się w oczy dwie rzeczy. Srgb ląduje na jasności 0,600, podczas gdy percepcyjny środek między niebieskim (0,452) a żółtym (0,968) to 0,710: stąd ciemny, zabłocony środek gradientów w srgb. I tylko oklch zachowuje intensywność mieszanki, za cenę przejścia przez barwę, której nie ma żaden z kolorów wejściowych.

Praktyczna zasada: w oklab mieszaj rozjaśnienia, przyciemnienia i stany hover, gdzie zostajesz przy jednej barwie i chcesz równych kroków jasności. W oklch mieszaj, gdy oba kolory są nasycone i chcesz nasyconego wyniku. W srgb mieszaj przezroczystość, bo tak przeglądarka składa warstwy.

Przepisy: hover, rozjaśnienia i przezroczyste warianty

Wszystkie wartości poniżej używają #2563eb jako --brand. Biały tekst na nim ma współczynnik kontrastu 5,17:1.

Domieszka 10% czerni przyciemnia w oklab mocniej niż w srgb: kontrast białego tekstu rośnie do 6,50:1 wobec 6,11:1. Oklab i oklch dają ten sam wynik, gdy drugim kolorem jest czerń lub biel, bo nie mają one barwy do interpolacji.

PrzepisCSSWynikKontrast
Hover, o 10% ciemniejcolor-mix(in oklab, var(--brand) 90%, black)#1f55cc6.50:1 z białym tekstem
Active, o 20% ciemniejcolor-mix(in oklab, var(--brand) 80%, black)#1947ae8.22:1 z białym tekstem
Hover mieszany w srgbcolor-mix(in srgb, var(--brand) 90%, black)#2159d36.11:1 z białym tekstem
Rozjaśnione tło, 10%color-mix(in oklab, var(--brand) 10%, white)#e8f0ff4.51:1 z tekstem w kolorze marki
Rozjaśnione tło, 20%color-mix(in oklab, var(--brand) 20%, white)#d2e2ff3.95:1 z tekstem w kolorze marki
Przezroczysty, 20%color-mix(in srgb, var(--brand) 20%, transparent)rgba(37, 99, 235, 0.2)Na bieli wygląda jak #d3e0fb

Uważaj na rozjaśnienia. Tekst w kolorze marki ma 5,17:1 na bieli, 4,51:1 na rozjaśnieniu 10% i tylko 3,95:1 na rozjaśnieniu 20%, co nie spełnia WCAG AA dla zwykłego tekstu. Jeśli kładziesz tekst w kolorze marki na jej rozjaśnieniu, użyj dla tekstu koloru z hovera.

Mieszanie z transparent zachowuje kolor i obniża tylko kanał alfa, bo przeglądarka miesza wartości z premnożoną alfą. Wynik dopasowuje się do tego, co jest pod spodem: ta sama reguła wygląda jak #d3e0fb na bieli i jak #132651 na ciemnej powierzchni #0f172a. Rozjaśnienie zmieszane z bielą zostaje blade na ciemnej stronie, więc dla komponentów widocznych w obu motywach wersja przezroczysta jest zwykle lepszym wyborem.

Składnia kolorów względnych: zmiana jednego kanału

Składnia kolorów względnych bierze istniejący kolor, rozkłada go na kanały i pozwala przepisać dowolny z nich przez calc(). W oklch(from var(--brand) l c h) słowa kluczowe l, c i h przechowują jasność (od 0 do 1), chromę i barwę --brand.

W przeciwieństwie do color-mix() zmienia dokładnie jedną właściwość: obniża jasność bez ruszania chromy, obraca barwę bez zmiany jasności albo dodaje alfę do koloru zapisanego jako hex.

PrzepisCSSWynik z #2563ebBiały tekst
Ciemniejszyoklch(from var(--brand) calc(l - 0.1) c h)#0442c88.02:1
Jaśniejszyoklch(from var(--brand) calc(l + 0.1) c h)#4484ff3.51:1
Połowa chromyoklch(from var(--brand) l calc(c * 0.5) h)#4e6faf4.98:1
Barwa +30°oklch(from var(--brand) l c calc(h + 30))#7a49df5.46:1
Komplementarnyoklch(from var(--brand) l c calc(h + 180))#9567004.98:1
Szary, ta sama jasnośćoklch(from var(--brand) l 0 h)#7070704.95:1
Alfa 50%oklch(from var(--brand) l c h / 0.5)rgba(37, 99, 235, 0.5)Zależy od tła

CSS

:root {
    --brand: #2563eb;
    --brand-hover: oklch(from var(--brand) calc(l - 0.08) c h);
    --brand-muted: oklch(from var(--brand) l calc(c * 0.5) h);
    --brand-ring: oklch(from var(--brand) l c h / 0.4);
    --accent: oklch(from var(--brand) l c calc(h + 30));
}

Spójrz na cztery wiersze, które zachowują l: zmiana chromy lub barwy przesuwa kontrast białego tekstu tylko w zakresie od 4,95:1 do 5,46:1, wobec 5,17:1 dla oryginału. O kontraście decyduje jasność, więc warianty barwy zbudowane w ten sposób zachowują mniej więcej tę samą dostępność. Kolor jaśniejszy i komplementarny przy pełnej chromie wypadają poza sRGB, a przeglądarka mapuje je na najbliższy kolor, jaki potrafi wyświetlić.

color-mix() a kolory względne a Sass darken()

Używaj color-mix(), gdy myślisz kategoriami „trochę czerni” albo „trochę przezroczystości”. Używaj składni kolorów względnych, gdy myślisz kanałami: „ten sam kolor, o 0,1 ciemniejszy”. Obie zastępują większość funkcji kolorów z Sass i nadążają za zmianą motywu bez przebudowy.

color-mix()Składnia kolorów względnychSass darken()
Gdzie działaW przeglądarceW przeglądarcePodczas budowania
Działa z var() i currentColorTakTakNie
Model koloruPrzestrzeń, którą podasz: srgb, oklab, oklch, hsl i inneDowolna funkcja koloru: oklch(), rgb(), hsl(), lab()Tylko HSL
Najlepsze doRozjaśnień, przyciemnień, przezroczystości, mieszania dwóch tokenówZmiany jednego kanału: jasności, chromy, barwy lub alfyStarego kodu ze stałymi kolorami
Wielkość krokuCzęść odległości do drugiego koloruDokładna, w jednostkach kanałuStałe punkty HSL, nierówne dla oka
Obsługa odChrome 111, Safari 16.2, Firefox 113Chrome 119, Safari 18, Firefox 128Każda przeglądarka, wynik jest statyczny

Dlaczego Sass darken() daje nierówne kroki

darken($color, 10%) odejmuje 10 punktów jasności HSL. Jasność HSL to nie postrzegana jasność, więc widoczna zmiana zależy od barwy. Oto darken(10%) obok oklch(from … calc(l - 0.1) c h) na czterech popularnych kolorach interfejsu, zmierzone przez ΔE OK, gdzie około 0,02 to najmniejsza różnica, jaką da się zobaczyć.

KolorSass darken(10%)ΔE OKOKLCH l − 0.1ΔE OK
#2563eb#134cca0.078#0442c80.099
#facc15#d7ad050.099#d9ab000.101
#16a34a#1076360.136#00842b0.094
#dc2626#b21d1d0.090#b700000.089

To samo darken(10%) zmienia zieleń 1,7 raza mocniej niż niebieski. Wersja OKLCH mieści się między 0,089 a 0,101 dla każdej barwy; niewielki rozrzut bierze się z mapowania gamutu, bo niektóre ciemniejsze kolory wypadają tuż poza sRGB. Sam Sass zaleca color.adjust() lub color.scale() zamiast darken(), a w czystym CSS nie potrzebujesz żadnej z nich.

Obsługa w przeglądarkach i fallbacki

color-mix() działa w Chrome i Edge 111, Safari 16.2 oraz Firefox 113, wydanych w 2023 roku. Składnia kolorów względnych pojawiła się w Chrome i Edge 119 oraz Firefox 128; Safari wprowadziło wczesną wersję w 16.4, a obecną składnię w Safari 18. Wszystkie aktualne przeglądarki obsługują obie.

Popularny trik ze zwykłą wartością w linii powyżej nie działa, gdy nowa wartość zawiera var(). Deklaracja z var() jest zawsze akceptowana na etapie parsowania, więc przeglądarka odrzuca twoją linię zapasową, a jeśli nie potrafi policzyć color-mix(), wraca do wartości dziedziczonej lub początkowej. Zamiast tego opakuj nowoczesną wersję w @supports.

CSS

.button:hover {
    background: #1f55cc;
}

@supports (color: color-mix(in oklab, red, blue)) {
    .button:hover {
        background: color-mix(in oklab, var(--brand) 90%, black);
    }
}

@supports (color: oklch(from red l c h)) {
    .badge {
        border-color: oklch(from var(--brand) l c h / 0.3);
    }
}

Pytania i odpowiedzi

Co robi color-mix() w CSS?

color-mix() miesza dwa kolory w podanej przestrzeni barw i zwraca wynik, na przykład color-mix(in oklab, var(--brand) 90%, black) daje kolor o 10% ciemniejszy od koloru marki. Działa w przeglądarce, więc współpracuje ze zmiennymi CSS i currentColor.

Jakiej przestrzeni barw używać w color-mix()?

Do rozjaśnień, przyciemnień i stanów hover używaj oklab, bo daje równe kroki jasności i zachowuje barwę. Oklch wybierz przy mieszaniu dwóch nasyconych kolorów, gdy chcesz nasyconego wyniku, a srgb przy mieszaniu z transparent. Niebieski i żółty zmieszane w srgb dają płaską szarość #808080, a w oklch intensywny morski turkus.

Jak przyciemnić kolor na hover w czystym CSS?

Użyj background: color-mix(in oklab, var(--brand) 90%, black) albo background: oklch(from var(--brand) calc(l - 0.1) c h). Dla #2563eb pierwszy daje #1f55cc, a drugi #0442c8, podnosząc kontrast białego tekstu z 5,17:1 do 6,50:1 i 8,02:1.

Jak zrobić przezroczysty kolor ze zmiennej CSS?

Napisz color-mix(in srgb, var(--brand) 20%, transparent) albo oklch(from var(--brand) l c h / 0.2). Oba działają, gdy --brand jest zapisany jako hex, i nie zmieniają samego koloru, obniżają tylko jego krycie.

Czy color-mix() działa we wszystkich przeglądarkach?

Tak, obsługują go wszystkie aktualne przeglądarki: Chrome i Edge od wersji 111, Safari od 16.2 i Firefox od 113. Dla starszych przeglądarek wpisz najpierw statyczny kolor, a wersję z color-mix() umieść w @supports, bo linia z var() nie potrafi sama wrócić do wartości zapasowej.

Czym różni się color-mix() od składni kolorów względnych?

color-mix() miesza dwa kolory w podanych proporcjach, co pasuje do rozjaśnień, przyciemnień i przezroczystości. Składnia kolorów względnych, jak oklch(from var(--brand) l c calc(h + 30)), przepisuje poszczególne kanały jednego koloru, co pasuje do dokładnych kroków jasności, przesunięć barwy i alfy.

Wypróbuj w PickShade

Powiązane poradniki