Proprietà personalizzate CSS nella cascata

Pubblicato: 2022-03-10
Riassunto rapido ↬ In questo articolo, Miriam approfondisce le specifiche "Proprietà personalizzate CSS per variabili a cascata" per chiedersi: "Perché vengono chiamate proprietà personalizzate, come funzionano in cascata e cos'altro possiamo fare con esse ?" Superando la metafora della "variabile", le proprietà personalizzate possono fornire nuovi modi per bilanciare il contesto e l'isolamento nei modelli e nei componenti CSS.

Il mese scorso, ho avuto una conversazione su Twitter sulla differenza tra stili "con ambito" (generati in un processo di compilazione) e stili "nidificati" nativi di CSS. Ho chiesto perché, aneddoticamente, gli sviluppatori evitano la specificità dei selettori ID, mentre abbracciano gli "stili con ambito" generati da JavaScript? Keith Grant ha suggerito che la differenza sta nel bilanciare la cascata* e l'ereditarietà, cioè nel dare la preferenza alla vicinanza rispetto alla specificità. Diamo un'occhiata.

La cascata

La cascata CSS si basa su tre fattori:

  1. Importanza definita dal flag !important e origine dello stile (utente > autore > browser)
  2. Specificità dei selettori utilizzati (inline > ID > classe > elemento)
  3. Sorgente Ordine del codice stesso (l'ultimo ha la precedenza)

La prossimità non è menzionata da nessuna parte: la relazione dell'albero DOM tra le parti di un selettore. I paragrafi seguenti saranno entrambi rossi, anche se #inner p descrive una relazione più stretta di #outer p per il secondo paragrafo:

Vedi la penna [Cascade: Specificity vs Proximity](https://codepen.io/smashingmag/pen/OexweJ/) di Miriam Suzanne.

Vedi Pen Cascade: Specificity vs Proximity di Miriam Suzanne.
 <section> <p>This text is red</p> <div> <p>This text is also red!</p> </div> </section>
 #inner p { color: green; } #outer p { color: red; }

Entrambi i selettori hanno la stessa specificità, entrambi descrivono lo stesso elemento p e nessuno dei due è contrassegnato come !important , quindi il risultato è basato solo sull'ordine di origine.

Altro dopo il salto! Continua a leggere sotto ↓

Stili BEM e con ambito

Convenzioni di denominazione come BEM ("Block__Element—Modifier") vengono utilizzate per garantire che ogni paragrafo sia "ambito" su un solo genitore, evitando completamente la cascata. Al paragrafo "elementi" vengono assegnate classi univoche specifiche per il loro contesto "blocco":

Vedi la penna [BEM Selectors & Proximity](https://codepen.io/smashingmag/pen/qzPyeM/) di Miriam Suzanne.

Vedi i selettori e la prossimità della penna BEM di Miriam Suzanne.
 <section class="outer"> <p class="outer__p">This text is red</p> <div class="inner"> <p class="inner__p">This text is green!</p> </div> </section>
 .inner__p { color: green; } .outer__p { color: red; }

Questi selettori hanno ancora la stessa importanza relativa, specificità e ordine di origine, ma i risultati sono diversi. Gli strumenti CSS "con ambito" o "modulari" automatizzano quel processo, riscrivendo il nostro CSS per noi, basato sull'HTML. Nel codice seguente, ogni paragrafo ha come ambito il suo genitore diretto:

Guarda la penna [Scoped Style Proximity](https://codepen.io/smashingmag/pen/NZaLWN/) di Miriam Suzanne.

Vedi il Pen Scoped Style Proximity di Miriam Suzanne.
 <section outer-scope> <p outer-scope>This text is red</p> <div outer-scope inner-scope> <p inner-scope>This text is green!</p> </div> </section>
 p[inner-scope] { color: green } p[outer-scope] { color: red; }

Eredità

La prossimità non fa parte della cascata, ma fa parte dei CSS. È qui che l' eredità diventa importante. Se eliminiamo la p dai nostri selettori, ogni paragrafo erediterà un colore dal suo predecessore più vicino:

Vedi la penna [Ereditarietà: Specificità vs Prossimità](https://codepen.io/smashingmag/pen/mZBGyN/) di Miriam Suzanne.

Vedi l'ereditarietà della penna: specificità vs prossimità di Miriam Suzanne.
 #inner { color: green; } #outer { color: red; }

Poiché #inner e #outer descrivono elementi diversi, rispettivamente il nostro div e la section , entrambe le proprietà del colore vengono applicate senza conflitti. L'elemento p annidato non ha un colore specificato, quindi i risultati sono determinati dall'ereditarietà (il colore del genitore diretto) piuttosto che da cascade . La prossimità ha la precedenza e il valore #inner ha la precedenza su #outer .

Ma c'è un problema: per usare l'ereditarietà, stiamo modellando tutto all'interno della nostra section e div . Vogliamo scegliere come target il colore del paragrafo in modo specifico.

(Ri-)Introduzione alle proprietà personalizzate

Le proprietà personalizzate forniscono una nuova soluzione nativa del browser; ereditano come qualsiasi altra proprietà, ma non devono essere utilizzati dove sono definiti . Utilizzando un semplice CSS, senza convenzioni di denominazione o strumenti di costruzione, possiamo creare uno stile mirato e contestuale, con la prossimità che ha la precedenza sulla cascata:

Guarda la penna [Custom Props: Specificity vs Proximity](https://codepen.io/smashingmag/pen/gNGdaO/) di Miriam Suzanne.

Vedi gli accessori personalizzati della penna: specificità vs prossimità di Miriam Suzanne.
 p { color: var(--paragraph); } #inner { --paragraph: green; } #outer { --paragraph: red; }

La proprietà --paragraph personalizzata eredita proprio come la proprietà color , ma ora abbiamo il controllo esattamente su come e dove viene applicato quel valore. La proprietà --paragraph agisce in modo simile a un parametro che può essere passato al componente p , tramite selezione diretta (regole di specificità) o contesto (regole di prossimità).

Penso che questo riveli un potenziale per le proprietà personalizzate che spesso associamo a funzioni, mixin o componenti.

"Funzioni" e parametri personalizzati

Funzioni, mixin e componenti sono tutti basati sulla stessa idea: codice riutilizzabile, che può essere eseguito con vari parametri di input per ottenere risultati coerenti ma configurabili. La distinzione è in ciò che fanno con i risultati. Inizieremo con una variabile a gradiente a strisce, quindi possiamo estenderla in altre forme:

 html { --stripes: linear-gradient( to right, powderblue 20%, pink 20% 40%, white 40% 60%, pink 60% 80%, powderblue 80% ); }

Quella variabile è definita sull'elemento html radice (potrebbe anche usare :root , ma ciò aggiunge specificità non necessarie), quindi la nostra variabile a strisce sarà disponibile ovunque nel documento. Possiamo applicarlo ovunque siano supportati i gradienti:

Guarda la penna [Custom Props: Variable](https://codepen.io/smashingmag/pen/NZwrrm/) di Miriam Suzanne.

Guarda gli oggetti di scena personalizzati della penna: variabile di Miriam Suzanne.
 body { background-image: var(--stripes); }

Aggiunta di parametri

Le funzioni vengono utilizzate come variabili, ma definiscono i parametri per modificare l'output. Possiamo aggiornare la nostra variabile --stripes in modo che sia più simile a una funzione definendo alcune variabili simili a parametri al suo interno. Inizierò sostituendo to right con var(--stripes-angle) , per creare un parametro per la modifica dell'angolo:

 html { --stripes: linear-gradient( var(--stripes-angle), powderblue 20%, pink 20% 40%, white 40% 60%, pink 60% 80%, powderblue 80% ); }

Ci sono altri parametri che potremmo creare, a seconda dello scopo a cui è destinata la funzione. Dovremmo consentire agli utenti di scegliere i propri colori di strisce? In tal caso, la nostra funzione accetta 5 parametri di colore diversi o solo 3 che andranno fuori-interno come abbiamo ora? Vogliamo creare parametri anche per i color-stop? Ogni parametro che aggiungiamo fornisce una maggiore personalizzazione a scapito della semplicità e della coerenza.

Non esiste una risposta universale e corretta a questo equilibrio: alcune funzioni devono essere più flessibili e altre devono essere più supponenti. Le astrazioni esistono per fornire coerenza e leggibilità nel codice, quindi fai un passo indietro e chiedi quali sono i tuoi obiettivi. Cosa deve essere davvero personalizzabile e dove dovrebbe essere applicata la coerenza? In alcuni casi, potrebbe essere più utile avere due funzioni supponenti, piuttosto che una funzione completamente personalizzabile.

Per utilizzare la funzione sopra, dobbiamo passare un valore per il parametro --stripes-angle e applicare l'output a una proprietà di output CSS, come background-image :

 /* in addition to the code above… */ html { --stripes-angle: 75deg; background-image: var(--stripes); } 

Guarda la penna [Custom Props: Function](https://codepen.io/smashingmag/pen/BgwOjj/) di Miriam Suzanne.

Guarda gli oggetti di scena personalizzati della penna: funzione di Miriam Suzanne.

Ereditato contro universale

Ho definito la funzione --stripes sull'elemento html per abitudine. Le proprietà personalizzate ereditano e voglio che la mia funzione sia disponibile ovunque, quindi ha senso inserirla nell'elemento radice. Funziona bene per ereditare variabili come --brand-color: blue , quindi potremmo aspettarci che funzioni anche per la nostra "funzione". Ma se proviamo a utilizzare nuovamente questa funzione su un selettore nidificato, non funzionerà:

Guarda la penna [Custom Props: Function Inheritance Fail](https://codepen.io/smashingmag/pen/RzjRrM/) di Miriam Suzanne.

Vedi la penna Custom Props: Function Inheritance Fail di Miriam Suzanne.
 div { --stripes-angle: 90deg; background-image: var(--stripes); }

Il nuovo --stripes-angle viene completamente ignorato. Si scopre che non possiamo fare affidamento sull'ereditarietà per le funzioni che devono essere ricalcolate. Questo perché ogni valore di proprietà viene calcolato una volta per elemento (nel nostro caso, l'elemento radice html ), e quindi il valore calcolato viene ereditato . Definendo la nostra funzione nella radice del documento, non rendiamo l'intera funzione disponibile ai discendenti, ma solo il risultato calcolato della nostra funzione.

Ciò ha senso se lo inquadra in termini di parametro --stripes-angle cascata. Come qualsiasi proprietà CSS ereditata, è disponibile per i discendenti ma non per gli antenati. Il valore che abbiamo impostato su un div nidificato non è disponibile per una funzione che abbiamo definito sull'antenato radice html . Per creare una funzione universalmente disponibile che ricalcoli su qualsiasi elemento, dobbiamo definirla su ogni elemento:

Guarda la penna [Custom Props: Universal Function](https://codepen.io/smashingmag/pen/agLaNj/) di Miriam Suzanne.

Guarda gli oggetti di scena personalizzati della penna: funzione universale di Miriam Suzanne.
 * { --stripes: linear-gradient( var(--stripes-angle), powderblue 20%, pink 20% 40%, white 40% 60%, pink 60% 80%, powderblue 80% ); }

Il selettore universale rende la nostra funzione disponibile ovunque, ma possiamo definirla in modo più restrittivo se vogliamo. L'importante è che possa ricalcolare solo dove è esplicitamente definito. Ecco alcune alternative:

 /* make the function available to elements with a given selector */ .stripes { --stripes: /* etc… */; } /* make the function available to elements nested inside a given selector */ .stripes * { --stripes: /* etc… */; } /* make the function available to siblings following a given selector */ .stripes ~ * { --stripes: /* etc… */; } 

Guarda la penna [Custom Props: Scoped Function](https://codepen.io/smashingmag/pen/JQMvGM/) di Miriam Suzanne.

Guarda gli oggetti di scena personalizzati della penna: funzione con mirino di Miriam Suzanne.

Questo può essere esteso con qualsiasi logica di selezione che non si basa sull'ereditarietà.

Parametri liberi e valori di fallback

Nel nostro esempio sopra, var(--stripes-angle) non ha valore né fallback. A differenza delle variabili Sass o JS che devono essere definite o istanziate prima di essere chiamate, le proprietà personalizzate CSS possono essere chiamate senza essere mai definite. Questo crea una variabile "libera", simile a un parametro di funzione che può essere ereditato dal contesto.

Possiamo eventualmente definire la variabile su html o :root (o qualsiasi altro predecessore) per impostare un valore ereditato, ma prima dobbiamo considerare il fallback se non viene definito alcun valore. Ci sono diverse opzioni, a seconda del comportamento che vogliamo

  1. Per i parametri "richiesti", non vogliamo un fallback. Così com'è, la funzione non farà nulla finché --stripes-angle non sarà definito.
  2. Per i parametri "opzionali", possiamo fornire un valore di fallback nella funzione var() . Dopo il nome-variabile, aggiungiamo una virgola, seguita dal valore predefinito:
 var(--stripes-angle, 90deg)

Ogni funzione var() può avere solo un fallback, quindi tutte le virgole aggiuntive faranno parte di quel valore. Ciò consente di fornire impostazioni predefinite complesse con virgole interne:

 html { /* Computed: Hevetica, Ariel, sans-serif */ font-family: var(--sans-family, Hevetica, Ariel, sans-serif); /* Computed: 0 -1px 0 white, 0 1px 0 black */ test-shadow: var(--shadow, 0 -1px 0 white, 0 1px 0 black); }

Possiamo anche utilizzare variabili nidificate per creare le nostre regole a cascata, dando priorità diverse ai diversi valori:

 var(--stripes-angle, var(--global-default-angle, 90deg))
  1. Per prima cosa, prova il nostro parametro esplicito ( --stripes-angle );
  2. Fallback a un "default utente" globale ( --user-default-angle ) se disponibile;
  3. Infine, fallback al nostro "default di fabbrica" (90deg ).

Guarda la penna [Custom Props: Fallback Values](https://codepen.io/smashingmag/pen/jjGvVm/) di Miriam Suzanne.

Guarda gli oggetti di scena personalizzati della penna: valori di riserva di Miriam Suzanne.

Impostando i valori di fallback in var() anziché definire esplicitamente la proprietà personalizzata, ci assicuriamo che non ci siano specificità o restrizioni a cascata sul parametro. Tutti i parametri *-angle sono "liberi" per essere ereditati da qualsiasi contesto.

Fallback del browser e fallback delle variabili

Quando utilizziamo le variabili, ci sono due percorsi di fallback che dobbiamo tenere a mente:

  1. Quale valore dovrebbe essere utilizzato dai browser senza supporto per le variabili?
  2. Quale valore dovrebbe essere utilizzato dai browser che supportano le variabili, quando una particolare variabile è mancante o non valida?
 p { color: blue; color: var(--paragraph); }

Mentre i vecchi browser ignoreranno la proprietà di dichiarazione della variabile e torneranno al blue , i browser moderni leggeranno entrambi e utilizzeranno quest'ultimo. Il nostro var(--paragraph) potrebbe non essere definito, ma è valido e sovrascriverà la proprietà precedente, quindi i browser con supporto per le variabili eseguiranno il fallback al valore ereditato o iniziale, come se utilizzassero la parola chiave unset .

All'inizio può sembrare confuso, ma ci sono buone ragioni per questo. Il primo è tecnico: i motori del browser gestiscono la sintassi non valida o sconosciuta al "tempo di analisi" (che accade per primo), ma le variabili non vengono risolte fino al "tempo del valore calcolato" (che accade in seguito).

  1. Al momento dell'analisi, le dichiarazioni con sintassi non valida vengono completamente ignorate, ricorrendo alle dichiarazioni precedenti. Questo è il percorso che seguiranno i vecchi browser. I browser moderni supportano la sintassi delle variabili, quindi la dichiarazione precedente viene invece eliminata.
  2. Al momento del valore calcolato la variabile viene compilata come non valida, ma è troppo tardi: la dichiarazione precedente era già stata eliminata. Secondo le specifiche, i valori delle variabili non valide vengono trattati come unset :

Guarda la penna [Custom Props: Invalid/Unsupported vs Undefined](https://codepen.io/smashingmag/pen/VJMGbJ/) di Miriam Suzanne.

Vedi gli accessori personalizzati della penna: non validi/non supportati vs non definiti di Miriam Suzanne.
 html { color: red; /* ignored as *invalid syntax* by all browsers */ /* - old browsers: red */ /* - new browsers: red */ color: not a valid color; color: var(not a valid variable name); /* ignored as *invalid syntax* by browsers without var support */ /* valid syntax, but invalid *values* in modern browsers */ /* - old browsers: red */ /* - new browsers: unset (black) */ --invalid-value: not a valid color value; color: var(--undefined-variable); color: var(--invalid-value); }

Questo è un bene anche per noi autori, perché ci consente di giocare con fallback più complessi per i browser che supportano le variabili e fornisce semplici fallback per i browser meno recenti. Ancora meglio, ciò ci consente di utilizzare lo stato null / undefined per impostare i parametri richiesti. Questo diventa particolarmente importante se vogliamo trasformare una funzione in un mixin o in un componente.

Proprietà personalizzate "Mixin"

In Sass, le funzioni restituiscono valori grezzi, mentre i mixin generalmente restituiscono l'output CSS effettivo con coppie proprietà-valore. Quando definiamo una proprietà --stripes universale, senza applicarla a nessun output visivo, il risultato è simile a una funzione. Possiamo farlo comportare più come un mixin, definendo anche l'output universalmente:

 * { --stripes: linear-gradient( var(--stripes-angle), powderblue 20%, pink 20% 40%, white 40% 60%, pink 60% 80%, powderblue 80% ); background-image: var(--stripes); }

Finché --stripes-angle rimane non valido o non definito, il mixin non viene compilato e non verrà applicata alcuna background-image . Se impostiamo un angolo valido su qualsiasi elemento, la funzione calcolerà e ci darà uno sfondo:

 div { --stripes-angle: 30deg; /* generates the background */ }

Sfortunatamente, quel parametro-value erediterà , quindi la definizione corrente crea uno sfondo sul div e su tutti i discendenti . Per risolvere il problema, dobbiamo assicurarci che il valore --stripes-angle non erediti, appoggiandolo initial (o qualsiasi valore non valido) su ogni elemento. Possiamo farlo sullo stesso selettore universale:

Guarda la penna [Custom Props: Mixin](https://codepen.io/smashingmag/pen/ZdXMJx/) di Miriam Suzanne.

Guarda gli accessori personalizzati della penna: Mixin di Miriam Suzanne.
 * { --stripes-angle: initial; --stripes: /* etc… */; background-image: var(--stripes); }

Stili in linea sicuri

In alcuni casi, è necessario che il parametro sia impostato dinamicamente dall'esterno del CSS, sulla base dei dati di un server back-end o di un framework front-end. Con le proprietà personalizzate, possiamo definire in sicurezza variabili nel nostro HTML senza preoccuparci dei soliti problemi di specificità:

Guarda la penna [Custom Props: Mixin + Inline Style](https://codepen.io/smashingmag/pen/qzPMPv/) di Miriam Suzanne.

Guarda gli accessori personalizzati della penna: Mixin + Inline Style di Miriam Suzanne.
 <div>...</div>

Gli stili in linea hanno un'elevata specificità e sono molto difficili da ignorare, ma con le proprietà personalizzate abbiamo un'altra opzione: ignorarla. Se impostiamo il div su background-image: none (ad esempio) quella variabile inline non avrà alcun impatto. Per andare ancora più lontano, possiamo creare una variabile intermedia:

 * { --stripes-angle: var(--stripes-angle-dynamic, initial); }

Ora abbiamo la possibilità di definire --stripes-angle-dynamic nell'HTML, o ignorarlo, e impostare --stripes-angle direttamente nel nostro foglio di stile.

Guarda la penna [Custom Props: Mixin + Inline / Override](https://codepen.io/smashingmag/pen/ZdXMao/) di Miriam Suzanne.

Guarda gli accessori personalizzati della penna: Mixin + Inline / Override di Miriam Suzanne.

Valori preimpostati

Per valori più complessi o schemi comuni che vogliamo riutilizzare, possiamo anche fornire alcune variabili preimpostate tra cui scegliere:

 * { --tilt-down: 6deg; --tilt-up: -6deg; }

E usa quei preset, invece di impostare direttamente il valore:

 <div>...</div> 

Guarda la penna [Custom Props: Mixin + Presets](https://codepen.io/smashingmag/pen/LKemZm/) di Miriam Suzanne.

Guarda gli accessori personalizzati della penna: Mixin + Presets di Miriam Suzanne.

Questo è ottimo per creare grafici e grafici basati su dati dinamici o persino per definire un'agenda giornaliera.

Vedi la penna [Grafico a barre nella griglia CSS + variabili](https://codepen.io/smashingmag/pen/wLrEyg/) di Miriam Suzanne.

Vedi il grafico Pen Bar nella griglia CSS + variabili di Miriam Suzanne.

Componenti contestuali

Possiamo anche riformulare il nostro "mixin" come un "componente" applicandolo a un selettore esplicito e rendendo i parametri opzionali. Piuttosto che fare affidamento sulla presenza o assenza di --stripes-angle per attivare o disattivare il nostro output, possiamo fare affidamento sulla presenza o assenza di un selettore di componenti. Ciò ci consente di impostare i valori di fallback in modo sicuro:

Guarda la penna [Custom Props: Component](https://codepen.io/smashingmag/pen/QXqVmM/) di Miriam Suzanne.

Guarda gli oggetti di scena personalizzati della penna: componente di Miriam Suzanne.
 [data-stripes] { --stripes: linear-gradient( var(--stripes-angle, to right), powderblue 20%, pink 20% 40%, white 40% 60%, pink 60% 80%, powderblue 80% ); background-image: var(--stripes); }

Inserendo il fallback all'interno della funzione var() , possiamo lasciare --stripes-angle non definito e "libero" per ereditare un valore dall'esterno del componente. Questo è un ottimo modo per esporre alcuni aspetti di uno stile componente all'input contestuale. Anche gli stili "con scope" generati da un framework JS (o con scope all'interno dello shadow-DOM, come le icone SVG) possono utilizzare questo approccio per esporre parametri specifici per l'influenza esterna.

Componenti isolati

Se non vogliamo esporre il parametro per l'ereditarietà, possiamo definire la variabile con un valore predefinito:

 [data-stripes] { --stripes-angle: to right; --stripes: linear-gradient( var(--stripes-angle, to right), powderblue 20%, pink 20% 40%, white 40% 60%, pink 60% 80%, powderblue 80% ); background-image: var(--stripes); }

Questi componenti funzionerebbero anche con una classe o qualsiasi altro selettore valido, ma ho scelto l'attributo data- per creare uno spazio dei nomi per tutti i modificatori che vogliamo:

 [data-stripes='vertical'] { --stripes-angle: to bottom; } [data-stripes='horizontal'] { --stripes-angle: to right; } [data-stripes='corners'] { --stripes-angle: to bottom right; } 

Guarda la penna [Custom Props: Isolated Components](https://codepen.io/smashingmag/pen/agLaGX/) di Miriam Suzanne.

Guarda gli accessori personalizzati della penna: componenti isolati di Miriam Suzanne.

Selettori e parametri

Spesso vorrei poter utilizzare gli attributi dei dati per impostare una variabile, una funzionalità supportata dalla specifica CSS3 attr() , ma non ancora implementata in nessun browser (consultare la scheda delle risorse per i problemi collegati su ciascun browser). Ciò ci consentirebbe di associare più strettamente un selettore a un determinato parametro:

 <div data-stripes="30deg">...</div> /* Part of the CSS3 spec, but not yet supported */ /* attr( , ) */ [data-stripes] { --stripes-angle: attr(data-stripes angle, to right); } <div data-stripes="30deg">...</div> /* Part of the CSS3 spec, but not yet supported */ /* attr( , ) */ [data-stripes] { --stripes-angle: attr(data-stripes angle, to right); } <div data-stripes="30deg">...</div> /* Part of the CSS3 spec, but not yet supported */ /* attr( , ) */ [data-stripes] { --stripes-angle: attr(data-stripes angle, to right); }

Nel frattempo, possiamo ottenere qualcosa di simile usando l'attributo style :

Guarda la penna [Custom Props: Style Selectors](https://codepen.io/smashingmag/pen/PrJdBG/) di Miriam Suzanne.

Guarda gli accessori personalizzati della penna: selettori di stile di Miriam Suzanne.
 <div>...</div> /* The `*=` atttribute selector will match a string anywhere in the attribute */ [style*='--stripes-angle'] { /* Only define the function where we want to call it */ --stripes: linear-gradient(…); }

Questo approccio è particolarmente utile quando si vogliono includere altre proprietà oltre al parametro da impostare. Ad esempio, l'impostazione di un'area della griglia potrebbe anche aggiungere spaziatura interna e sfondo:

 [style*='--grid-area'] { background-color: white; grid-area: var(--grid-area, auto / 1 / auto / -1); padding: 1em; }

Conclusione

Quando iniziamo a mettere insieme tutti questi pezzi, diventa chiaro che le proprietà personalizzate vanno ben oltre i comuni casi d'uso delle variabili con cui abbiamo familiarità. Non solo siamo in grado di memorizzare i valori e di estenderli alla cascata, ma possiamo usarli per manipolare la cascata in nuovi modi e creare componenti più intelligenti direttamente in CSS.

Questo ci richiede di ripensare molti degli strumenti su cui abbiamo fatto affidamento in passato, dalle convenzioni di denominazione come SMACSS e BEM, agli stili "con ambito" e CSS-in-JS. Molti di questi strumenti aiutano a aggirare la specificità o a gestire gli stili dinamici in un'altra lingua: casi d'uso che ora possiamo affrontare direttamente con proprietà personalizzate. Gli stili dinamici che abbiamo spesso calcolato in JS, ora possono essere gestiti passando dati grezzi nel CSS.

All'inizio, questi cambiamenti possono essere visti come "complessità aggiunta", poiché non siamo abituati a vedere la logica all'interno dei CSS. E, come con tutto il codice, l'eccesso di ingegneria può essere un vero pericolo. Ma direi che in molti casi, possiamo usare questo potere non per aggiungere complessità, ma per spostare la complessità da strumenti e convenzioni di terze parti, indietro nel linguaggio centrale del web design e (cosa più importante) nel browser. Se i nostri stili richiedono il calcolo, quel calcolo dovrebbe risiedere all'interno del nostro CSS.

Tutte queste idee possono essere portate molto oltre. Le proprietà personalizzate stanno appena iniziando a vedere un'adozione più ampia e abbiamo solo iniziato a scalfire la superficie di ciò che è possibile. Sono entusiasta di vedere dove va a finire, e cos'altro viene in mente la gente. Divertiti!

Ulteriori letture

  • "È ora di iniziare a utilizzare le proprietà personalizzate CSS", Serg Hospodarets
  • "Una guida strategica alle proprietà personalizzate CSS", Michael Riethmuller