blexin

Sviluppo
Consulenza e
Formazione IT


Blog

Evolvi la tua azienda

Vediamo come semplificare la creazione di CSS con la metodologia BEM

Semplifichiamo i CSS con BEM

Mercoledì 4 Settembre 2019

Cos’è BEM

Partiamo dalle basi: BEM non è un framework ma una metodologia, un modo particolare di scrivere e organizzare il codice CSS che amo definire “BEM Philosophy”, un gioco di parole per spiegare la pace interiore che si può raggiungere attraverso l’utilizzo di questa tecnica.

Ricordate CSS Zen Garden? Anche se non c’entra niente dal punto di vista tecnologico, il principio di poter lavorare sui fogli di stile senza rischiare l’esaurimento nervoso è lo stesso. Modificare un CSS è un po’ come disinnescare una bomba: non sai mai se la modifica che stai effettuando su un componente ne farà esplodere un altro.

Procediamo con ordine e andiamo ad analizzare una delle problematiche più comuni derivante dalla codifica di CSS. Quante volte vi sarà capitato di aver stilizzato un pulsante e magari di averlo riutilizzato dentro un altro blocco di codice e di perdere tutta la personalizzazione prevista?

Guardiamo questo esempio di codice:

<main class="container">
    <button type="button" class="btn">
    ENTER
    </button>
</main>
    
<aside class="sidebar">
    <button type="button" class="btn">
    ENTER
    </button>
</aside>
 
/* CSS */
 
.container .btn {
background: red;
color: white;
font-size: 15px;
height: 50px;
padding: 5px 10px;
        }

Il pulsante all’interno di .container verrà renderizzato in questo modo:

Guardate però cosa succede quando spostiamo il pulsante dentro .sidebar

In questo esempio, abbiamo utilizzato un selettore di discendenza. Il pulsante cambia forma perché le proprietà CSS vengono applicate solo quando .btn è posizionato all’interno del blocco .container. Di conseguenza, all’interno di un qualsiasi altro blocco diverso, come ad esempio .sidebar, assumerà una forma differente

Sarebbe bello poter avere dei componenti univoci da poter spostare da un punto all’altro del nostro layout e ritrovarli sempre uguali: ebbene, grazie alla metodologia BEM, tutto questo è finalmente possibile!

Vediamo come: BEM sta per Block – Element – Modifier

  • .block : rappresenta l’elemento padre, può essere innestato in altri blocchi ma non deve essere dipendente da essi;
  • .block__element : elemento, è dipendente dal blocco;
  • .block—modifier : serve a modificare lo stile di base, può essere applicato sia a un blocco che ad un elemento.

Ad ogni elemento nel markup va assegnata una classe e gli ID non sono consentiti. Ad un primo approccio la sintassi potrebbe non essere molto gradevole alla vista e bisognerà farci un po’ l’abitudine.

Ecco un esempio pratico dove .card rappresenta il blocco padre, mentre .card__title e .card__content sono gli elementi “figli” ad esso correlati. Nella prima parte del selettore, prima del doppio underscore ( __ ) va indicato il nome del “blocco” da cui l’elemento è dipendente. Nella seconda parte dopo il doppio underscore, va indicato il nome (possibilmente semantico) dell’elemento stesso:

<div class="card" >
    <h1 class="card__title" >Hello World!</h1 >
    <p class="card__content" >Text... </p >
</div >

In questo caso invece .card—red rappresenta il modificatore di card e ne sostituisce il background di default. Nella prima parte del selettore, prima del doppio trattino ( -- ) va indicato il nome del Blocco a cui il Modificatore dovrà essere applicato, nella seconda parte dopo il doppio trattino, va indicato il nome del Modificatore stesso:

<div class="card card--red">
    <h1 class="card__title">Hello World!</h1>
    <p class="card__content">Text... </p>
</div>

Il CSS correlato invece sarà questo:

.card {
    background: white;
}
    .card.card--red {
    background: red;
}

È possibile annidare i blocchi?

La risposta è sì! Un classico esempio è una form posizionata all’interno di un blocco .card

<div class="card">
    <h1 class="card__title">Contacts </h1>
    <p class="card__content">Text... </p>
        
    <form class="form-contact">
    <input type="text" class="form-contact__input">
    <textarea ows="10" class="form-contact__message"></textarea>
    <button class="form-contact__btn">SUBMIT</button>
    </form>
</div>
/* CSS */
    .form-contact { ... }
    .form-contact__input { ... }
    .form-contact__text { ... }

Gestione degli elementi annidati

Nella scelta dei nomi dei selettori, dobbiamo fare sempre riferimento al Blocco senza seguire necessariamente la struttura del DOM. Così facendo, possiamo spostare gli elementi a piacimento all’interno del blocco, senza dover riscrivere il codice di volta in volta. Il seguente è un esempio da non seguire:

  
<div class="block">
    <header class="block__header">
    Hello
    <strong class="block__header__strong">World! </strong>
    </header>
</div>
 
<div class="block">
    <header class="block__header">
    <h1 class="block__header__title">
    Hello
    <strong class="block__header__title__strong">World! </strong>
    </h1>
    </header>
</div>
 
.block { ... }
.block__header { ... }
.block__header__title { ... }
.block__header__title__strong { ... }

Questo invece è l’approccio corretto:

<div class="block">
    <header class="block__header">
    <h1 class="block__title">
    Hello
    <strong class="block__strong">World!</strong>
    </h1>
    </header>
</div>
/* CSS */
.block { ... }
.block__header { ... }
.block__title { ... }
.block__strong { ... }

Come usarlo con SASS

Utilizzare BEM in accoppiata con SASS è davvero fantastico, perché, grazie all’utilizzo del Nesting e della direttiva & che ci permette di ottenere un’interpolazione con il nome del blocco, abbiamo la possibilità di realizzare dei componenti che potrebbero essere spostati facilmente da un progetto all’altro senza grossi problemi. Guardiamo un classico esempio di un pulsante stilizzato:

/* SCSS */
 
.btn {
    background: black;
 
    &__label {
        color: white;
    }
    
    &#{&}--red {
        background: red;
    }
    &#{&}--blue {
        background: blue;
    }
}

In questo caso, oltre alla direttiva & che abbiamo usato per definire i selettori degli elementi, utilizziamo anche la direttiva #{&} che ci permette di creare una ulteriore interpolazione del nome del blocco. Il CSS compilato sarà quindi il seguente:

/* CSS compilato */
.btn {
    background: black;
  }
  .btn__label {
    color: white;
  }
  .btn.btn--red {
    background: red;
  }
  .btn.btn--blue {
    background: blue;
}

Inoltre, possiamo dividere ulteriormente il nostro SCSS in tanti file per poi includere il tutto in un unico foglio di stile attraverso la direttiva @import di SASS. Avremo quindi una struttura del genere:

website /
    ├── scss /
    │   ├── style.scss
    │   ├── _header.scss
    │   ├── _footer.scss
    │   ├── _button.scss
    ├──
 
 
STYLE.SCSS
	@import header;
	@import footer;
@import button;

Come usarlo con Bootstrap?

Anche se la tendenza degli ultimi anni è quella di utilizzare delle soluzioni frameworkless, Bootstrap è ancora uno degli strumenti più utilizzati, allora come facciamo a utilizzarlo con BEM?

Possiamo procedere in questo modo: non definiremo le dimensioni dei blocchi, al massimo possiamo definire solo l’altezza, in questo caso dobbiamo astrarre la griglia dai componenti e dobbiamo evitare di aggiungere delle classi alle colonne di Bootstrap. Ecco un esempio pratico:

<div class="row">
   <div class="col-md-6">
    <div class="block">
            <header class="block__header">
                <h1 class="block__title">
                    Hello
                    <strong class="block__strong">World! </strong>
                </h1>
            </header>
        </div>
    </div>
    <div class="col-md-6">
        <div class="block">
            <header class="block__header">
                <h1 class="block__title">
                    Hello
                    <strong class="block__strong">World! </strong>
                </h1>
            </header>
        </div>
    </div>
</div>

Disaccoppiando i componenti dalla griglia abbiamo la possibilità in futuro di sostituire Bootstrap con un altro framework o con CSS grid (di cui parleremo nel prossimo articolo)

Quali sono i vantaggi

  • Maggiore manutenibilità del codice;
  • Possibilità di creare dei componenti riutilizzabili in altri progetti;
  • Ottimizzazione delle prestazioni: evitando l’utilizzo dei selettori di discendenza e assegnando una classe su ciascun elemento, non costringiamo il browser a fare troppi calcoli.

Quali sono gli svantaggi

Ovviamente non è tutto oro quello che luccica: nel mondo reale talvolta ci toccherà scendere anche a compromessi con la metodologia BEM. Soprattutto quando dobbiamo fare molti reset sugli elementi, infatti, i selettori potrebbero essere molto verbosi, come nel caso in cui avessimo dei Blocchi con dei Modificatori e con degli Elementi che a loro volta presentano altri Modificatori. Ad esempio, lo stesso pulsante in alcune pagine potrebbe presentare l’ombra mentre in altre no: per evitare quindi di applicare ulteriori Modificatori all’elemento, ho cercato di ovviare attraverso tre strade percorribili.

Nella prima, il pulsante potrebbe essere definito come Blocco, e in casi estremi, al posto del modificatore andremo a utilizzare un elemento, così da sfruttare il selettore .activity-main__btn per ottenere delle personalizzazioni specifiche come l’applicazione dell’ombra.

<div class="activity-main activity-main--white">
<button type="button" class="btn-main btn--red activity-main__btn"></button>
</div>

Una seconda strada potrebbe essere quella di utilizzare le classi “helpers” (per intenderci, quelle che descrivono le proprietà che vanno ad applicare), ovviamente senza esagerare, quindi otterremo una markup del genere

<div class="activity-main activity-main--white">
 	<button type="button" class="btn-main btn--red shadow"></button>
</div>

L’ultima opzione sarebbe quella di andare dal designer e dirgli che il suo pulsante dovrebbe essere coerente con gli altri presenti sul sito ed evitare del tutto questo problema… ma questa è un’altra storia.

Best practices

In teoria: non si potrebbero spostare gli elementi da un blocco all’altro, perciò a inizio progetto sarebbe buona norma creare una buona styleguide in modo da determinare tutti i blocchi, gli elementi e i modificatori.

In pratica: se ci chiedono le classiche modifiche dell’ultimo minuto (il venerdì sera o 5 minuti prima di andare in ferie) possiamo tranquillamente spostare un elemento da un blocco all’altro senza aver paura di trovarlo stilizzato in maniera totalmente diversa, per poi successivamente andare a ottimizzare anche il codice.

I nomi dei selettori potrebbero apparire molto frammentati a causa dell’utilizzo di trattini e underscore, a questa problematica possiamo ovviare utilizzando il camel case Quindi un .activity-main__title potrebbe diventare .activityMain__title

Nel prossimo articolo parlerò di CSS grid e vedremo insieme come utilizzarlo in accoppiata alla metodologia BEM.

Autore

css

Servizi

Evolvi la tua azienda