CSS color-mix() a relativní barvy: světlejší varianty, hover a průhlednost
color-mix() smíchá dvě barvy v barevném prostoru, který si zvolíte, a syntaxe relativních barev vám dovolí upravit jeden kanál existující barvy, například oklch(from var(--brand) calc(l - 0.1) c h). Obojí běží v prohlížeči, funguje s proměnnými CSS a nahradí většinu barevných funkcí Sass. Světlejší varianty a hover míchejte v oklab, průhlednost v srgb.
Čtení na 6 min
Jak funguje color-mix()
color-mix() přijme barevný prostor a dvě barvy s nepovinnými procenty a vrátí barvu mezi nimi. color-mix(in oklab, var(--brand) 90%, black) znamená 90 % firemní barvy a 10 % černé, smíchané v Oklab. Když zadáte jedno procento, druhá barva dostane zbytek. Když nezadáte žádné, každá dostane 50 %.
Prohlížeč počítá výsledek za běhu, takže to funguje s vlastními vlastnostmi, currentColor i přepínáním motivů. Funkce Sass proběhnou jednou při sestavení a hodnoty var() nevidí.
Pokud obě procenta dají dohromady méně než 100 %, výsledek bude navíc částečně průhledný: color-mix(in srgb, red 30%, blue 30%) je rovnoměrná směs s krytím 60 %. Pokud to nechcete, držte součet na 100 %.
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);
}V jakém barevném prostoru míchat: srgb, oklab, nebo oklch
Prostor mění výsledek víc, než by většina lidí čekala. Níže je čistá modrá #0000ff smíchaná půl na půl s čistou žlutou #ffff00, spočítaná stejnou matematikou, jakou používá prohlížeč.
V srgb se kanály zprůměrují přesně na 128, 128, 128: směs je #808080, šedá s nulovou chroma. Oklab také míchá po přímce a modrá se žlutou leží na jejích opačných stranách, takže se většinou vyruší do matné šedomodré. Oklch místo toho interpoluje úhel tónu a jde kratší cestou z 264° na 110°, takže uprostřed je sytá modrozelená s tónem 187°, která si drží chroma obou vstupů.
- Modrá #0000ff#0000ff
- Žlutá #ffff00#ffff00
- v srgb: #808080#808080
- v oklab: #6cabc7#6cabc7
- v oklch: #00bdb0#00bdb0
| Prostor | Modrá + žlutá | OKLCH L, C | Blue-600 + yellow-400 | OKLCH L, C |
|---|---|---|---|---|
| srgb | #808080 | 0.600, 0 | #909880 | 0.665, 0.035 |
| oklab | #6cabc7 | 0.710, 0.077 | #90a3ad | 0.703, 0.026 |
| oklch | #00bdb0 | 0.710, 0.262 | #00bd9e | 0.703, 0.194 |
Druhá dvojice jsou barvy #2563eb a #facc15 z Tailwindu. Výsledky v oklch leží mimo sRGB, proto je chroma uvedena před mapováním do gamutu a HEX je nejbližší barva, kterou obrazovka sRGB umí zobrazit.
Dvě věci stojí za pozornost. Srgb skončí na světlosti 0,600, zatímco vnímaný střed mezi modrou (0,452) a žlutou (0,968) je 0,710: to je ten tmavý, kalný střed gradientů v srgb. A jen oklch udrží směs sytou, za cenu průchodu tónem, který nemá ani jeden vstup.
Orientační pravidlo: světlejší a tmavší varianty a stavy hover míchejte v oklab, kde zůstáváte u jednoho tónu a chcete rovnoměrné kroky světlosti. V oklch míchejte, když jsou obě barvy syté a chcete sytý výsledek. V srgb míchejte průhlednost, protože odpovídá tomu, jak prohlížeč skládá vrstvy.
Recepty: hover, světlá pozadí a průhledné varianty
Všechny hodnoty níže používají #2563eb jako --brand. Bílý text na ní má kontrastní poměr 5,17:1.
Přimíchání 10 % černé ztmaví v oklab víc než v srgb: bílý text stoupne na 6,50:1 proti 6,11:1. Oklab a oklch dávají stejný výsledek, když je druhou barvou černá nebo bílá, protože ty nemají tón, který by se interpoloval.
| Recept | CSS | Výsledek | Kontrast |
|---|---|---|---|
| Hover, o 10 % tmavší | color-mix(in oklab, var(--brand) 90%, black) | #1f55cc | 6.50:1 s bílým textem |
| Active, o 20 % tmavší | color-mix(in oklab, var(--brand) 80%, black) | #1947ae | 8.22:1 s bílým textem |
| Hover míchaný v srgb | color-mix(in srgb, var(--brand) 90%, black) | #2159d3 | 6.11:1 s bílým textem |
| Světlé pozadí, 10 % | color-mix(in oklab, var(--brand) 10%, white) | #e8f0ff | 4.51:1 s firemním textem |
| Světlé pozadí, 20 % | color-mix(in oklab, var(--brand) 20%, white) | #d2e2ff | 3.95:1 s firemním textem |
| Průhledná, 20 % | color-mix(in srgb, var(--brand) 20%, transparent) | rgba(37, 99, 235, 0.2) | Na bílé vypadá jako #d3e0fb |
Pozor na světlá pozadí. Text ve firemní barvě má na bílé 5,17:1, na 10% pozadí 4,51:1 a na 20% pozadí jen 3,95:1, což u běžného textu neprojde WCAG AA. Když dáváte text ve firemní barvě na její světlé pozadí, použijte pro text tmavší barvu ze stavu hover.
Míchání s transparent zachová barvu a sníží jen alfa kanál, protože prohlížeč míchá hodnoty s předem vynásobenou alfou. Výsledek se přizpůsobí tomu, co je pod ním: stejné pravidlo vypadá na bílé jako #d3e0fb a na tmavém povrchu #0f172a jako #132651. Světlé pozadí smíchané s bílou zůstane na tmavé stránce bledý, takže pro komponenty, které se objevují v obou motivech, je průhledná varianta obvykle lepší volba.
Syntaxe relativních barev: úprava jednoho kanálu
Syntaxe relativních barev vezme existující barvu, rozloží ji na kanály a dovolí vám kterýkoli z nich přepsat pomocí calc(). V oklch(from var(--brand) l c h) obsahují klíčová slova l, c a h světlost (0 až 1), chroma a tón barvy --brand.
Na rozdíl od color-mix() mění přesně jednu vlastnost: sníží světlost, aniž by sáhla na chroma, otočí tón beze změny světlosti nebo přidá alfa kanál barvě uložené jako HEX.
| Recept | CSS | Výsledek z #2563eb | Bílý text |
|---|---|---|---|
| Tmavší | oklch(from var(--brand) calc(l - 0.1) c h) | #0442c8 | 8.02:1 |
| Světlejší | oklch(from var(--brand) calc(l + 0.1) c h) | #4484ff | 3.51:1 |
| Poloviční chroma | oklch(from var(--brand) l calc(c * 0.5) h) | #4e6faf | 4.98:1 |
| Tón +30° | oklch(from var(--brand) l c calc(h + 30)) | #7a49df | 5.46:1 |
| Komplementární | oklch(from var(--brand) l c calc(h + 180)) | #956700 | 4.98:1 |
| Šedá se stejnou světlostí | oklch(from var(--brand) l 0 h) | #707070 | 4.95:1 |
| Alfa 50 % | oklch(from var(--brand) l c h / 0.5) | rgba(37, 99, 235, 0.5) | Záleží na pozadí |
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));
}Podívejte se na čtyři řádky, které ponechávají l: změna chroma nebo tónu posune kontrast bílého textu jen mezi 4,95:1 a 5,46:1, proti 5,17:1 u původní barvy. Kontrast určuje světlost, takže varianty tónu vytvořené tímto způsobem mají zhruba stejnou přístupnost. Světlejší a komplementární barva leží při plné chroma mimo sRGB a prohlížeč je namapuje na nejbližší barvu, kterou umí zobrazit.
color-mix(), relativní barvy, nebo Sass darken()
color-mix() použijte, když uvažujete ve smyslu „trochu černé“ nebo „trochu průhlednosti“. Syntaxi relativních barev použijte, když uvažujete v kanálech: „stejná barva, o 0,1 tmavší“. Obojí nahradí většinu barevných funkcí Sass a přizpůsobí se změně motivu bez nového sestavení.
| color-mix() | Syntaxe relativních barev | Sass darken() | |
|---|---|---|---|
| Kde běží | V prohlížeči | V prohlížeči | Při sestavení |
| Funguje s var() a currentColor | Ano | Ano | Ne |
| Barevný model | Prostor, který zadáte: srgb, oklab, oklch, hsl a další | Jakákoli barevná funkce: oklch(), rgb(), hsl(), lab() | Jen HSL |
| Nejlepší na | Světlejší a tmavší varianty, průhlednost, míchání dvou tokenů | Změnu jednoho kanálu: světlosti, chroma, tónu nebo alfy | Starý kód s pevnými barvami |
| Velikost kroku | Podíl vzdálenosti k druhé barvě | Přesná, v jednotkách kanálu | Pevné body HSL, pro oko nerovnoměrné |
| Podpora od | Chrome 111, Safari 16.2, Firefox 113 | Chrome 119, Safari 18, Firefox 128 | Jakýkoli prohlížeč, výstup je statický |
Proč Sass darken() dává nerovnoměrné kroky
darken($color, 10%) odečte 10 bodů světlosti v HSL. Světlost v HSL není vnímaná světlost, takže viditelná změna závisí na tónu. Tady je darken(10%) vedle oklch(from … calc(l - 0.1) c h) na čtyřech běžných barvách rozhraní, měřeno v ΔE OK, kde zhruba 0,02 je nejmenší rozdíl, který postřehnete.
| Barva | Sass darken(10%) | ΔE OK | OKLCH l − 0.1 | ΔE OK |
|---|---|---|---|---|
| #2563eb | #134cca | 0.078 | #0442c8 | 0.099 |
| #facc15 | #d7ad05 | 0.099 | #d9ab00 | 0.101 |
| #16a34a | #107636 | 0.136 | #00842b | 0.094 |
| #dc2626 | #b21d1d | 0.090 | #b70000 | 0.089 |
Stejné darken(10%) změní zelenou 1,7krát víc než modrou. Verze v OKLCH zůstává u každého tónu mezi 0,089 a 0,101, malý rozptyl způsobuje mapování do gamutu, protože některé tmavší barvy vypadnou těsně mimo sRGB. Samotný Sass doporučuje místo darken() color.adjust() nebo color.scale() a v čistém CSS nepotřebujete ani jedno.
Podpora v prohlížečích a záložní řešení
color-mix() funguje v Chrome a Edge 111, Safari 16.2 a Firefoxu 113, všechny vyšly v roce 2023. Syntaxe relativních barev přišla v Chrome a Edge 119 a Firefoxu 128, Safari dodalo ranou verzi v 16.4 a současnou syntaxi v Safari 18. Všechny aktuální prohlížeče podporují obojí.
Obvyklý trik s prostou hodnotou na řádku předtím nefunguje, když nová hodnota obsahuje var(). Deklarace s var() se při parsování přijme vždy, takže prohlížeč váš záložní řádek zahodí, a pokud color-mix() spočítat neumí, použije zděděnou nebo výchozí hodnotu. Moderní verzi proto zabalte do @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);
}
}Otázky a odpovědi
Co dělá color-mix() v CSS?
color-mix() smíchá dvě barvy v barevném prostoru, který zadáte, a vrátí výsledek, například color-mix(in oklab, var(--brand) 90%, black) pro barvu o 10 % tmavší než firemní. Běží v prohlížeči, takže funguje s proměnnými CSS i currentColor.
Jaký barevný prostor použít v color-mix()?
Pro světlejší a tmavší varianty a stavy hover použijte oklab, protože dává rovnoměrné kroky světlosti a drží tón. Oklch použijte při míchání dvou sytých barev, když chcete sytý výsledek, a srgb při míchání s transparent. Modrá a žlutá smíchané v srgb dají plochou šedou #808080, v oklch sytou modrozelenou.
Jak v čistém CSS ztmavit barvu při hover?
Použijte background: color-mix(in oklab, var(--brand) 90%, black) nebo background: oklch(from var(--brand) calc(l - 0.1) c h). Pro #2563eb dá první #1f55cc a druhé #0442c8, čímž se kontrast bílého textu zvýší z 5,17:1 na 6,50:1 a 8,02:1.
Jak udělat barvu z proměnné CSS průhlednou?
Napište color-mix(in srgb, var(--brand) 20%, transparent) nebo oklch(from var(--brand) l c h / 0.2). Obojí funguje, i když je --brand uložená jako HEX, a samotnou barvu nemění, snižuje jen její krytí.
Podporují color-mix() všechny prohlížeče?
Ano, podporují ho všechny aktuální prohlížeče: Chrome a Edge od verze 111, Safari od 16.2 a Firefox od 113. Pro starší prohlížeče dejte nejdřív statickou barvu a verzi s color-mix() do @supports, protože řádek s var() se sám na záložní hodnotu vrátit neumí.
Jaký je rozdíl mezi color-mix() a syntaxí relativních barev?
color-mix() míchá dvě barvy v daném poměru, což se hodí na světlejší a tmavší varianty a průhlednost. Syntaxe relativních barev, například oklch(from var(--brand) l c calc(h + 30)), přepisuje jednotlivé kanály jedné barvy, což se hodí na přesné kroky světlosti, posuny tónu a alfa kanál.