Architettura CSS per sistemi di progettazione

Abbiamo appena creato un sistema di progettazione per una grande organizzazione e stabilito un’architettura CSS siamo abbastanza soddisfatti. È una delle prime volte che ho mai raggiunto il traguardo di un progetto senza desiderare di aver fatto almeno alcune cose in modo diverso. Quindi ho pensato che sarebbe stato bello condividere come siamo andati a creare l’architettura CSS del nostro sistema.

Per dare un po ‘ di contesto al progetto, abbiamo avuto il compito di creare un sistema di progettazione e una guida di stile destinata a servire le migliaia di sviluppatori dell’organizzazione, che impiegano una vasta gamma di tecnologie per costruire le loro oltre 500 applicazioni web interne.

La stragrande maggioranza degli sviluppatori dell’organizzazione non è specializzata nello sviluppo di frontend, ma piuttosto si concentra sulla programmazione delle applicazioni, sui dati e sulla logica. Poiché questi sviluppatori hanno bisogno di tempo per ottenere le loro applicazioni installato e funzionante rapidamente, spesso semplicemente copiare e incollare il codice frontend da altre applicazioni o raggiungere per framework come Bootstrap per ottenere il lavoro dell’interfaccia utente fatto. Come ci si potrebbe aspettare, il risultato cumulativo di queste azioni è un miscuglio di esperienze web incongruenti. Naturalmente questo è ciò che miravamo a porre rimedio costruendo l’organizzazione proprio un sistema di progettazione dell’interfaccia utente ponderato e robusto.

Stabilire i principi CSS

All’inizio del progetto, abbiamo parlato con gli sviluppatori del loro processo e dei punti dolenti, e abbiamo chiesto come un sistema di progettazione dell’interfaccia potrebbe semplificare la loro vita.

Abbiamo esaminato e completato il mio questionario sulle linee guida frontend, che ha portato a una serie di principi frontend che dovevano essere incapsulati all’interno del sistema. Ecco i principi specifici CSS che abbiamo stabilito:

  • Rendilo modulare. – Il sistema di progettazione è modulare in ogni modo, il che si applica molto al modo in cui viene scritto il CSS. Ci dovrebbe essere una chiara separazione tra i componenti.
  • La leggibilità è la chiave. – Gli sviluppatori dovrebbero essere in grado di comprendere il codice CSS a colpo d’occhio e capire lo scopo di un determinato selettore.
  • La chiarezza supera la concisione – Il sistema di progettazione può a volte sembrare prolisso, ma offre chiarezza e reslience in cambio. Mantenere i CSS leggibili e scalabili significa sacrificare una sintassi più breve.
  • Mantieni le cose piatte – Le stringhe di selezione lunghe dovrebbero essere evitate laddove possibile per mantenere i CSS il più possibile indipendenti dal DOM e modulari.
  • Evitare conflitti: poiché i componenti verranno distribuiti in molte applicazioni diverse, è fondamentale assicurarsi che il CSS del sistema di progettazione non sia in conflitto con altre librerie e sistemi. Ciò è ottenuto dal namespacing dei nomi delle classi del sistema, descritto più dettagliatamente di seguito.

Da lì, abbiamo stabilito convenzioni e una sintassi che ha abbracciato questi principi al fine di soddisfare le esigenze degli sviluppatori. Ecco uno sguardo alla sintassi della classe che abbiamo trovato:

spazio dei nomi Globale

Tutte le classi associate con il sistema di progettazione sono preceduti da un namespace globale, che è il Nome della Società seguito da un trattino:

.cn-

Se stai lavorando su un CSS architettura che è solo destinato ad essere servita a un singolo sito o se si dispone di un sacco di controllo sul proprio ambiente, tra cui uno spazio dei nomi globale è probabilmente inutile. Ma se il tuo sistema di progettazione si mescola con altre tecnologie, potrebbe avere senso creare un identificatore per il codice specifico del sistema. Lightning Design System utilizza un approccio simile per il proprio sistema (con il prefisso .slds-) poiché gli sviluppatori di terze parti utilizzano il proprio sistema in ambienti che Salesforce potrebbe non controllare. Nel nostro caso, molti degli sviluppatori del nostro cliente usano Angular in modo che abbiano già familiarità con la nozione di uno spazio dei nomi, poiché Angular usa ng- come spazio dei nomi per il codice specifico di Angular.

Prefissi di classe

Oltre a uno spazio dei nomi globale, abbiamo aggiunto prefissi a ciascuna classe per rendere più evidente quale lavoro sta facendo quella classe. Ecco su quali prefissi di classe siamo atterrati:

Sono stato introdotto a questo concetto da Harry Roberts, e mentre pensavo che avessero senso, all’inizio ero un po ‘ scettico semplicemente perché si trattava di caratteri extra e pensavo che i prefissi potessero effettivamente diminuire la leggibilità del codice. Non era affatto così. Dopo aver implementato i prefissi di classe, li abbiamo trovati estremamente utili per chiarire il ruolo di ogni classe e abbiamo reso facile decifrare la base di codice di un’applicazione a colpo d’occhio. Questo tipo di chiarezza è particolarmente utile per gli utenti del sistema di progettazione per essere in grado di fare facilmente testa o croce di cose.

Sintassi BEM

BEM sta per “Block Element Modifier”, che significa:

Questa metodologia sta guadagnando molta popolarità e la combinazione di questi concetti con lo spazio dei nomi globale e i prefissi di classe ci ha permesso di creare nomi di classe ancora più espliciti e incapsulati.

Mettere tutto insieme: anatomia di una classe

La combinazione di uno spazio dei nomi globale, prefissi di categoria e sintassi BEM si traduce in una stringa di classe esplicita (e sì, verbosa) che consente agli sviluppatori di dedurre quale lavoro svolge nella costruzione dell’interfaccia utente.

Diamo un’occhiata al seguente esempio:

.cn-c-btn--secondary
  • cn- è lo spazio dei nomi globale per tutti gli stili provenienti dal sistema di progettazione.
  • c- è la categoria di classe, che in questo caso c- significa “componente”
  • btn è il nome del blocco (“Blocco” è la “B” in BEM)
  • --secondary è un modificatore, che indica una variazione stilistica del blocco (“Modificatore” di essere la “M” di BEM)

Ecco un altro esempio:

.cn-l-grid__item
  • cn- ancora una volta è il sistema globale dello spazio dei nomi.
  • l- è la categoria di classe, che in questo caso l- significa “layout”
  • grid è il nome del blocco
  • __item è un elemento, che indica che questo è un bambino di blocco (“Elemento” essere “E” in BEM)

E uno più:

.cn-c-primary-nav__submenu
  • cn- è il sistema globale dello spazio dei nomi.
  • c- è la categoria di classe, che in questo caso c- significa “componente”
  • principale-nav è il nome del blocco
  • __submenu è un elemento, che indica che questo è un bambino di blocco (“Elemento” essere “E” in BEM)

di Nuovo, non c’è dubbio che queste classi sono più dettagliato rispetto alla maggior parte altri tipi di approcci là fuori, ma per questo specifico sistema di queste convenzioni fatto un sacco di senso.

Altri trucchi

Essere espliciti con minutia

Per evitare che le cose cadano a pezzi, abbiamo dettagliato come gestire molti dettagli minori come commenti, spaziatura attorno ai blocchi di codice, schede vs spazi, ecc. Per fortuna, Harry Roberts ha messo insieme una risorsa eccellente e completa chiamata Linee guida CSS, che abbiamo usato come base per questo tipo di convenzioni. Abbiamo setacciato tutto e contrassegnato le aree in cui abbiamo pianificato di deviare da ciò che Harry ha spiegato.

Sass parent selectors

Un problema che ho sempre avuto con i CSS è capire dove diavolo mettere una determinata regola. Se ho un componente di navigazione principale, ma voglio regolare il suo allineamento quando appare all’interno di un componente di intestazione, inserisco quegli stili nella mia intestazione o nella navigazione primaria Sass partial? Fortunatamente, esistono selettori padre Sass, che ci consente di mantenere tutti gli stili specifici del componente sotto lo stesso tetto:

Ciò significa che tutti i miei stili di navigazione primari possono essere trovati nel parziale Sass di navigazione principale, piuttosto che dividerli tra più file.

Regole esplicite sul nesting Sass

Il nesting in Sass può essere molto conveniente, ma corre il rischio di un output scadente con stringhe di selezione eccessivamente lunghe. Abbiamo seguito la regola di inizio e mai annidato Sass più di tre strati in profondità.

Tenendo presente il principio di planarità CSS del sistema di progettazione, abbiamo voluto limitare il nesting ai seguenti casi d’uso:

  1. Modificatori di un blocco di stile
  2. Media query
  3. Selettori padre
  4. Stati

1. Modificatori di blocchi di stile

Per i modificatori, se la regola è lunga solo poche righe, il modificatore può essere nidificato all’interno del genitore in questo modo:

.cn-c-alert { border: 1px solid gray; color: gray; /** * Error Alert */ &--error { border-color: red; color: red; }}

Grazie al simbolo &, questo compilerebbe per:

.cn-c-alert { border: 1px solid gray; color: gray;}.cn-c-alert--error { border-color: red; color: red;}

Per blocchi di stile più lunghi non abbiamo annidato il codice modificatore in quanto riduceva la leggibilità del codice.

2. Query multimediali

Le query multimediali specifiche del componente devono essere nidificate all’interno del blocco del componente.

.cn-c-primary-nav { /* Base styles */ /** * 1) On larger displays, convert to a horizontal list */ @media all and (min-width: 40em) { display: flex; }}

Questo compila a:

.cn-c-primary-nav { /* Base styles */}@media all and (min-width: 40em) { .cn-c-primary-nav { display: flex; }}

3. Selettori padre

Il sistema di progettazione utilizzerà il meccanismo di selezione genitore di Sass. Ciò consente di mantenere tutte le regole per un determinato componente in un’unica posizione.

Questo compilerà per:

.cn-c-header .cn-c-primary-nav { display: flex;}

Tutti gli stili per cn-c-primary-nav devono essere trovati in un unico posto, piuttosto che sparsi in più file parziali.

4. Stati

Gli stati di un componente devono essere inclusi come elemento nidificato. Questo include hover, focus e active stati:

.cn-c-btn { background: blue; &:hover, &:focus { background: red; }}

Questo compilerà per:

.cn-c-btn { background: blue;}.cn-c-btn:hover, .cn-c-btn:focus { background: red;}

gli Stati possono anche assumere la forma di classi di utilità, come is- e has-:

.cn-c-accordion__panel { overflow: hidden; max-height: 0; &.cn-is-active { max-height: 40em; }}

Questo compilerà per:

.cn-c-accordion__panel { overflow: hidden; max-height: 0;}.cn-c-accordion__panel.cn-is-active { max-height: 40em;}

Mettere queste regole ci ha dato una serie di vincoli e convenzioni abbiamo bisogno di attenersi al fine di creare un solido sistema. Quando ci siamo imbattuti in casi in cui una convenzione non era ovvia o una soluzione poteva essere gestita in diversi modi, avremmo avuto una conversazione su come gestirla e aggiornare le linee guida se necessario.

Funziona per tutti?

Prima di diventare tutti caldi e infastiditi e iniziare a non essere d’accordo con le decisioni specifiche che abbiamo preso nella creazione del nostro sistema, riconosci che questa architettura aveva senso per il sistema su cui stavamo lavorando. Questo significa che è una soluzione antiproiettile per ogni progetto? No, e non te lo sto proponendo. Le esigenze specifiche e la configurazione dell’organizzazione dovrebbero influenzare molto l’architettura CSS del tuo sistema di progettazione.

Lavoro su molti progetti in cui posso cavarmela con stringhe come .table-of-contents li a, ma questi progetti sono per lo più gestiti da me. Per i progetti client che coinvolgono il lavoro in un ambiente di team, sto gravitando molto verso sintassi più verbose ed esplicite come ho descritto sopra perché forniscono meno spazio alle persone per rovinare le cose. È bello vedere altre squadre come Sparkbox giungere a conclusioni simili.

Dopo alcune settimane di distanza dal progetto, stiamo tornando a continuare a lavorare sulla versione 1.1 del sistema di progettazione. Non vedo l’ora di tornare a questa base di codice e vedere quanto velocemente posso ri-acclimatarmi con esso!

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.