Costruire delle palette di colori partendo da un colore base

(articolo: http://www.sitepoint.com/using-sass-build-color-palettes/ )

Mettiamo di avere una tavolozza composta da 7 colori sulla tonalità del rosso, che  hai realizzato in Photoshop o con le funzioni Sass ( Il colore 4 ° (al centro) è il colore di base e ci sono tre toni più leggeri di esso e tre più scure ) e mettiamo di volere un modo per produrre rapidamente una palette simile di un altro colore di base.

In sostanza, si vuole avere un'altra raccolta di colori in cui la differenza di luminosità e saturazione tra il colore di base e ogni colore della tavolozza è la stessa. Quindi, se la differenza tra il colore più chiaro e il colore di base è, diciamo, il 10% di leggerezza, si desidera che il colore più chiaro il 10% più luminoso rispetto al colore di base della propria tavolozza.

Ma senza conoscere su che regole è stata generata la prima paletta, come creare una funzione che permetta di creare nuove palette partendo da un colore base?

In primo luogo, abbiamo bisogno di inizializzare la tavolozza predefinita come una variabile globale e assegnarla come nostro !default. Con un picker ci prendiamo i valori dei diversi colori e compiliamo la nostra tavolozza come:

$base-palette: (
  'base': #ff6351,
  'colors': #cfdfe8 #bfb9c3 #cf9192 #ff6351 #bf413c #7f3128 #732c24
) !default;

La nostra gamma di colori di base è una mappa fatta di 2 chiavi: il colore di base, e un elenco di colori.

I primi tre sono i toni chiari, partendo dal più chiaro, poi di nuovo il colore di base, e infine i toni scuri, per finire con il più scuro.

Noi calcolaremo la diff colore. Un diff colore è una mappa di operazioni da applicare a un colore A al fine di elaborarlo per ottenere il colore B.

Nel nostro caso, avremo bisogno di un elenco di diff colore, uno per ogni colore della tavolozza. Ogni diff colore conterrà le operazioni da applicare al colore n, in modo da avere il colore di base (o l'inverso, non importa).

@function color-diff($a, $b) {
  $sat: saturation($a) - saturation($b);
  $lig: lightness($a) - lightness($b);
  $fn-sat: if($sat > 0, 'desaturate', 'saturate');
  $fn-lig: if($lig > 0, 'darken', 'lighten');

  @return (
    adjust-hue: -(hue($a) - hue($b)),
    #{$fn-sat}: abs($sat),
    #{$fn-lig}: abs($lig)
  );
}

Riassumendo, la color-diff  restituisce una mappa di operazioni da applicare al primo colore $a per ottenere il secondo colore $b.

Adesso abbiamo bisogno di una funzione che gestisca la color-diff in tutti i colori  ( each ) della tavolozza di base $base-palette e restituisca un elenco di queste differenze:

@function palette-diff($palette) {
  $base: map-get($palette, 'base');
  $colors: map-get($palette, 'colors');
  $diffs: ();

  @each $color in $colors {
    $diffs: append($diffs, color-diff($base, $color));
  }

  @return $diffs;
}

Ora, tutto quello che dobbiamo fare è eseguire una volta e poi memorizzare in una variabile globale. Non c'è bisogno di calcolare i diff per ogni tavolozza stiamo correndo, solo una volta è sufficiente:


$base-palette: (
  'base': #FF6351,
  'colors': #CFDFE8 #BFB9C3 #CF9192 #FF6351 #BF413C #7F3128 #732C24
) !default;

$palette-diff: palette-diff($base-palette);

/**
 * Yields a list of 7 maps (diffs)

(
  (adjust-hue: 195.3931deg, desaturate: 64.78873%, lighten: 20.19608%),
  (adjust-hue: 269.7931deg, desaturate: 92.30769%, lighten: 8.62745%),
  (adjust-hue: 352.82536deg, desaturate: 60.75949%, lighten: 3.13725%),
  (adjust-hue: 0deg, saturate: 0%, lighten: 0%),
  (adjust-hue: 0.20532deg, desaturate: 47.80876%, darken: 16.66667%),
  (adjust-hue: 0deg, desaturate: 47.90419%, darken: 33.13725%),
  (adjust-hue: -0.13095deg, desaturate: 47.68212%, darken: 36.27451%)
)

 */

Fin qui tutto bene! Solo due funzioni ancora.

La prima, che applicando un color-diff ad un colore, restituisca il nuovo colore.

@function apply-diff($color, $diff) {
  @each $function, $value in $diff {
    $color: call($function, $color, $value);
  }

  @return $color;
}

Ora abbiamo solo bisogno di una funzione che crei una tavolozza partendo da un colore di base. Chiamiamola create-palette.

@function create-palette($base-color) {
  $palette: ();

  @each $diff in $palette-diff {
    $palette: append($palette, apply-diff($base-color, $diff));
  }

  @return $palette;
}

A questo punto, abbiamo praticamente finito. Chiamiamo la create-palette funzione con un colore di base, che ci restituirà una lista di 7 colori eseguendo  le stesse operazioni che sono stati utilizzate per creare la tavolozza di base. Per esempio:

$green-palette: create-palette(lightgreen);
// Returns: #f4f1f3 #d5d5d5 #c2cec0 lightgreen #79b079 #4f864f #497c49

Un elenco di colori non è davvero il modo migliore per trattare con i colori. Che cosa hai intenzione di usare? nth($green-palette, 3)

Non proprio pratico. Che cosa succede se abbiamo trasformato questa lista in una mappa con i tasti esplicite come: lightest lighter light base dark darker darkest

Allora si potrebbe dire map-get($green-palette, light)

Per questo, costruiremo una funzione che trasforma manualmente l'elenco dei colori nella mappa:

@function palette($base-color) {
  $colors: create-palette($base-color);
  $keys: 'lightest' 'lighter' 'light' 'base' 'dark' 'darker' 'darkest';
  $palette: ();

  @for $i from 1 through min(length($colors), length($keys)) {
    $palette: map-merge($palette, (nth($keys, $i): nth($colors, $i)));
  }

  @return $palette;
}

che applicato all’esempio precedente:


$green-palette: palette(lightgreen);


/**
 * Yields

(
  lightest: #f4f1f3, 
  lighter: #d5d5d5, 
  light: #c2cec0, 
  base: lightgreen, 
  dark: #79b079, 
  darker: #4f864f, 
  darkest: #497c49
)

 */

che non è male.

Perfezionando ulteriormente le cose

Le cose sono sempre abbastanza usabili qui, ma digitando map-get(..., light) può diventare rapidamente fastidioso. Al fine di alleggerire il processo possiamo costruirci dei tool un po più pratici:

@function lightest($palette) {
  @if not map-has-key($palette, 'lightest') {
    @warn "`#{inspect($palette)}` doesn't seem to have a key named `lightest`.";
  }

  @return map-get($palette, 'lightest');
}

@function lighter($palette) {
  @if not map-has-key($palette, 'lighter') {
    @warn "`#{inspect($palette)}` doesn't seem to have a key named `lighter`.";
  }

  @return map-get($palette, 'lighter');
}

@function light($palette) {
  @if not map-has-key($palette, 'light') {
    @warn "`#{inspect($palette)}` doesn't seem to have a key named `light`.";
  }

  @return map-get($palette, 'light');
}

e quindi applicheremo un:

.el {
  color: light($green-palette);
}

Che può essere interpretato come dammi il colore "light" dalla $green-palette.