CSS relatieve kleursyntaxis

Creëer nieuwe kleuren op basis van de kanalen en waarden van een andere kleur.

Adam Argyle
Adam Argyle

In Chrome 119 zit een zeer krachtige kleurfunctie van CSS Color Level 5 . De relatieve kleursyntaxis creëert een vloeiend pad voor kleurmanipulatie binnen CSS, waardoor auteurs en ontwerpers manieren krijgen om:

Voordat u de relatieve kleursyntaxis gebruikt, moet u, om de dekking van een kleur te wijzigen, aangepaste eigenschappen maken voor de kanalen van een kleur, meestal HSL, en deze samenvoegen tot een uiteindelijke kleur en een uiteindelijke variantkleur. Dit betekent dat u veel kleurstukken moet beheren, wat snel lastig kan worden.

:root {
  --brand-hue: 300deg;
  --brand-saturation: 75%;
  --brand-lightness: 50%;

  --brand-hsl:
    var(--brand-hue)
    var(--brand-saturation)
    var(--brand-lightness);

  --brand-color: hsl(var(--brand-hsl));

  /* all this work just so I can set the opacity to 50% in a variant */
  --brand-color-variant: hsl(var(--brand-hsl) / 50%);
}

Na de relatieve kleursyntaxis kunt u een merkkleur maken met elke gewenste kleurruimte of syntaxis, en een variant met halve dekking maken met veel minder code. Het is ook veel gemakkelijker om de bedoeling van de stijlen en het systeem te lezen.

:root {
  --brand-color: hsl(300deg 75% 50%);
  --brand-color-variant: hsl(from var(--brand-color) h s l / 50%);
}

Dit bericht zal je helpen de syntaxis te leren en algemene kleurmanipulaties te demonstreren .

Als je de voorkeur geeft aan video, wordt bijna het hele volgende artikel behandeld in deze GUI-uitdaging.

Syntaxisoverzicht

Het doel van de syntaxis van relatieve kleuren is om het mogelijk te maken een kleur uit een andere kleur af te leiden. De basiskleur wordt de oorspronkelijke kleur genoemd, dit is de kleur die na het nieuwe from komt. De browser zal deze oorspronkelijke kleur converteren en opsplitsen en de delen aanbieden als variabelen voor gebruik in de nieuwe kleurdefinitie.

Er wordt een diagram van de syntaxis rgb (van groen r g b / alpha) getoond, met een pijl die de bovenkant van groen verlaat en overgaat in het rgb-begin van de functie. Deze pijl splitst zich in 4 pijlen die vervolgens naar hun relevante variabele wijzen. De 4 pijlen zijn rood, groen, blauw en alpha. Rood en blauw hebben een waarde van 0, groen is 128 en alfa is 100%.

Het voorgaande diagram laat zien dat de oorspronkelijke kleur green wordt geconverteerd naar de kleurruimte van de nieuwe kleur, omgezet in individuele getallen die worden weergegeven als r , g , b en alpha variabelen, die vervolgens rechtstreeks worden gebruikt als de waarden van een nieuwe rgb() kleur.

Hoewel deze afbeelding de uitsplitsing, het proces en de variabelen toont, verandert de kleur ook niet. De variabelen worden ongewijzigd terug in de kleur gezet, waardoor er nog steeds een groene kleur ontstaat.

Het from -trefwoord

Het eerste deel van de syntaxis dat u moet leren, is het deel from <color> toevoeging tot het opgeven van een kleur. Dit gebeurt vlak voordat u de waarden opgeeft. Hier is een codevoorbeeld waarin alles wat is toegevoegd afkomstig is from green , vlak voordat de waarden voor rgb() worden opgegeven.

.syntax-introduction_same-colors {
  color: green;
  color: rgb(0 128 0);
  color: rgb(from green r g b);    /* result = rgb(0 128 0) */
}

Dat from trefwoord, gezien als de eerste parameter in functionele notatie, verandert de kleurdefinitie in een relatieve kleur! Na het zoekwoord from verwacht CSS een kleur, een kleur die de volgende kleur zal inspireren .

Kleurconversie

In eenvoudiger bewoordingen converteert het groen naar rg- en b-kanalen voor gebruik in een nieuwe kleur.

rgb(from green r g b)           /* r=0 g=128 b=0 */
rgb(from rgb(0 128 0) r g b);   /* r=0 g=128 b=0 */

Kleuren van aangepaste eigenschappen

Het lezen rgb from green is heel duidelijk en gemakkelijk te begrijpen. Dit is de reden waarom aangepaste eigenschappen en relatieve kleursyntaxis zo goed bij elkaar passen, omdat je het mysterie uit de from kleur kunt halen. Over het algemeen hoeft u ook niet het kleurformaat van de aangepaste eigenschap kleur te kennen, omdat u een nieuwe kleur maakt in een formaat naar keuze.

rgb(from rgb(255 105 180) r g b) /* ????? */
rgb(from var(--hotpink) r g b)   /* clear */

Werk in de kleurruimte van uw voorkeur

U kunt de kleurruimte kiezen met uw keuze voor functionele kleurnotatie.

rgb(from hsl(120 100% 25%) r g b)     /*  r=0   g=128  b=0    */
hsl(from hsl(120 100% 25%) h s l)     /*  h=120 s=100% l=25%  */
hwb(from hsl(120 100% 25%) h w b)     /*  h=120 w=0%   b=50%  */
lch(from hsl(120 100% 25%) l c h)     /*  l=46  c=68   h=134  */

De relatieve kleursyntaxis heeft die conversiestap; de kleur na from wordt omgezet naar de kleurruimte zoals opgegeven aan het begin van de relatieve kleur. De input en output hoeven niet bij elkaar te passen, wat erg bevrijdend is.

De mogelijkheid om een ​​kleurruimte te kiezen geeft ook kracht, omdat het kiezen van een kleurruimte doorgaans meer gericht is op het type kleurafwisseling dan op een voorkeur. De voorkeur ligt in de resultaten, niet in het kleurformaat of de kanaaltypen. Dit zal veel duidelijker worden in de secties waarin gebruiksscenario's worden gedemonstreerd, omdat verschillende kleurruimten uitblinken in verschillende taken.

Mix, match, laat de variabelen weg en herhaal ze

Er is iets vreemds maar opwindends aan deze syntaxis: de variabelen hoeven niet opnieuw in de juiste volgorde te worden geplaatst en kunnen worden herhaald.

rgb(from green g g g)    /* rgb(128 128 128) */
rgb(from green b r g)    /* rgb(0 0 128) */
rgb(from green 0 0 g)    /* rgb(0 0 128) */

Dekking als variabele

De syntaxis biedt ook de dekking als een variabele met de naam alpha . Het is optioneel en komt na de / in de functionele kleurnotatie.

rgb(from #00800080 r g b / alpha)             /* alpha=50% */
rgb(from rgba(0,128,0,.5) r g b / alpha)      /* alpha=50% */
rgb(from rgb(0 128 0 / 50%) r g b / alpha)    /* alpha=50% */

Gebruik calc() of andere CSS-functies voor de variabelen

Tot nu toe hebben we de kleur groen keer op keer gecreëerd. Het leren van de syntaxis, vertrouwd raken met de conversie- en destructureringsstappen. Nu is het tijd om de variabelen te wijzigen, de uitvoer te wijzigen zodat deze niet hetzelfde is als de invoer.

green                              /*  h=120 s=100% l=25%  */
hsl(from green calc(h * 2) s l)    /*  h=240 s=100% l=25%  */

Het is nu marineblauw! De tint werd verdubbeld, waarbij een tint van 120 werd genomen en deze in 240 werd veranderd, waardoor de kleur volledig veranderde. Hierdoor werd de tint langs het kleurenwiel gedraaid, een handige truc die heel eenvoudig werd gemaakt met cilindrische kleurruimten zoals HSL , HWB , LCH en OKLCH .

Om de waarden van kanalen visueel te zien, zodat u de wiskunde precies goed kunt krijgen zonder te raden of de specificaties te moeten onthouden, kunt u dit hulpmiddel voor relatieve kleursyntaxis van kanaalwaarden proberen. Het onthult de waarde van elk kanaal op basis van de syntaxis die u opgeeft, zodat u precies weet met welke waarden u kunt spelen.

Controleer op browserondersteuning

@supports (color: rgb(from white r g b)) {
  /* safe to use relative color syntax */
}

Gebruiksscenario's en demonstraties

De volgende voorbeelden en gebruiksscenario's hebben veel alternatieve syntaxis om vergelijkbare of dezelfde resultaten te bereiken. De variaties komen voort uit de kleurruimten en de kanalen die ze aanbieden.

Ook zullen veel voorbeelden kleuraanpassingen laten zien met de woordenstroom van by en to . Een kleur die verandert by is een relatieve kleurverandering; een wijziging die de waarde van de variabele gebruikt en een aanpassing maakt op basis van de huidige waarde. Een kleurverandering to een absolute kleurverandering; een wijziging die niet de waarde van de variabele gebruikt en in plaats daarvan een geheel nieuwe waarde specificeert.

Alle demo's zijn te vinden in deze Codepen collectie .

Maak een kleur lichter

De OKLCH-, OKLAB- , XYZ- of sRGB- kleurruimten bieden de meest voorspelbare resultaten bij het lichter maken van kleuren.

Verlicht een hoeveelheid

Het volgende voorbeeld .lighten-by-25 neemt de kleur blue en converteert deze naar OKLCH, waarna het blauw lichter wordt door het l kanaal (lichtheid) te vergroten door de huidige waarde met 1.25 te vermenigvuldigen. Dit duwt de blauwe lichtheid met 25% richting wit.

.lighten-by-25 {
  background: oklch(from blue calc(l * 1.25) c h);
}

Verlicht tot een specifieke waarde

Het volgende voorbeeld .lighten-to-75 gebruikt het l kanaal niet om blue lichter te maken, maar vervangt in plaats daarvan de waarde volledig door 75% .

.lighten-to-75 {
  background: oklch(from blue 75% c h);
}

Maak een kleur donkerder

Dezelfde kleurruimten die effectief zijn bij het lichter maken van een kleur, zijn ook uitstekend geschikt voor het donkerder maken van kleuren.

Verdonker met een hoeveelheid

Het volgende voorbeeld .darken-by-25 neemt de kleur blauw en converteert deze naar OKLCH, waarna het blauw donkerder wordt door het l kanaal (lichtheid) met 25% te verlagen door de waarde te vermenigvuldigen met .75 . Dit duwt de blauwe kleur met 25% richting zwart.

.darken-by-25 {
  background: oklch(from blue calc(l * .75) c h);
}

Donkerder maken tot een opgegeven waarde

Het volgende voorbeeld .darken-to-25 maakt geen gebruik van het l kanaal om blue te verdonkeren, maar vervangt in plaats daarvan de waarde volledig door 25% .

.darken-to-25 {
  background: oklch(from blue 25% c h);
}

Verzadig een kleur

Verzadig met een hoeveelheid

Het volgende voorbeeld .saturate-by-50 gebruikt de s van hsl() om de levendigheid van orchid met relatief 50% te vergroten.

.saturate-by-50 {
  background: hsl(from orchid h calc(s * 1.5) l);
}

Verzadig tot een bepaalde hoeveelheid

Het volgende voorbeeld .saturate-to-100 maakt geen gebruik van het s kanaal van hsl() , maar specificeert in plaats daarvan een gewenste verzadigingswaarde. In dit voorbeeld wordt de verzadiging verhoogd naar 100% .

.saturate-to-100 {
  background: hsl(from orchid h 100% l);
}

Desatureer een kleur

Desatureer met een hoeveelheid

Het volgende voorbeeld .desaturate-by-half gebruikt de s van hsl() om de verzadiging van indigo met de helft te verminderen.

.desaturate-by-half {
  background: hsl(from indigo h calc(s / 2) l);
}

Desatureer tot een specifieke waarde

In plaats van de verzadiging met een bepaald bedrag te desatureren, kunt u ook desatureren tot een specifieke gewenste waarde. In het volgende voorbeeld .desaturate-to-25 wordt een nieuwe kleur gemaakt op basis van indigo , maar wordt de verzadiging ingesteld op 25%.

.desaturate-to-25 {
  background: hsl(from indigo h 25% l);
}

Chroma versterkt een kleur

Dit effect is vergelijkbaar met het verzadigen van een kleur, maar is op een aantal manieren anders. Ten eerste is het een chroma en geen saturation , en dit komt omdat de kleurruimten die een hoog dynamisch bereik kunnen bereiken geen verzadiging gebruiken. De kleurruimten met chroma hebben een hoog dynamisch bereik, waardoor auteurs de kleurlevendigheid verder kunnen versterken dan verzadiging zelfs maar kan.

.increase-chroma {
  background: oklch(from orange l calc(c + .1) h);
}

Pas de dekking van een kleur aan

Het maken van een semi-transparante variant van een kleur is een van de meest voorkomende kleuraanpassingen in ontwerpsystemen. Zie het voorbeeld in de inleiding van dit artikel als je het gemist hebt; het schetst de probleemruimte heel goed.

Pas de dekking met een bedrag aan

.decrease-opacity-by-25 {
  background: rgb(from lime r g b / calc(alpha / 2));
}

Pas de dekking aan tot een specifieke waarde

.decrease-opacity-to-25 {
  background: rgb(from lime r g b / 25%);
}

Een kleur omkeren

Kleurinversie is een veelgebruikte kleuraanpassingsfunctie in kleurenbibliotheken. Eén manier om dit te bereiken is door een kleur naar RGB te converteren en vervolgens de waarde van elk kanaal van 1 af te trekken.

.invert-each-rgb-channel {
  background: rgb(from yellow calc(255 - r) calc(255 - g) calc(255 - b));
}

Vul een kleur aan

Als het niet uw doel was om een ​​kleur om te keren, maar deze eerder aan te vullen, dan is tintrotatie waarschijnlijk wat u zoekt. Kies een kleurruimte die de tint als een hoek biedt, en gebruik vervolgens calc() om de tint met de gewenste hoeveelheid te roteren. Het vinden van het complement van een kleur doe je door een halve slag te draaien. In dit geval kun je het h kanaal 180 graden optellen of aftrekken om het resultaat te bereiken.

.complementary-color {
  background: hsl(from blue calc(h + 180) s l);
}

Contrasteer een kleur

Als methode om toegankelijke kleurcontrastverhoudingen te bereiken, kunt u L* (Lstar) overwegen. Dit maakt gebruik van het (ongeveer) perceptueel uniforme lichtheidskanaal (L) van LCH en OKLCH, in een calc() . Afhankelijk of u laag, gemiddeld of hoog contrast target, ligt de L*-delta rond ~40, ~50 of ~60.

Deze techniek werkt goed bij elke tint in LCH of OKLCH.

Contrasteer een donkerdere kleur

De klasse .well-contrasting-darker-color demonstreert L* met een delta van 60. Omdat de oorspronkelijke kleur een donkere kleur is (lichtheid met lage waarde), wordt 60% (0,6) toegevoegd aan het lichtheidskanaal. Deze techniek wordt gebruikt om een ​​goed contrasterende, dezelfde tint, donkere tekstkleur op een lichte achtergrond te vinden.

.well-contrasting-darker-color {
  background: darkred;
  color: oklch(from darkred calc(l + .60) c h);
}

Contrasteer een lichtere kleur

De klasse .well-contrasting-lighter-color demonstreert L* ook met een delta van 60%. Omdat de oorspronkelijke kleur een lichte kleur is (lichtheid met hoge waarde), wordt .60 afgetrokken van het lichtheidskanaal.

.well-contrasting-lighter-color {
  background: lightpink;
  color: oklch(from lightpink calc(l - .60) c h);
}

Kleurenpaletten

De relatieve kleursyntaxis is erg goed in het maken van kleurenpaletten. Het is vooral nuttig en krachtig vanwege het aantal beschikbare kleurruimten. De volgende voorbeelden gebruiken allemaal OKLCH omdat het lichtheidskanaal betrouwbaar is en het tintkanaal zonder bijwerkingen kan worden geroteerd. Het laatste voorbeeld demonstreert een combinatie van aanpassingen van helderheid en tintrotatie voor een interessanter resultaat!

Open hiervoor de voorbeeldbroncode en probeer de --base-color te wijzigen om te zien hoe dynamisch deze paletten zijn. Het is leuk!

Als je van video houdt, geef ik diepgaande informatie over het bouwen van kleurenpaletten in CSS met OKLCH op YouTube .

Monochromatische paletten

Als u een monochromatisch palet maakt, betekent dit dat u een palet maakt met allemaal dezelfde tint, maar met variaties in licht en donker. De middelste kleur is de bronkleur voor het palet, waarbij aan weerszijden twee lichtere en twee donkerdere varianten zijn geplaatst.

:root {
  --base-color: deeppink;

  --color-0: oklch(from var(--base-color) calc(l + .20) c h); /* lightest */
  --color-1: oklch(from var(--base-color) calc(l + .10) c h);
  --color-2: var(--base-color);
  --color-3: oklch(from var(--base-color) calc(l - .10) c h);
  --color-4: oklch(from var(--base-color) calc(l - .20) c h); /* darkest */
}
Probeer een aantal paletten uit die zijn gemaakt met relatieve kleursyntaxis en OKLCH

Open Props , een bibliotheek met gratis CSS-variabelen, biedt kleurenpaletten die met deze strategie zijn gebouwd en maakt ze gemakkelijk bruikbaar met een import. Ze zijn ook allemaal opgebouwd uit een kleur die je kunt aanpassen, je geeft er gewoon een kleur aan en er komt een palet uit!

Analoge paletten

Omdat tintrotatie zo eenvoudig is met OKLCH en HSL, is het triviaal om een ​​analoog kleurenpalet te creëren. Roteer de tint met een hoeveelheid die u bevalt en verander de basiskleur, en zie hoe nieuwe paletten door de browser worden gebouwd.

:root {
  --base-color: blue;

  --primary:   var(--base-color);
  --secondary: oklch(from var(--base-color) l c calc(h - 45));
  --tertiary:  oklch(from var(--base-color) l c calc(h + 45));
}

Triadische paletten

Net als complementaire kleuren zijn triadische kleurenpaletten tegengestelde maar harmonieuze tintrotaties gegeven een basiskleur. Waar een complementaire kleur zich aan de tegenovergestelde kant van een kleur bevindt, zoals een rechte lijn die door het midden van het kleurenwiel wordt getrokken, zijn triadische paletten als een driehoek van lijnen, waarbij twee kleuren gelijkmatig worden geroteerd ten opzichte van een basiskleur. U kunt dit bereiken door de tint 120deg te draaien.

Dit is een kleine vereenvoudiging van de kleurentheorie, maar het is voldoende om je kennis te laten maken met de meer complexe triadische paletten als je geïnteresseerd bent.

:root {
  --base-color: yellow;
  --triad-1: oklch(from var(--base-color) l c calc(h - 120));
  --triad-2: oklch(from var(--base-color) l c calc(h + 120));
}

Tetradische paletten

Tetradische paletten zijn vier kleuren die gelijkmatig verdeeld zijn over het kleurenwiel, waardoor een palet ontstaat zonder duidelijke dominante waarde. Je zou het ook kunnen zien als twee paar complementaire kleuren. Wanneer het verstandig wordt gebruikt, kan het zeer betekenisvol zijn.

Dit is een kleine vereenvoudiging van de kleurentheorie, maar het is voldoende om je kennis te laten maken met de meer complexe tetradische paletten als je geïnteresseerd bent.

:root {
  --base-color: lime;

  --color-1: var(--base-color);
  --color-2: oklch(from var(--base-color) l c calc(h + 90));
  --color-3: oklch(from var(--base-color) l c calc(h + 180));
  --color-4: oklch(from var(--base-color) l c calc(h + 270));
}

Monochromatisch met een lichte tintrotatie

Veel kleurexperts houden deze truc achter de hand. Het probleem is dat een monochrome kleurenschaal behoorlijk saai kan zijn. De oplossing is om aan elke nieuwe kleur een kleine of grote tintrotatie toe te voegen naarmate de lichtheid verandert.

In het volgende voorbeeld wordt de helderheid per staal met 10% verminderd en wordt de tint ook 10 graden gedraaid. Het resultaat, een felroze tot indigo-palet dat naadloos lijkt te versmelten als een verloop.

:root {
  --base-color: deeppink;

  --color-1: var(--base-color);
  --color-2: oklch(from var(--base-color) calc(l - .10) c calc(h - 10));
  --color-3: oklch(from var(--base-color) calc(l - .20) c calc(h - 20));
  --color-4: oklch(from var(--base-color) calc(l - .30) c calc(h - 30));
  --color-5: oklch(from var(--base-color) calc(l - .40) c calc(h - 40));
}
Probeer dit klassement uit, gebouwd met OKLCH en tintrotatie

De volgende scorebordinterface gebruikt deze tintrotatiestrategie. Van elk lijstitem wordt de index in het document bijgehouden als een variabele met de naam --i . Deze index wordt vervolgens gebruikt om de chroma, lichtheid en tint aan te passen. De aanpassing is slechts 5% of 5 graden, veel subtieler dan het bovenstaande voorbeeld met dieproze, en dus is er een scherp oog nodig om op te merken waarom dit klassement met zoveel elegantie in welke tint dan ook kan zijn.

Zorg ervoor dat u de tint in de schuifregelaar onder het klassement wijzigt en zie hoe de relatieve kleursyntaxis prachtige kleurmomenten creëert.

li {
  --_bg: oklch(
    /* decrease lightness as list grows */
    calc(75% - (var(--i) * 5%))

    /* decrease chroma as list grows */
    calc(.2 - (var(--i) * .01))

    /* lightly rotate the hue as the list grows */
    calc(var(--hue) - (var(--i) + 5))
  );
}