Prima libreria di modelli: un approccio per la gestione dei CSS
Pubblicato: 2022-03-10In questo articolo, sulla base del discorso che ho tenuto alla Smashing Conference di Toronto, descriverò un metodo di lavoro che ho adottato negli ultimi due anni e che mi aiuta a gestire i CSS nei miei progetti.
Ti mostrerò come utilizzare lo strumento della libreria di modelli Fractal, per gestire i tuoi CSS componente per componente, consentendoti al contempo di utilizzare gli strumenti con cui hai già familiarità. Anche se questo serve come introduzione a Fractal e perché abbiamo selezionato questa particolare libreria di modelli, è probabile che questo modo di lavorare venga trasferito ad altre soluzioni.
I nostri progetti
La mia azienda ha un paio di prodotti: Perch e Perch Runway CMS e Notist, un'applicazione software come servizio per oratori pubblici. Questi prodotti sono abbastanza diversi, soprattutto perché Perch è un sistema self-hosted e Notist è SaaS, tuttavia, entrambi hanno molta interfaccia utente da sviluppare. Abbiamo anche tutti i siti Web associati e la documentazione per questi prodotti, oltre ad altre cose su cui lavoriamo come il sito Web 24 Ways. Dopo aver scoperto Fractal due anni fa, abbiamo spostato ogni nuovo progetto, grande e piccolo, in Fractal.
Problemi che volevamo risolvere
Ho iniziato a studiare le soluzioni della libreria di modelli due anni fa, quando ho iniziato a ricostruire l'interfaccia utente di Perch per la versione 3. Una caratteristica di Perch è che i modelli che crei per l'output del contenuto sul tuo sito Web diventano lo schema dell'interfaccia utente di amministrazione. Ciò significa che qualsiasi tipo di campo utilizzato in un modello deve poter esistere insieme a qualsiasi altro tipo di campo. Non sappiamo come i nostri clienti possano combinarli e ci sono un numero enorme di combinazioni possibili. Inoltre, non è un "sito Web" e non volevo provare a forzare la libreria di modelli in qualcosa progettato per l'organizzazione di modelli di siti Web.
Poiché Perch è auto-ospitato - le persone lo scaricano e lo ospitano sui propri server - dobbiamo utilizzare lo stack tecnologico più semplice possibile per non porre ulteriori barriere all'ingresso di fronte alle persone, molte delle quali non conoscono l'utilizzo di un CMS. Per aggiungere un ulteriore livello di divertimento, supportiamo Internet Explorer 9, ma avevo intenzione di utilizzare molto Flexbox, poiché era prima della pubblicazione di Grid Layout.
Volevo anche evitare l'uso di strumenti che derivavano dal riapprendimento di come lavoravamo e dal cambiamento completo del nostro processo. Qualsiasi strumento aggiuntivo o modifica al modo in cui lavori ai tuoi progetti porta con sé un nuovo attrito. Puoi risolvere un problema, ma introdurre una nuova serie di problemi se apporti grandi modifiche al tuo modo di lavorare. Nel nostro caso, stavamo usando Sass in un modo abbastanza limitato, elaborandolo usando Gulp. Nessuno dei nostri progetti utilizza un framework Javascript, stiamo solo scrivendo HTML, CSS e JavaScript.
Fractal si adatta perfettamente alle nostre esigenze. È indipendente dal modo in cui sviluppi o dagli strumenti che desideri utilizzare. Cosa importante per i nostri scopi, non presupponeva che stessimo creando un sito web. L'esperimento ha avuto un tale successo che ci siamo trovati a utilizzare Fractal per ogni progetto grande o piccolo, poiché rende il processo di lavoro sui CSS molto più semplice. Anche i piccoli siti che creo da solo spesso iniziano la loro vita in Fractal, perché ci sono più vantaggi di quanto potresti pensare in termini di lavoro con una libreria di modelli e molti di questi vantaggi hanno altrettanto senso per un team composto da un team grande .
Prima di pensare a come sviluppare usando Fractal e perché penso che abbia senso sia per i piccoli progetti che per quelli grandi, diamo un'occhiata a come impostare l'ambiente.
Iniziare con Fractal
L'approccio più semplice per lavorare con Fractal è visitare il sito Web di Fractal e dare un'occhiata alla Guida introduttiva. Dovrai prima installare Fractal a livello globale, quindi puoi seguire i passaggi elencati qui per creare un nuovo progetto Fractal.
Con il tuo nuovo progetto installato, alla riga di comando cambia nella cartella che hai appena creato ed esegui il comando:
fractal start --sync
Questo avvierà un piccolo server alla porta 3000, quindi dovresti essere in grado di andare su https://localhost:3000
in un browser web e vedere il tuo progetto.
Ora che il tuo progetto è attivo e funzionante, apri la cartella del progetto nel tuo editor di testo preferito e trova il componente di esempio in components/example
. Troverai un file di configurazione e un file chiamato example.hbs . Il modello example.hbs è l'HTML del tuo componente, puoi aggiungere altro HTML a quello e Fractal lo ricaricherà e lo visualizzerà automaticamente. Cambia il file in:
<h1>This is my heading</h1> <p>{{ text }}</p>
Dovresti vedere l'intestazione apparire nel browser. Il file di configurazione può essere utilizzato per aggiungere contenuto e configurare in altro modo il componente. Se vuoi leggere il testo dell'intestazione da quel file, modifica quel file in modo che assomigli al seguente esempio:
title: Example component context: text: This is an example component! heading: My heading
Ora cambia il tuo file example.hbs per leggere quel testo.
<h1>{{ heading }}</h1> <p>{{ text }}</p>
Aggiunta di componenti aggiuntivi
Puoi seguire lo schema del componente di esempio per aggiungere il tuo. Come minimo, sono necessari una cartella (il nome del componente) e un file .hbs con lo stesso nome. È possibile aggiungere il file di configurazione se si desidera impostare le opzioni di configurazione.
I componenti possono essere nidificati in cartelle per facilitare l'individuazione di componenti particolari e il modo in cui strutturare le cartelle dipende completamente da te.
Nota : è davvero facile ritrovarsi a passare molto tempo a preoccuparsi di come nominare i propri componenti. Almeno in Fractal, rinominare e anche riorganizzare i componenti in cartelle è semplice. Puoi rinominarli o spostarli e Fractal si aggiornerà per mostrare la nuova struttura. Trovo che spesso la struttura ideale diventa evidente solo mentre mi sto sviluppando, quindi non mi preoccupo troppo all'inizio e poi la rafforzo in seguito.
Aggiunta di un flusso di lavoro CSS
Finora, siamo in grado di creare componenti HTML come modelli di manubri e un file di configurazione per inserire dati, tuttavia non abbiamo aggiunto alcun CSS. Idealmente, vogliamo aggiungere il CSS per ogni componente nella stessa cartella del resto dei file dei componenti e quindi combinarli tutti insieme.
Ho detto che Fractal fa pochissime ipotesi sul tuo flusso di lavoro; per questo motivo, fa molto meno fuori dagli schemi di quanto potrebbe se ti costringesse a un particolare modo di lavorare. Tuttavia, possiamo facilmente far funzionare Fractal con una configurazione di Gulp.
Combinando Fractal, Sass e Gulp
Di seguito viene descritta una configurazione minima che utilizza Gulp e Sass per creare un singolo file CSS di output. Si spera che tu possa seguire questo processo per fare qualsiasi altra cosa che faresti normalmente in Gulp. La cosa fondamentale da notare è che la maggior parte di questo non è specifico di Fractal, quindi una volta che hai ottenuto il funzionamento della parte Fractal puoi aggiungere qualsiasi altra cosa seguendo gli stessi schemi. Se hai familiarità con un altro strumento di compilazione, è probabile che tu possa creare un processo simile; se lo fai e sei felice di condividere, faccelo sapere nei commenti.
Prima alcune impostazioni, le seguenti ti consentiranno di seguire il codice elencato in questo tutorial, le posizioni dei tuoi file Sass e il CSS di output potrebbero alla fine essere diversi dai miei. La cosa fondamentale è che il file CSS di output deve trovarsi da qualche parte nella cartella pubblica.
- All'interno della cartella pubblica nell'installazione di Fractal, aggiungi una cartella denominata css .
- Nella cartella principale del tuo Fractal, installa aggiungi una cartella asset all'interno della quale si trova una cartella scss . Crea un file Sass chiamato global.scss all'interno di quella cartella. All'interno di quel file aggiungi la seguente riga:
@import "../../components/**/*.scss";
- Crea un file denominato example.scss nella directory del componente di
example
. - Crea gulpfile.js nella radice del tuo progetto Fractal e aggiungi il codice seguente.
'use strict'; const gulp = require('gulp'); const fractal = require('./fractal.js'); const logger = fractal.cli.console; const sass = require('gulp-sass'); const sassGlob = require('gulp-sass-glob'); const plumber = require('gulp-plumber'); const notify = require('gulp-notify'); const path = require('path'); gulp.task('sass',function() { return gulp.src('assets/scss/**/*.scss') .pipe(customPlumber('Error running Sass')) .pipe(sassGlob()) .pipe(sass()) .pipe(gulp.dest('public/css')) }); gulp.task('watch', ['sass'], function() { gulp.watch([ 'components/**/*.scss', 'assets/scss/**/*.scss' ], ['sass']); }); function customPlumber(errTitle) { return plumber({ errorHandler: notify.onError({ title: errTitle || "Error running Gulp", message: "Error: <%= error.message %>", }) }); } gulp.task('fractal:start', function(){ const server = fractal.web.server({ sync: true }); server.on('error', err => logger.error(err.message)); return server.start().then(() => { logger.success(`Fractal server is now running at ${server.url}`); }); }); gulp.task('default', ['fractal:start', 'sass', 'watch']);
Quindi installo le dipendenze elencate nella parte superiore del file. Se dovessi installarli dalla riga di comando, eseguiresti:
npm install gulp gulp-sass gulp-sass-glob gulp-plumber gulp-notify
La funzione sass
compila il Sass dagli asset in un unico file e lo emette nella cartella public
.
gulp.task('sass',function() { return gulp.src('src/assets/scss/**/*.scss') .pipe(customPlumber('Error running Sass')) .pipe(sassGlob()) .pipe(sass()) .pipe(gulp.dest('public/css')) });
Quindi creo una funzione watch
che guarderà il mio Sass negli assets
e anche quello nei singoli componenti e lo compilerà nella cartella pubblica.
gulp.task('watch', ['sass'], function() { gulp.watch([ 'components/**/*.scss', 'assets/scss/**/*.scss' ], ['sass']); });
Questo è il mio edificio CSS. Ora voglio farlo in modo da poter eseguire gulp e avvierà la visione del file CSS e l'avvio di frattale. Lo faccio creando un'attività gulp per eseguire il comando di avvio frattale.
gulp.task('fractal:start', function(){ const server = fractal.web.server({ sync: true }); server.on('error', err => logger.error(err.message)); return server.start().then(() => { logger.success(Fractal server is now running at ${server.url}); }); });
Infine, devo assicurarmi che Sass building e Fractal vengano avviati quando eseguo gulp e la riga di comando:
gulp.task('default', 'fractal:start', 'sass', 'watch');
Questo è il mio gulpfile.js completato. Se lo aggiungi al tuo progetto Fractal predefinito, assicurati che le cartelle siano a posto per i percorsi menzionati. Dovresti essere in grado di andare alla riga di comando, eseguire gulp
e Fractal si avvierà.
Possiamo testare il nostro Sass aggiungendo una variabile nel file global.scss ; dovrai aggiungerlo sopra la riga che include i componenti in modo che la variabile sia disponibile per quei componenti.
$color1: rebeccapurple;
Quindi in example.scss
aggiungi una regola per l'intestazione di livello 1 che abbiamo aggiunto in precedenza:
h1 { color: $color1; }
Se tutto è impostato correttamente, dovresti scoprire di avere un file .css in public/css che contiene la regola:
h1 { color: rebeccapurple; }
Dobbiamo fare un'altra cosa in modo da poter visualizzare in anteprima i nostri componenti utilizzando il CSS che stiamo costruendo. Dobbiamo creare un file di anteprima, che si collegherà al foglio di stile dalla cartella pubblica.
All'interno della cartella dei componenti, crea un file denominato _preview.hbs .
Il file di anteprima è essenzialmente un documento HTML, collegato al nostro CSS e qualsiasi altra cosa devi includere. Nel corpo è presente un tag {{ yield }}
, ed è qui che verrà posizionato un componente.
<!doctype html> <html lang="en"> <head> <meta charset="utf-8" /> <title>Preview Layout</title> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <link rel="stylesheet" href="{{ path '/css/global.css' }}"> </head> <body> {{{ yield }}} </body> </html>
Nota : la cartella pubblica può anche ospitare qualsiasi altra risorsa che è necessario visualizzare in componenti come immagini, caratteri e così via.
La Pattern Library come fonte di verità
Come abbiamo visto, Fractal può costruire il nostro CSS. Nei nostri progetti, facciamo in modo che Fractal sia l' unico posto in cui costruiamo ed elaboriamo CSS e altre risorse per il sito. Ciò significa che la nostra libreria di modelli e il sito o l'applicazione non vanno alla deriva. La deriva si verifica dopo la distribuzione del sito se le persone iniziano a modificare il CSS del sito e non riportano tali modifiche nella libreria di modelli. Se puoi rendere la libreria di modelli il luogo in cui viene elaborato CSS, le modifiche devono iniziare da lì, il che impedisce lo spostamento tra il sito live e la libreria.
Costruiamo tutto in Fractal e quindi copiamo tali risorse pubbliche sui siti live da distribuire. Oltre a prevenire la deriva tra i sistemi, rende anche molto più semplice la gestione dei CSS nel controllo del codice sorgente. Quando più persone lavorano su un file CSS, i conflitti di unione possono essere ragionevolmente difficili da affrontare. Con le persone che lavorano su singoli componenti nella libreria di modelli, di solito puoi evitare che due persone commettano modifiche allo stesso file contemporaneamente, e se lo fanno è solo un piccolo file da sistemare e non tutto il tuo CSS.
Utilizzo di una libreria di modelli Primo approccio per la gestione dei fallback
Ho scoperto che la libreria di modelli di lavoro prima rende la gestione dei fallback nel codice molto più semplice e meno opprimente rispetto al tentativo di riparare un sito o un'applicazione completi in una volta. Ci consente anche di concentrarci sul miglior caso possibile ed essere creativi con nuove tecniche, piuttosto che limitare ciò che facciamo a causa della preoccupazione di come lo faremo funzionare bene in browser non supportati.
Possiamo esaminare un semplice caso di un componente di un oggetto multimediale per vedere come potrebbe funzionare. Per seguire, crea una cartella multimediale all'interno dei componenti in Fractal e aggiungi i file media.hbs e media.scss .
Inizia con un buon markup
Il tuo punto di partenza dovrebbe sempre essere un markup ben strutturato. Nella libreria dei modelli, è possibile che utilizzerai questo componente con un intervallo di markup, ad esempio potresti utilizzare un componente con contenuto contrassegnato come una figura in un punto e solo con div in un altro. I tuoi contenuti dovrebbero, tuttavia, essere strutturati in modo sensato e possono essere letti dall'alto verso il basso.
Ciò garantisce che i tuoi contenuti siano accessibili a un livello molto semplice, ma significa anche che puoi sfruttare il flusso normale. Il flusso normale è il modo in cui i browser visualizzano i tuoi contenuti per impostazione predefinita, con gli elementi del blocco che avanzano uno dopo l'altro nella dimensione del blocco e gli elementi in linea, come le parole in una frase, che corrono lungo l'asse in linea. Per molti contenuti è esattamente ciò che desideri e, sfruttando il flusso normale anziché combatterlo, rendi il tuo lavoro molto più semplice mentre crei il layout.
Pertanto, il mio componente ha il seguente markup che aggiungo a media.hbs .
<div class="media"> <div class="img"> <img src="/img/placeholder.jpg" alt="Placeholder"> </div> <h2 class="title">This is my title</h2> <div class="content"> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis vehicula vitae ligula sit amet maximus. Nunc auctor neque ipsum, ac porttitor elit lobortis ac. Vivamus ultrices sodales tellus et aliquam. Pellentesque porta sit amet nulla vitae luctus. Praesent quis risus id dolor venenatis condimentum.</p> </div> <div class="footer"> An optional footer goes here. </div> </div>
Puoi vedere come viene visualizzato all'interno di Fractal:
Una volta ottenuto il markup che desidero, lavorerò sul display desktop che ho in mente. Userò CSS Grid Layout e il metodo grid-template-areas
per farlo. Aggiungi quanto segue a media.scss .
img { max-width: 100%; } .media > .title { grid-area: title; } .media > .img { grid-area: img; } .media > .content { grid-area: bd; } .media > .footer { grid-area: ft; } .media { margin-bottom: 2em; display: grid; grid-column-gap: 20px; grid-template-columns: 200px 3fr; grid-template-areas: "img title" "img bd" "img ft"; }
Ora abbiamo un semplice layout di oggetti multimediali:
Qualcosa che puoi fare in Fractal è aggiungere variazioni di un componente. Potresti voler capovolgere l'oggetto multimediale in modo che l'immagine sia sulla destra.
Ora aggiungi il CSS a media.scss per capovolgere il layout:
.media.media-flip { grid-template-columns: 3fr 200px ; grid-template-areas: "title img" "bd img" "ft img"; }
Esistono due modi per creare varianti: basate su file e basate su configurazione. Basato su file è il più semplice ed è utile anche se la tua variante ha un markup diverso. Per creare una variante basata su file, crea una copia del tuo componente nella cartella media con il nome media --flip.hbs (sono due trattini nel nome del file).
Questo componente dovrebbe avere un markup identico con la classe media-flip
aggiunta alla prima riga e sarai quindi in grado di vedere entrambe le versioni.
<div class="media media-flip">
In alternativa, poiché in questo caso tutto ciò che dobbiamo fare è aggiungere una classe, puoi creare una variante usando un file di configurazione.
Se vuoi farlo, rimuovi il tuo file variant e aggiungi invece un file di configurazione chiamato media.config.json contenente il codice seguente:
{ "title": "Media Object", "context": { "modifier": "default" }, "variants": [ { "name": "Flipped", "context": { "modifier": "flip" } } ] }
Quindi modificare la prima riga di media.hbs come segue:
<div class="media media-{{ modifier }}">
Nota : puoi aggiungere tutte le varianti che vuoi (dai un'occhiata alla documentazione per le varianti per saperne di più).
Ora potremmo pensare di aggiungere alcuni CSS per modificare il layout in base alle dimensioni dello schermo. Avvolgere il layout che abbiamo creato in una query multimediale e, soprattutto, creare un layout a colonna singola per dispositivi più piccoli.
img { max-width: 100%; } .media > .title { grid-area: title; } .media > .img { grid-area: img; } .media > .content { grid-area: bd; } .media > .footer { grid-area: ft; } .media { display: grid; grid-column-gap: 20px; grid-template-areas: "title" "img" "bd" "ft"; } @media (min-width: 600px) { .media { margin-bottom: 2em; display: grid; grid-column-gap: 20px; grid-template-columns: 200px 3fr; grid-template-areas: "img title" "img bd" "img ft"; } .media.media-flip { grid-template-columns: 3fr 200px ; grid-template-areas: "title img" "bd img" "ft img"; } }
Quindi, proprio come gestiamo la vista per i dispositivi più piccoli all'interno del nostro componente, possiamo gestire il layout per i browser più vecchi che non supportano la griglia.
In questo caso, creerò un fallback basato su float (funziona praticamente per qualsiasi browser legacy). Me ne preoccuperò solo per dimensioni dello schermo più ampie e lascerò il componente visualizzato nel flusso normale per i dispositivi mobili più vecchi.
Appena dentro la media query, aggiungi il seguente CSS:
.media:after { content: ""; display: table; clear: both; } .media > .media { margin-left: 160px; clear: both; } .media .img { float: left; margin: 0 10px 0 0; width: 150px; } .media.media-flip .img { float: right; margin: 0 0 0 10px; } .media > * { margin: 0 0 0 160px; } .media.media-flip > * { margin: 0 160px 0 0; }
Questo dovrebbe risolvere il display nei browser non di griglia. Per i browser che supportano la griglia, non devi preoccuparti dei float, cioè quando l'elemento float diventa un elemento della griglia, il float viene rimosso. Quello che sarà un problema sono i margini. Il layout nei browser che supportano la griglia ora sarà tutto distanziato a causa dei margini extra.
È qui che possiamo aggiungere una query di funzionalità, rimuovendo i margini se sappiamo che il nostro browser supporta la griglia.
@supports(display: grid) { .media > *, .media.media-flip > * { margin: 0; } .media .img, .media.media-flip .img { width: auto; margin: 0; } .media:after { content: none; } }
Questo è il nostro piccolo componente finito. Sebbene sia un semplice esempio - e si potrebbe sostenere che non ha davvero bisogno di una griglia se è necessario avere un fallback - dimostra l'approccio che sto adottando in tutti i miei progetti, grandi e piccoli.
Per mettere in produzione il mio file CSS, possiamo prendere il file CSS dalla cartella pubblica e aggiungerlo al nostro sito di produzione. Puoi anche creare uno script di questo processo per copiarlo nella cartella del tuo sito mentre viene compilato.
Sviluppo ridotto del primo caso di test
Qualcosa che ho scoperto come un vantaggio chiave nel lavorare in questo modo, è che rende davvero più semplice il supporto del browser. Non solo è più facile vedere quali CSS di fallback sono inclusi in questo componente, ma anche se si verificano problemi con un browser, è molto più semplice eseguirne il debug.
Quando stai combattendo con un problema con il browser, la cosa che generalmente ti verrà detto di fare è creare un test case ridotto. Riduci il problema alla cosa più piccola che mostra il problema. Un componente in una libreria di modelli spesso è già molto vicino a quel test case ridotto. Sicuramente molto più vicino che se stai cercando di eseguire il debug di un problema mentre guardi l'intero sito web.
Oltre a semplificare il debug del browser, l'inclusione dei tuoi fallback insieme al resto del CSS semplifica la rimozione del codice di fallback una volta che non è più necessario, è ovvio che questo codice di fallback è per questo componente. So che rimuoverlo non cambierà il modo in cui viene visualizzato nient'altro.
Questa facilità di organizzazione del nostro codice è davvero il motivo per cui Fractal ha senso anche nei piccoli progetti. Dato che tendiamo a usare comunque Gulp e Sass (anche su progetti più piccoli), l'aggiunta di Fractal al mix non è un grosso sovraccarico. Non abbiamo bisogno di vederlo solo per i nostri progetti più grandi, poiché anche un piccolo sito potrebbe avere una quantità ragionevole di CSS.
Vedi Il codice
Ho creato un progetto GitHub che ha tutto il codice menzionato nell'articolo. Suggerirei di impostare Fractal come descritto nell'articolo e quindi di prelevare qualsiasi bit, come il gulpfile o il layout di anteprima, dal mio repository.
Come ulteriore riferimento e per vedere alcuni progetti Fractal pubblicati, abbiamo la versione pubblicata della Perch Pattern Library e anche la Pattern Library for 24 Ways (costruita da Paul Robert Lloyd), a cui puoi dare un'occhiata. Questi sono buoni esempi di una libreria di modelli non di un sito Web e di una più tradizionale utilizzata per un sito.
Come gestisci i CSS?
Mi piace molto questo modo di lavorare; mi permette di scrivere CSS in modo diretto e progressivamente migliorato. A seconda del progetto, potremmo includere molti più strumenti ed elaborazione dei file. Oppure, potrei creare un sito semplice, nel qual caso l'installazione sarà più o meno come abbiamo visto in questo articolo, con una leggera elaborazione di Sass. Il fatto che Fractal significa che possiamo avere lo stesso processo per siti grandi e piccoli, per applicazioni web o siti web. Significa che possiamo sempre lavorare in un modo familiare.
Questo funziona per noi e spero che questo articolo possa darti alcune cose con cui sperimentare. Tuttavia, mi piacerebbe conoscere i modi in cui tu e il tuo team vi siete avvicinati alla gestione dei CSS nei vostri progetti e i punti di forza e di debolezza degli approcci che avete provato. Sarei particolarmente interessato a sentire qualcuno che ha sviluppato un processo simile utilizzando un'altra soluzione di libreria di modelli. Aggiungi le tue esperienze nei commenti.