Creazione di una combinazione di colori

Una panoramica di base su come stabilire una combinazione di colori dinamica e configurabile

In questo post voglio condividere alcune riflessioni su come gestire più combinazioni di colori in CSS. Prova la demo.

Demo

Se preferisci i video, ecco una versione di questo post su YouTube:

Panoramica

Creeremo un sistema di colori accessibile con proprietà personalizzate e calc() per creare una pagina web che si adatti alle preferenze dell'utente, mantenendo al contempo un'esperienza di creazione minima. Iniziamo con un colore di base del brand e creiamo un sistema di varianti: 2 colori del testo, 4 colori della superficie e un'ombra corrispondente.

Questa guida inizia con la definizione di tutti i colori per ogni combinazione di colori. Vengono utilizzati per cambiare pagina solo alla fine.

Brand

Spesso, un colore del brand è già stato stabilito e viene fornito come esadecimale o rgb. Questa GUI Challenge ha un colore del brand di base #0af. Innanzitutto, per questo sistema di colori, il valore esadecimale deve essere convertito in hsl.

* {
  --brand: #0af;
  --brand: hsl(200 100% 50%);
}

Per attivare un concetto di scurimento o schiarimento del colore del brand, ad esempio del 20%, i tre canali del valore del colore hsl devono essere estratti nelle proprie proprietà personalizzate, in questo modo:

* {
  --brand-hue: 200;
  --brand-saturation: 100%;
  --brand-lightness: 50%;
}

CSS può eseguire operazioni matematiche su queste proprietà di colore, ad esempio calc(var(--brand-lightness) - 20%) per ridurre il valore di luminosità del 20%. Questo è fondamentale per creare una combinazione di colori, poiché CSS può mantenere tutti i colori nella stessa famiglia di tonalità regolando i valori di saturazione e luminosità hsl.

Tema chiaro

Ogni variante di colore verrà contrassegnata con lo schema corrispondente, in questo caso, a ciascuna viene aggiunto -light.

anteprima dei risultati finali del tema chiaro

Brand

A partire dal colore del brand, viene ricostruito inserendo le proprietà personalizzate --brand-hue, --brand-saturation e --brand-lightness tra le parentesi della funzione hsl (), senza calcoli:

* {
  --brand-light: hsl(var(--brand-hue) var(--brand-saturation) var(--brand-lightness));
}

Colori testo

Successivamente, gli elementi essenziali di una combinazione di colori richiedono i colori del testo. In un tema chiaro, il testo deve essere molto scuro. Nota come la luminosità dei seguenti colori sia bassa, ben al di sotto del 50%.

* {
  --text1-light: hsl(var(--brand-hue) var(--brand-saturation) 10%);
  --text2-light: hsl(var(--brand-hue) 30% 30%);
}

--text1-light, poiché è molto scuro con una luminosità del 10%, mantiene la saturazione intensa del 100% in modo che il colore del brand possa ancora emergere nel blu scuro.

--text2-light, non è scuro come il primo colore, il che è positivo in quanto è un colore secondario, ed è anche molto meno saturo.

Colori delle superfici

I colori della superficie sono gli sfondi, i bordi e altre superfici decorative su cui o all'interno delle quali si trova il testo. In un tema chiaro, questi sono i colori chiari, a differenza dei colori del testo che erano scuri. Per creare colori chiari con hsl, utilizzeremo valori percentuali più elevati nel terzo valore di luminosità. Inoltre, ridurremo la saturazione, in modo che i grigi chiari non appaiano troppo colorati.

* {
  --surface1-light: hsl(var(--brand-hue) 25% 90%);
  --surface2-light: hsl(var(--brand-hue) 20% 99%);
  --surface3-light: hsl(var(--brand-hue) 20% 92%);
  --surface4-light: hsl(var(--brand-hue) 20% 85%);
}

Sono stati creati 4 colori di superficie, poiché i colori decorativi tendono a richiedere più varianti, per momenti interattivi come :focus o :hover o per creare l'aspetto di strati di carta. In questi scenari, è utile passare da --surface2-light al passaggio del mouse a --surface3-light, in modo che il passaggio del mouse comporti un aumento del contrasto (dal 99% di luminosità al 92% di luminosità, rendendolo più scuro).

Ombre

Le ombre all'interno di una combinazione di colori sono un elemento aggiuntivo, ma conferiscono un aspetto realistico all'effetto e lo aiutano a distinguersi dalle ombre nere non realistiche. Per farlo, il colore dell'ombra utilizzerà la proprietà personalizzata della tonalità, sarà leggermente saturo con la tonalità, ma comunque molto scuro. In sostanza, crea un'ombra molto scura, leggermente blu.

* {
  --surface-shadow-light: var(--brand-hue) 10% 20%;
  --shadow-strength-light: .02;
}

--surface-shadow-light non è racchiuso in una funzione hsl. Questo perché il valore --shadow-strength verrà combinato per creare un'opacità e CSS ha bisogno delle parti per eseguire i calcoli. Vai alla sezione Rad Shadow per saperne di più.

Colori chiari tutti insieme

Non è necessario cercare come vengono realizzati i colori chiari, sono tutti in un unico posto nel CSS.

* {
  --brand-light: hsl(var(--brand-hue) var(--brand-saturation) var(--brand-lightness));
  --text1-light: hsl(var(--brand-hue) var(--brand-saturation) 10%);
  --text2-light: hsl(var(--brand-hue) 30% 30%);
  --surface1-light: hsl(var(--brand-hue) 25% 90%);
  --surface2-light: hsl(var(--brand-hue) 20% 99%);
  --surface3-light: hsl(var(--brand-hue) 20% 92%);
  --surface4-light: hsl(var(--brand-hue) 20% 85%);
  --surface-shadow-light: var(--brand-hue) 10% calc(var(--brand-lightness) / 5);
  --shadow-strength-light: .02;
}
screenshot dei colori chiari tutti insieme
Sandbox su CodePen

Tema scuro

La maggior parte dei brand non inizia con un tema scuro, ma con una variante del tema principale, di solito più chiaro. Gli utenti, invece, spesso scelgono un tema scuro per contesti diversi, ad esempio di notte. Questi fattori mi hanno portato a tenere a mente due cose sui temi scuri:

  1. In genere, gli utenti si troveranno al buio quando utilizzano questo tema, quindi esegui i test al buio.
  2. I colori devono essere desaturati per non vibrare sullo schermo a causa di un'intensità eccessiva.

anteprima del risultato finale del tema scuro

Brand

Il tema chiaro utilizza i valori dei tre canali di colore HSL del brand senza modifiche, mentre il tema scuro no. La saturazione viene dimezzata e la luminosità ridotta del 50% in termini relativi.

* {
  --brand-dark: hsl(
    var(--brand-hue)
    calc(var(--brand-saturation) / 2)
    calc(var(--brand-lightness) / 1.5)
  );
}

Colori testo

In un tema scuro, i colori del testo devono essere chiari. I seguenti colori hanno valori di luminosità elevati, il che li avvicina al bianco.

* {
  --text1-dark: hsl(var(--brand-hue) 15% 85%);
  --text2-dark: hsl(var(--brand-hue) 5% 65%);
}

Colori delle superfici

In un tema scuro, i colori delle superfici devono essere scuri. I seguenti colori hanno luminosità e saturazione basse, con la prima superficie che è la più scura al 10%.

* {
  --surface1-dark: hsl(var(--brand-hue) 10% 10%);
  --surface2-dark: hsl(var(--brand-hue) 10% 15%);
  --surface3-dark: hsl(var(--brand-hue) 5%  20%);
  --surface4-dark: hsl(var(--brand-hue) 5% 25%);
}

Ombre

In un tema scuro, le ombre possono essere molto difficili da vedere. Questo è logico, poiché è difficile scurire qualcosa che è già abbastanza scuro. È qui che --shadow-strength-dark si rivela molto utile, in quanto ci consente di scurire le ombre modificando una variabile.

* {
  --surface-shadow-dark: var(--brand-hue) 50% 3%;
  --shadow-strength-dark: .8;
}

Inoltre, guarda quanta saturazione c'è in quell'ombra. Riesci a notare il colore quando guardi l'interfaccia? Prova a rimuovere la saturazione da DevTools. Quale preferisci?

Colori scuri tutti insieme

* {
  --brand-dark: hsl(var(--brand-hue) calc(var(--brand-saturation) / 2) calc(var(--brand-lightness) / 1.5));
  --text1-dark: hsl(var(--brand-hue) 15% 85%);
  --text2-dark: hsl(var(--brand-hue) 5% 65%);
  --surface1-dark: hsl(var(--brand-hue) 10% 10%);
  --surface2-dark: hsl(var(--brand-hue) 10% 15%);
  --surface3-dark: hsl(var(--brand-hue) 5%  20%);
  --surface4-dark: hsl(var(--brand-hue) 5% 25%);
  --surface-shadow-dark: var(--brand-hue) 50% 3%;
  --shadow-strength-dark: .8;
}
screenshot dei colori scuri tutti insieme
Sandbox su CodePen

Tema scuro

Questa combinazione di colori si basa sull'orchestrazione di luminosità e saturazione. La saturazione deve essere sufficiente per rendere visibile una tonalità, ma deve anche superare di poco i punteggi di contrasto, poiché è destinata a essere comunque scura e a basso contrasto.

anteprima dei risultati finali del tema scuro

Brand

* {
  --brand-dim: hsl(
    var(--brand-hue)
    calc(var(--brand-saturation) / 1.25)
    calc(var(--brand-lightness) / 1.25)
  );
}

Colori testo

* {
  --text1-dim: hsl(var(--brand-hue) 15% 75%);
  --text2-dim: hsl(var(--brand-hue) 10% 61%);
}

Colori delle superfici

* {
  --surface1-dim: hsl(var(--brand-hue) 10% 20%);
  --surface2-dim: hsl(var(--brand-hue) 10% 25%);
  --surface3-dim: hsl(var(--brand-hue) 5%  30%);
  --surface4-dim: hsl(var(--brand-hue) 5% 35%);
}

Ombre

* {
  --surface-shadow-dim: var(--brand-hue) 30% 13%;
  --shadow-strength-dim: .2;
}

Attenua tutti i colori contemporaneamente

* {
  --brand-dim: hsl(var(--brand-hue) calc(var(--brand-saturation) / 1.25) calc(var(--brand-lightness) / 1.25));
  --text1-dim: hsl(var(--brand-hue) 15% 75%);
  --text2-dim: hsl(var(--brand-hue) 10% 61%);
  --surface1-dim: hsl(var(--brand-hue) 10% 20%);
  --surface2-dim: hsl(var(--brand-hue) 10% 25%);
  --surface3-dim: hsl(var(--brand-hue) 5%  30%);
  --surface4-dim: hsl(var(--brand-hue) 5% 35%);
  --surface-shadow-dim: var(--brand-hue) 30% 13%;
  --shadow-strength-dim: .2;
}
screenshot dei colori tenui tutti insieme
Sandbox su CodePen

Colori accessibili

Nota come la luminosità più bassa nel set di colori del testo scuro è del 65% e la luminosità più alta nelle superfici scure è del 25%. Questo significa che tra i due colori c'è un margine di luminosità del 40%. Nel tema chiaro, c'è il 55% di spazio vuoto. Mantenere le differenze di luminosità tra i colori del testo e della superficie intorno al 40-50% può aiutare a mantenere elevati i rapporti di contrasto dei colori, oltre a essere una leva sottile da regolare nel caso in cui i punteggi siano scarsi.

La chiamo "bump bump til ya pass", ovvero l'interazione di aumentare il valore di luminosità finché uno strumento non mostra che ho superato il test.

Maiusc + Freccia giù per ridurre la luminosità e aumentare il contrasto fino a superare

Ognuno dei temi creati in questa sfida supera i punteggi di contrasto. La combinazione di colori scuri ha il contrasto più basso, ma soddisfa comunque i requisiti minimi. Per aiutare gli altri membri del team a utilizzare colori con un buon contrasto, è consigliabile creare un nome di classe che accoppi un colore della superficie con un colore del testo accessibile.

.surface1 {
  background-color: var(--surface1);
  color: var(--text2);
}

.surface2 {
  background-color: var(--surface2);
  color: var(--text2);
}

.surface3 {
  background-color: var(--surface3);
  color: var(--text1);
}

.surface4 {
  background-color: var(--surface4);
  color: var(--text1);
}
Screenshot degli abbinamenti di testo e superficie scura
Screenshot degli abbinamenti di testo e superficie scura con VisBug

Rad Shadow

I temi utilizzano una classe di utilità denominata .rad-shadow. Questa ombra è stata generata con lo strumento Smooth Shadow, che apprezzo molto. Ho preso lo snippet generato e l'ho personalizzato con i miei colori e i calcoli dell'opacità. Il motivo era creare un'ombra che potessi regolare all'interno di ogni combinazione di colori.

ogni ombra accanto all'altra

Per farlo, ho creato due variabili per ogni combinazione di colori da regolare: un colore dell'ombra e un'intensità dell'ombra. Il colore serve per le regolazioni della saturazione e dell'oscurità, mentre l'intensità è un modo semplice per aumentare l'intensità dell'ombra quando si utilizza una combinazione di colori scuri. Il risultato finale è stato simile a questo.

:root {
  --surface-shadow-light: var(--brand-hue) 10% 20%;
  --shadow-strength-light: .02;
}

.rad-shadow {
  box-shadow:
    0 2.8px 2.2px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .03)),
    0 6.7px 5.3px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .01)),
    0 12.5px 10px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .02)),
    0 22.3px 17.9px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .02)),
    0 41.8px 33.4px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .03)),
    0 100px 80px hsl(var(--surface-shadow) / var(--shadow-strength))
  ;
}

Se volessi approfondire l'uso delle ombre nella mia combinazione di colori, renderei anche gli angoli delle ombre una costante dei token di progettazione, poiché la direzione della luce dovrebbe essere la stessa per tutte le ombre del design.

Utilizzo delle combinazioni di colori

Una volta completata la predefinizione dei colori, è il momento di trasformarli in proprietà indipendenti dallo schema. In altre parole, come autore CSS all'interno di questo progetto di combinazione di colori, raramente dovresti aver bisogno di accedere al valore di una combinazione di colori specifica. Voglio che sia facile rimanere in tema.

Per farlo, l'utilizzo della combinazione di colori deve avvenire esclusivamente tramite le proprietà personalizzate generiche, che definiremo tra un attimo. In questo modo, chi utilizza le variabili di progettazione non deve mai preoccuparsi della combinazione di colori attualmente impostata, ma deve solo utilizzare i colori della superficie e del testo. Invece di color: var(--text1-light), utilizza color: var(--text1). Tutti gli adattamenti e le modifiche dei colori vengono eseguiti a un livello molto più alto nel CSS.

Per iniziare, gli stili di connessione del tema chiaro nel seguente blocco di codice collegano una proprietà personalizzata generica al colore specifico del tema chiaro. Ora tutti gli utilizzi di var(--brand) utilizzeranno il colore chiaro del brand.

Tema chiaro (automatico)

:root {
  color-scheme: light;
  --brand: var(--brand-light);
  --text1: var(--text1-light);
  --text2: var(--text2-light);
  --surface1: var(--surface1-light);
  --surface2: var(--surface2-light);
  --surface3: var(--surface3-light);
  --surface4: var(--surface4-light);
  --surface-shadow: var(--surface-shadow-light);
  --shadow-strength: var(--shadow-strength-light);
}

Il sito ora utilizza il tema chiaro. Questo è un momento di successo molto divertente. Vediamo altri esempi di questo tipo utilizzando i nostri colori predefiniti in altri contesti di combinazioni di colori.

Tema scuro (automatico)

@media (prefers-color-scheme: dark) {
  :root {
    color-scheme: dark;

    --brand: var(--brand-dark);
    --text1: var(--text1-dark);
    --text2: var(--text2-dark);
    --surface1: var(--surface1-dark);
    --surface2: var(--surface2-dark);
    --surface3: var(--surface3-dark);
    --surface4: var(--surface4-dark);
    --surface-shadow: var(--surface-shadow-dark);
    --shadow-strength: var(--shadow-strength-dark);
  }
}

Tema chiaro

[color-scheme="light"] {
  color-scheme: light;

  --brand: var(--brand-light);
  --text1: var(--text1-light);
  --text2: var(--text2-light);
  --surface1: var(--surface1-light);
  --surface2: var(--surface2-light);
  --surface3: var(--surface3-light);
  --surface4: var(--surface4-light);
  --surface-shadow: var(--surface-shadow-light);
  --shadow-strength: var(--shadow-strength-light);
}

Tema scuro

[color-scheme="dark"] {
  color-scheme: dark;

  --brand: var(--brand-dark);
  --text1: var(--text1-dark);
  --text2: var(--text2-dark);
  --surface1: var(--surface1-dark);
  --surface2: var(--surface2-dark);
  --surface3: var(--surface3-dark);
  --surface4: var(--surface4-dark);
  --surface-shadow: var(--surface-shadow-dark);
  --shadow-strength: var(--shadow-strength-dark);
}

Tema scuro

[color-scheme="dim"] {
  color-scheme: dark;

  --brand: var(--brand-dim);
  --text1: var(--text1-dim);
  --text2: var(--text2-dim);
  --surface1: var(--surface1-dim);
  --surface2: var(--surface2-dim);
  --surface3: var(--surface3-dim);
  --surface4: var(--surface4-dim);
  --surface-shadow: var(--surface-shadow-dim);
  --shadow-strength: var(--shadow-strength-dim);
}

A questo punto, gli autori sono liberi di utilizzare i generici della combinazione di colori forniti in base alle esigenze e non dovrebbero più preoccuparsi dei temi.

Conclusione

Ora che sai come ho fatto io, come faresti tu? 🙂

Diversifichiamo i nostri approcci e impariamo tutti i modi per creare sul web. Crea un Codepen o ospita la tua demo, twittala e la aggiungerò alla sezione Remix della community di seguito.

Origine

Remix della community - @chris-kruining ha aggiunto un cursore di tonalità, colori di stato e modalità di contrasto per no-preference, more e less: demo.