Variabili CSS: perché dovrebbero interessarti?

Le variabili CSS, più precisamente note come proprietà CSS personalizzate, sono disponibili in Chrome 49. Possono essere utili per ridurre le ripetizioni in CSS e anche per potenti effetti di runtime come il cambio di tema e potenzialmente l'estensione/il polyfilling di future funzionalità CSS.

Disordine CSS

Quando si progetta un'applicazione, è prassi comune mettere da parte una serie di colori del marchio che verranno riutilizzati per mantenere coerente l'aspetto dell'app. Purtroppo, ripetere questi valori di colore più e più volte nel codice CSS non solo è un'attività spiacevole, ma è anche soggetta a errori. Se, a un certo punto, uno dei colori deve essere modificato, potresti ignorare le precauzioni e utilizzare la funzionalità "Trova e sostituisci" per tutte le occorrenze, ma in un progetto abbastanza grande questo potrebbe diventare facilmente pericoloso.

Di recente, molti sviluppatori si sono rivolti a preprocessori CSS come SASS o LESS che risolvono questo problema tramite l'uso di variabili del preprocessore. Sebbene questi strumenti abbiano aumentato enormemente la produttività degli sviluppatori, le variabili che utilizzano presentano uno svantaggio importante, ovvero il fatto che sono statiche e non possono essere modificate in fase di runtime. L'aggiunta della possibilità di modificare le variabili in fase di esecuzione non solo consente di utilizzare elementi come il tema dinamico delle applicazioni, ma ha anche importanti ripercussioni sul design responsive e la possibilità di eseguire il polyfill di future funzionalità CSS. Con il rilascio di Chrome 49, queste funzionalità sono ora disponibili sotto forma di proprietà CSS personalizzate.

Panoramica delle proprietà personalizzate

Le proprietà personalizzate aggiungono due nuove funzionalità alla nostra cassetta degli attrezzi CSS:

  • La possibilità per un autore di assegnare valori arbitrari a una proprietà con un nome scelto dall'autore.
  • La funzione var(), che consente all'autore di utilizzare questi valori in altre proprietà.

Ecco un breve esempio per dimostrare

:root {
    --main-color: #06c;
}

#foo h1 {
    color: var(--main-color);
}

--main-color è una proprietà personalizzata definita dall'autore con un valore di #06c. Tieni presente che tutte le proprietà personalizzate iniziano con due trattini.

La funzione var() recupera e si sostituisce con il valore della proprietà personalizzata, generando color: #06c;. Se la proprietà personalizzata è definita da qualche parte nello stile, dovrebbe essere disponibile per la funzione var.

All'inizio la sintassi potrebbe sembrare un po' strana. Molti sviluppatori si chiedono: "Perché non usare solo $foo per i nomi delle variabili?" L'approccio è stato scelto appositamente per essere il più flessibile possibile e potenzialmente consentire l'uso di macro $foo in futuro. Per conoscere la storia, puoi leggere questo post scritto da uno degli autori delle specifiche, Tab Atkins.

Sintassi delle proprietà personalizzate

La sintassi di una proprietà personalizzata è semplice.

--header-color: #06c;

Tieni presente che le proprietà personalizzate sono sensibili alle maiuscole, quindi --header-color e --Header-Color sono proprietà personalizzate diverse. Anche se possono sembrare semplici, la sintassi consentita per le proprietà personalizzate è in realtà piuttosto permissiva. Ad esempio, la seguente è una proprietà personalizzata valida:

--foo: if(x > 5) this.width = 10;

Sebbene non sia utile come variabile, in quanto non sarebbe valida in nessuna proprietà normale, potrebbe essere potenzialmente letta e utilizzata con JavaScript in fase di esecuzione. Ciò significa che le proprietà personalizzate hanno il potenziale per sbloccare tutti i tipi di tecniche interessanti non attualmente possibili con i pre-processori CSS attuali. Quindi, se stai pensando "Sbadiglio, ho già SASS, chi se ne frega…", dai un'altra occhiata. Non sono le variabili con cui sei abituato a lavorare.

La cascata

Le proprietà personalizzate seguono le regole di cascata standard, quindi puoi definire la stessa proprietà a diversi livelli di specificità

:root { --color: blue; }
div { --color: green; }
#alert { --color: red; }
* { color: var(--color); }
<p>I inherited blue from the root element!</p>
<div>I got green set directly on me!</div>
<div id="alert">
    While I got red set directly on me!
    <p>I’m red too, because of inheritance!</p>
</div>

Ciò significa che puoi sfruttare le proprietà personalizzate all'interno delle query sui media per supportare il responsive design. Un caso d'uso potrebbe essere quello di espandere i margini intorno ai principali elementi di suddivisione man mano che le dimensioni dello schermo aumentano:

:root {
    --gutter: 4px;
}

section {
    margin: var(--gutter);
}

@media (min-width: 600px) {
    :root {
    --gutter: 16px;
    }
}

È importante sottolineare che lo snippet di codice riportato sopra non è possibile utilizzando i pre-processori CSS attuali, che non sono in grado di definire variabili all'interno delle query supporti. Questa funzionalità offre un'ampia gamma di possibilità.

È anche possibile avere proprietà personalizzate che ricavano il proprio valore da altre proprietà personalizzate. Questo può essere estremamente utile per la scelta dei temi:

:root {
    --primary-color: red;
    --logo-text: var(--primary-color);
}

La funzione var()

Per recuperare e utilizzare il valore di una proprietà personalizzata, devi utilizzare la funzione var(). La sintassi della funzione var() è la seguente:

var(<custom-property-name> [, <declaration-value> ]? )

dove <custom-property-name> è il nome di una proprietà personalizzata definita dall'autore, come --foo, e <declaration-value> è un valore alternativo da utilizzare quando la proprietà personalizzata a cui si fa riferimento non è valida. I valori di riserva possono essere un elenco separato da virgole, che verrà combinato in un unico valore. Ad esempio, var(--font-stack, "Roboto", "Helvetica"); definisce un valore di riserva di "Roboto", "Helvetica". Tieni presente che i valori abbreviati, come quelli utilizzati per i margini e i padding, non sono separati da virgole, quindi un valore alternativo appropriato per il padding sarà simile al seguente.

p {
    padding: var(--pad, 10px 15px 20px);
}

Utilizzando questi valori di riserva, l'autore di un componente può scrivere stili difensivi per il suo elemento:

/* In the component’s style: */
.component .header {
    color: var(--header-color, blue);
}
.component .text {
    color: var(--text-color, black);
}

/* In the larger application’s style: */
.component {
    --text-color: #080;
    /* header-color isn’t set,
        and so remains blue,
        the fallback value */
}

Questa tecnica è particolarmente utile per applicare temi ai componenti web che utilizzano il DOM nascosto, poiché le proprietà personalizzate possono attraversare i confini dell'ombra. Un autore di componenti web può creare un design iniziale utilizzando valori di riserva ed esporre "hook" per la tematizzazione sotto forma di proprietà personalizzate.

<!-- In the web component's definition: -->
<x-foo>
    #shadow
    <style>
        p {
        background-color: var(--text-background, blue);
        }
    </style>
    <p>
        This text has a yellow background because the document styled me! Otherwise it
        would be blue.
    </p>
</x-foo>
/* In the larger application's style: */
x-foo {
    --text-background: yellow;
}

Quando utilizzi var(), devi fare attenzione ad alcuni aspetti. Le variabili non possono essere nomi di proprietà. Ad esempio:

.foo {
    --side: margin-top;
    var(--side): 20px;
}

Tuttavia, non è equivalente all'impostazione margin-top: 20px;. La seconda dichiarazione, invece, non è valida e viene ignorata come errore.

Analogamente, non puoi (ingenuamente) creare un valore di cui una parte è fornita da una variabile:

.foo {
    --gap: 20;
    margin-top: var(--gap)px;
}

Anche in questo caso, non è equivalente all'impostazione margin-top: 20px;. Per creare un valore, hai bisogno di qualcos'altro: la funzione calc().

Creazione di valori con calc()

Se non l'hai mai utilizzata, la funzione calc() è un piccolo e pratico strumento che ti consente di eseguire calcoli per determinare i valori CSS. È supportato su tutti i browser moderni e può essere combinato con proprietà personalizzate per creare nuovi valori. Ad esempio:

.foo {
    --gap: 20;
    margin-top: calc(var(--gap) * 1px); /* niiiiice */
}

Utilizzo delle proprietà personalizzate in JavaScript

Per ottenere il valore di una proprietà personalizzata in fase di esecuzione, utilizza il getPropertyValue() metodo dell'oggetto CSSStyleDeclaration calcolato.

/* CSS */
:root {
    --primary-color: red;
}

p {
    color: var(--primary-color);
}
<!-- HTML -->
<p>I’m a red paragraph!</p>
/* JS */
var styles = getComputedStyle(document.documentElement);
var value = String(styles.getPropertyValue('--primary-color')).trim();
// value = 'red'

Analogamente, per impostare il valore della proprietà personalizzata in fase di esecuzione, utilizza il metodo setProperty() dell'oggetto CSSStyleDeclaration.

/* CSS */
:root {
    --primary-color: red;
}

p {
    color: var(--primary-color);
}
<!-- HTML -->
<p>Now I’m a green paragraph!</p>
/* JS */
document.documentElement.style.setProperty('--primary-color', 'green');

Puoi anche impostare il valore della proprietà personalizzata in modo che rimandi a un'altra proprietà personalizzata in fase di esecuzione utilizzando la funzione var() nella chiamata a setProperty().

/* CSS */
:root {
    --primary-color: red;
    --secondary-color: blue;
}
<!-- HTML -->
<p>Sweet! I’m a blue paragraph!</p>
/* JS */
document.documentElement.style.setProperty('--primary-color', 'var(--secondary-color)');

Poiché le proprietà personalizzate possono fare riferimento ad altre proprietà personalizzate nei fogli di stile, puoi immaginare come questo possa portare a tutti i tipi di effetti interessanti in fase di runtime.

Supporto browser

Al momento, Chrome 49, Firefox 42, Safari 9.1 e iOS Safari 9.3 supportano le proprietà personalizzate.

Demo

Prova il sample per dare un'occhiata a tutte le tecniche interessanti che ora puoi sfruttare grazie alle proprietà personalizzate.

Per approfondire

Se vuoi saperne di più sulle proprietà personalizzate, Philip Walton del team di Google Analytics ha scritto un articolo introduttivo su perché è entusiasta delle proprietà personalizzate e puoi monitorare i relativi progressi in altri browser su chromestatus.com.