Tutorial Flexbox e Sass Grid: come ottimizzare il design reattivo
Pubblicato: 2022-03-11Di recente, mi è stato chiesto di creare il mio sistema a griglia e, poiché reinventare la ruota è sempre utile come esperienza di apprendimento, ci sono andato. Sapevo che sarebbe stata una sfida interessante, ma sono rimasto sorpreso da quanto sia stato facile!
In questo esperimento, esamineremo i layout Flexbox e come consentono implementazioni graziose dei layout senza eseguire hack folli. Inoltre, se non hai familiarità con Sass, vedremo come funziona e utilizzeremo alcune utili utilità di Sass. Potresti anche imparare qualcosa di nuovo sulle griglie CSS come quella che fa parte di Bootstrap.
Una brevissima introduzione a Sass e Flexbox
Sass è fondamentalmente uno strumento che ti consente di evitare alcune delle carenze dei CSS, è un linguaggio di scripting che viene interpretato in CSS. La sintassi sembra molto familiare se stai già scrivendo stili CSS, ma il suo toolbox include variabili, mixin per la riutilizzabilità e if, for, each and while, tra le altre. Una delle cose più utili di Sass è che qualsiasi codice CSS valido è Sass valido, quindi puoi trasformare progressivamente la tua base di codice.
Un semplice esempio di ciclo for:
@for $i from 1 through 3 { .a-numbered-class-#{$i} { width: (20 * $i) * 1px; } }
Questo semplice ciclo itera da 1 a 3 e crea classi. L'indice dell'iterazione verrà facilmente archiviato in $i
. Possiamo anche fare calcoli e stampare la .a-numbered-class-X
tre volte con una larghezza diversa ogni volta. Questo codice restituisce:
.a-numbered-class-1 { width: 20px; } .a-numbered-class-2 { width: 40px; } .a-numbered-class-3 { width: 60px; }
Come possiamo vedere, possiamo astrarre molto del lavoro che dovresti fare in CSS. In CSS, dovresti copiare, incollare e modificare manualmente, il che è ovviamente più soggetto a errori e meno elegante, se non l'hai ancora provato, non perdere altro tempo!
Flexbox sta per Flexible Box, un sistema di layout CSS3 che posiziona e distribuisce gli elementi in modo dinamico. È uno strumento molto potente che consente layout flessibili con il minimo sforzo. Per maggiori dettagli su come imparare Flexbox, consulta la Guida completa di Chris Coyier a Flexbox.
La griglia
Passando alla griglia stessa, iniziamo con i suoi elementi di base. Saranno ispirati dagli elementi della griglia di Bootstrap: Contenitori, Righe e Colonne, ciascuno contenuto all'interno del primo.
Useremo le convenzioni di denominazione BEM per i nomi delle classi. Le convenzioni BEM sono piuttosto semplici da usare e aggiungono molte informazioni sull'elemento e sul suo contesto. In poche parole, hai:
- Blocks , che "incapsulano un'entità autonoma che ha significato di per sé":
.block
. - Elementi , che sono "parti di un blocco e non hanno alcun significato autonomo" che sono indicati da un nome del blocco, due caratteri di sottolineatura e l'elemento:
.block__elem
- Modificatori , come "Flag su blocchi o elementi", che sono rappresentati con due trattini:
.block .block--mod
.
Contenitori
Questo è l'elemento più esterno della griglia, conterrà i nostri elementi di riga. Esistono due tipi di contenitori: .container
e .container--fluid
.
Il comportamento di .container
è definito dall'essere il 100% della larghezza al di sotto di un certo punto, avere una larghezza massima fissa sopra di esso e avere margini uguali sinistro e destro:
$grid__bp-md: 768; .container { max-width: $grid__bp-md * 1px; margin: 0 auto; }
Gioca con esso qui espandendo e contraendo la finestra "output".
Per il contenitore del fluido, che ha sempre una larghezza del 100%, sostituiamo semplicemente queste proprietà con un modificatore:
&--fluid { margin: 0; max-width: 100%; }
Gioca con esso qui.
È stato facile! Ora abbiamo entrambi i contenitori implementati. Passiamo all'elemento successivo.
Righe
Le righe saranno gli organizzatori orizzontali dei nostri contenuti.
Useremo Flexbox per posizionare gli elementi figlio di una riga, facendoli avvolgere in modo che non trabocchino e dando loro il 100% di larghezza all'interno della riga (in modo da poterli annidare in seguito).
&__row { display: flex; flex-wrap: wrap; width: 100%; }
Questo posizionerà gli elementi figlio fianco a fianco e li avvolgerà in nuove righe se la somma della loro larghezza è maggiore di se stessa. Ora dobbiamo solo aggiungere alcuni div e apparirà così:
Gioca con esso qui espandendo e contraendo la finestra "output".
Le cose stanno iniziando a prendere forma, ma questa non è ancora una griglia CSS. Manca...
Colonne
Le colonne sono dove risiede il contenuto del sito. Definiscono in quante parti è divisa la riga e quanto occupano. Faremo un layout a dodici colonne. Ciò significa che possiamo dividere la riga in una o fino a dodici parti.
Per cominciare, un po' di matematica di base. Quando vogliamo avere una colonna, la sua larghezza dovrebbe essere del 100%. Se vogliamo dodici colonne. Quindi ciascuno dovrebbe occupare l'8.333...% o 100/12 della larghezza.
Con Flexbox, per distribuire i contenuti in questo modo, possiamo utilizzare flex-basis
.
Per dividere in quattro colonne, ora aggiungiamo qualcosa come:
flex-basis: (100 / 4 ) * 1%;
In questo modo, possiamo far sì che gli elementi occupino ciascuno il 25% della larghezza o qualsiasi percentuale desideriamo.
Gioca con esso qui.
Rendiamolo più dinamico. Dal momento che vogliamo che questo rifletta le nostre possibili classi, chiamiamo .col-1
, una classe per un div di colonna che avrà l'8,333% della larghezza poiché dodici di esse dovrebbero adattarsi prima di dover passare a una nuova riga. La percentuale aumenterà per tutto il tempo fino .col-12
, che occuperà il 100%.
$grid__cols: 12; @for $i from 1 through $grid__cols { .col-#{$i} { flex-basis: (100 / ($grid__cols / $i) ) * 1%; } }
Giusto per chiarire cosa sta succedendo, diciamo di voler dividere la larghezza in quattro parti uguali. Avremmo bisogno .col-3
poiché si adatta 4 volte su 12, ciò significa che .col-3
dovrebbe avere il 25% di base flessibile:
100 / ($grid__cols / $i) 100 / (12 / 3) = 25
Questo sta già iniziando a sembrare una griglia!
Gioca con esso qui.
Colonne dipendenti dalla larghezza dello schermo
Ora vogliamo essere in grado di avere un elemento che abbia una certa larghezza su mobile ma diverso su tablet e così via. Utilizzeremo determinati punti di interruzione dipendenti dalla larghezza della finestra. La nostra interfaccia utente reagirà a quei punti di interruzione e si adatterà a un layout ideale adatto alle dimensioni dello schermo di diversi dispositivi. Denomineremo i punti di interruzione in base alla dimensione: piccola (sm), media (md) e così via, .col-sm-12
sarà un elemento che occupa almeno 12 colonne fino al punto di interruzione sm
.

Rinominiamo la classe .col- .col-*
.col-sm-*
. Poiché la nostra griglia sarà prima mobile, applicheremo le sue proprietà a tutte le dimensioni dello schermo. Per quelli che devono comportarsi diversamente con schermi più grandi, aggiungeremo la classe: .col-md-*
.
Immagina un elemento con .col-sm-12
e .col-md-4
. Il comportamento previsto sarà che al di sotto del punto di interruzione "md" (medio) avrà una larghezza del 100% e sopra di esso avrà il 33,333%, un evento molto comune, poiché sui dispositivi mobili potrebbe essere necessario impilare gli elementi sopra anziché accanto a l'un l'altro quando la tua larghezza è molto più limitata.
Per questo, dovremo aggiungere una query multimediale (un'espressione che contiene codice che verrà eseguito solo al di sopra o al di sotto di una certa larghezza o su un dispositivo specifico) al punto di interruzione e creare le nostre colonne md
come abbiamo fatto prima per sm
:
@media screen and (min-width: $grid__bp-md * 1px) { @for $i from 1 through $grid__cols { &__col-md-#{$i} { flex-basis: (100 / ($grid__cols / $i) ) * 1%; } } }
Gioca con esso qui.
Si sta già avvicinando a qualcosa di utile. È un po' BAGNATO (capito? Non è SECCO...), quindi rendiamolo più astratto.
Come abbiamo visto, avremo bisogno di una query multimediale per ogni punto di interruzione, quindi creiamo un mixin che riceve un punto di interruzione che crea dinamicamente query multimediali. Potrebbe assomigliare a questo:
@mixin create-mq($breakpoint) { @if($breakpoint == 0) { @content; } @else { @media screen and (min-width: $breakpoint *1px) { @content; } } }
Ora, avvolgiamo quello che avevamo per creare le classi __col
in un mixin chiamato create-col-classes
e usiamo il mixin create-mq
.
@mixin create-col-classes($modifier, $grid__cols, $breakpoint) { @include create-mq($breakpoint) { @for $i from 1 through $grid__cols { &__col#{$modifier}-#{$i} { flex-basis: (100 / ($grid__cols / $i) ) * 1%; } } } }
E questo è tutto. Per usarlo, ora definiamo i nostri punti di interruzione in una mappa Sass e li iteriamo.
$map-grid-props: ('-sm': 0, '-md': $grid__bp-md, '-lg': $grid__bp-lg); @each $modifier , $breakpoint in $map-grid-props { @include create-col-classes($modifier, $grid__cols, $breakpoint); }
Il nostro sistema a griglia è praticamente finito! Abbiamo definito una classe .container__col-sm-*
che sarà quella predefinita e possiamo modificarne il comportamento su schermi più grandi con container__col-md-*
e container__col-lg-*
.
Possiamo anche annidare file! Gioca con esso qui.
La cosa bella di questo è che se ora volessimo che avesse tutti gli stessi punti di interruzione di Bootstrap v4 avremmo solo bisogno di fare:
$grid__bp-sm: 576; $grid__bp-md: 768; $grid__bp-lg: 992; $grid__bp-xl: 1200; $map-grid-props: ( '': 0, '-sm': $grid__bp-sm, '-md': $grid__bp-md, '-lg': $grid__bp-lg, '-xl': $grid__bp-xl );
E questo è tutto! Gioca con esso qui.
Nota come Bootstrap adotta un approccio mobile-first più completo di quanto abbiamo discusso inizialmente. Le dimensioni delle finestre più piccole non hanno suffisso come sm
o md
, il ragionamento è che la classe equivalente a .container__col-X
non verrà applicata solo da una larghezza della finestra da 0 a 576px; se non lo sovrascriviamo esplicitamente, sarà quel numero di colonne per ogni dimensione della finestra. Altrimenti, potremmo aggiungere la classe .container__col-sm-Y
per renderla una larghezza di colonne Y tra i punti di interruzione sm
.
Compensazioni
Gli offset aggiungeranno un margine rimasto rispetto alla colonna precedente. Un .container__col-offset-4
aggiungerà un margin-left: 33.333%
su tutte le dimensioni dello schermo. .container__col-md-offset-4
farà lo stesso ma al di sopra del punto di interruzione md
.
L'implementazione è ora banale; aggiungiamo una proprietà -offset
sullo stesso ciclo in cui creiamo le classi, ma invece di flex-bases
scriviamo la proprietà margin-left
. Dobbiamo farne uno in più anche per -offset-0
, dal momento che potremmo voler cancellare il margine su schermi più grandi:
@mixin create-col-classes($modifier, $grid-cols, $breakpoint) { @include create-mq($breakpoint) { &__col#{$modifier}-offset-0 { margin-left: 0; } @for $i from 1 through $grid-cols { &__col#{$modifier}-#{$i} { flex-basis: (100 / ($grid-cols / $i) ) * 1%; } &__col#{$modifier}-offset-#{$i} { margin-left: (100 / ($grid-cols / $i) ) * 1%; } } } }
Ora abbiamo offset completamente funzionanti! Gioca con esso qui.
Visualizzabilità
A volte vogliamo visualizzare/nascondere un elemento al di sotto o al di sopra di un certo punto. Per questo, possiamo rendere disponibili classi come quelle di Bootstrap v4.
Ad esempio, la classe .hidden-md-up
nasconderà qualsiasi elemento con questa classe dal punto di interruzione md
in su; al contrario, .hidden-md-down
lo nasconderà dal punto di interruzione verso il basso.
Il codice per questo è ancora una volta semplice: ripetiamo semplicemente i nostri punti di interruzione e creiamo una classe .hidden-*
con a for each
punto di interruzione. Tuttavia, abbiamo modificato la classe create-mq
per renderla un po' più astratta:
@each $modifier , $breakpoint in $map-grid-props { @if($modifier == '') { $modifier: '-xs'; } @include create-mq($breakpoint - 1, 'max') { .hidden#{$modifier}-down { display: none !important; } } @include create-mq($breakpoint, 'min') { .hidden#{$modifier}-up { display: none !important; } } }
Come nota a margine, non è questo uno dei pochi buoni usi di !important
? Si noti che l'elemento può avere una specificità arbitrariamente maggiore con una regola display: block
, ma vorremmo comunque nasconderlo sotto o sopra il punto di interruzione. Se non sei d'accordo con questo approccio, fammi sapere nei commenti!
Ecco fatto: ora abbiamo un sistema di visualizzabilità.
Gioca con esso qui.
Conclusione
Sebbene questo "framework" non sia pronto per la produzione, mostra quanto possono essere potenti i layout Flexbox e quanto sia pratico Sass. Con poche righe di codice, abbiamo implementato la funzionalità principale di un framework/griglia CSS.
Può anche servire da lezione sul fatto che una versione base di praticamente qualsiasi software può essere implementata molto facilmente. Sono i problemi concreti del mondo reale che iniziano a sommarsi ea renderlo difficile.
Ho creato un repository GitHub in cui puoi inviare problemi o eseguire richieste.
Quali funzionalità vorresti vedere implementate? L'implementazione potrebbe essere semplificata o più elegante?
Sentiti libero di farmi sapere la tua opinione sui commenti qui sotto.