Variabili CSS: perché dovrebbero interessarti?

Le variabili CSS, più accuratamente note come proprietà personalizzate CSS, sono disponibili in Chrome 49. Possono essere utili per ridurre la ripetizione in CSS, ma anche per effetti di runtime efficaci come il cambio di tema e la potenziale estensione/il polyfill delle future funzionalità CSS.

Disordine CSS

Quando si progetta un'applicazione, è prassi comune mettere da parte una serie di colori del brand che verranno riutilizzati per mantenere coerente l'aspetto dell'app. Purtroppo, ripetere i valori di questi colori più volte nel CSS non è solo un'attività ripetitiva, ma anche soggetta a errori. Se prima o poi devi cambiare uno dei colori, potresti far fronte al vento e cercare di trovare e sostituire tutte le cose, ma in un progetto abbastanza grande questo potrebbe diventare pericoloso.

Di recente molti sviluppatori si sono rivolti a preprocessori CSS, come SASS o MENO, che risolvono questo problema utilizzando variabili di preprocessore. Sebbene questi strumenti abbiano aumentato enormemente la produttività degli sviluppatori, le variabili che utilizzano presentano uno svantaggio grave, ovvero sono statiche e non possono essere modificate in fase di runtime. L'aggiunta della possibilità di modificare le variabili in fase di runtime non solo apre le porte a cose come la tematizzazione dinamica delle applicazioni, ma ha anche importanti ramificazioni per il progettazione adattabile e la possibilità di eseguire il polyfill delle future funzionalità CSS. Con la versione 49 di Chrome, queste funzionalità sono ora disponibili sotto forma di proprietà personalizzate CSS.

Proprietà personalizzate in breve

Le proprietà personalizzate aggiungono due nuove funzionalità agli strumenti CSS:

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

Ecco un breve esempio

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

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

--main-color è una proprietà personalizzata definita dall'autore con un valore #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 così color: #06c;. Se la proprietà personalizzata è definita da qualche parte nel foglio di stile, deve essere disponibile per la funzione var.

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

Sintassi delle proprietà personalizzate

La sintassi per una proprietà personalizzata è semplice.

--header-color: #06c;

Tieni presente che le proprietà personalizzate sono sensibili alle maiuscole, pertanto --header-color e --Header-Color sono proprietà personalizzate diverse. Sebbene possano sembrare semplici per le proprietà personalizzate, la sintassi consentita per le proprietà personalizzate è abbastanza permissiva. Ad esempio, di seguito è riportata una proprietà personalizzata valida:

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

Anche se non sarebbe utile come variabile, poiché non sarebbe valida in qualsiasi proprietà normale, potrebbe essere letta e utilizzata con JavaScript in fase di runtime. Ciò significa che le proprietà personalizzate hanno il potenziale per sbloccare tutti i tipi di tecniche interessanti attualmente non possibili con i preprocessori CSS di oggi. Quindi se stai pensando "sbadiglia, ho l'SASS, chi se ne frega...", dai un'altra occhiata. Queste non sono le variabili con cui sei abituato a lavorare.

La cascata

Le proprietà personalizzate seguono le regole a cascata standard, quindi puoi definire la stessa proprietà con 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 è possibile sfruttare le proprietà personalizzate all'interno delle query supporti per semplificare l'uso del annuncio adattabile. Un caso d'uso potrebbe essere l'espansione dei margini intorno agli elementi di sezione principali all'aumentare delle dimensioni dello schermo:

: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 gli attuali preprocessori CSS, che non sono in grado di definire le variabili all'interno delle query multimediali. Avere questa abilità sblocca un grande potenziale!

È anche possibile avere proprietà personalizzate che ricavano il loro valore da altre proprietà personalizzate. Questo può essere estremamente utile per la definizione 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 usare 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 di riserva da utilizzare quando la proprietà personalizzata a cui viene fatto riferimento non è valida. I valori di riserva possono essere un elenco separato da virgole, che verrà combinato in un singolo valore. Ad esempio, var(--font-stack, "Roboto", "Helvetica"); definisce un elemento di riserva di "Roboto", "Helvetica". Tieni presente che i valori abbreviati, come quelli utilizzati per margine e spaziatura interna, non sono separati da virgole, quindi un elemento di riserva appropriato per la spaziatura interna sarebbe simile a questo.

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

Utilizzando questi valori di riserva, l'autore di un componente può scrivere stili difensivi per il proprio 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 la tematizzazione dei componenti web che utilizzano shadow DOM, poiché le proprietà personalizzate possono attraversare i confini delle ombre. Un autore di componenti web può creare un progetto iniziale utilizzando valori di riserva ed esporre "hook" di temi 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() ci sono alcuni aspetti a cui fare attenzione. Le variabili non possono essere nomi di proprietà. Ad esempio:

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

Tuttavia, non equivale all'impostazione di margin-top: 20px;. Invece, la seconda dichiarazione non è valida e viene restituita come errore.

Allo stesso modo, non puoi (ingenuo) creare un valore se parte di questo è fornito da una variabile:

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

Anche in questo caso, questa operazione non equivale all'impostazione di 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 usata prima, la funzione calc() è un piccolo strumento che ti consente di eseguire calcoli per determinare i valori CSS. È supportato su tutti i browser moderni e può essere combinato con le proprietà personalizzate per creare nuovi valori. Ad esempio:

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

Utilizzare le proprietà personalizzate in JavaScript

Per ottenere il valore di una proprietà personalizzata in fase di runtime, usa il metodo getPropertyValue() 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 runtime, 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 faccia riferimento a un'altra proprietà personalizzata in fase di runtime 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 tuoi fogli di stile, potresti immaginare come tutto questo possa creare effetti di runtime di ogni tipo.

Supporto del browser

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

Demo

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

Per approfondire

Se ti interessa saperne di più sulle proprietà personalizzate, Philip Walton del team di Google Analytics ha scritto un'introduzione al perché è entusiasta delle proprietà personalizzate. Puoi tenere d'occhio i progressi in altri browser sul sito chromestatus.com.