Les slides sont disponibles :
https://tzi.fr/slides/riviera2018-bem
https://tzi.fr/slides/riviera2018-bem.pdf
Une méthodologie
Une convention de nommage
Un block est :
Ils sont indépendants
Ils peuvent être réutilisés
Ils peuvent être imbriqués
/* syntax */
.block-name { ... }
/* example */
.top-menu { ... }
Un élément est :
/* syntax */
.block-name__element-name { ... }
/* example */
.top-menu__tab { ... }
Un modifieur :
/* syntax */
.block-name--modifier-name { ... }
.block-name__element-name--modifier-name { ... }
/* example */
.top-menu__tab--active { ... }
<nav class="top-menu">
<a class="top-menu__tab">Tab 1</a>
<a class="top-menu__tab">Tab 2</a>
<a class="top-menu__tab top-menu__tab--active">Tab 3</a>
<a class="top-menu__tab">Tab 4</a>
</nav>
Où dois-je appliquer cette classe ?
__
(tirets du bas) vont sous leur block.--
(tirets du milieu) vont à côté de leur entité.On retient :
__
--
CSS is like a bear cub.
It’s almost a challenge to find a development team [...] where the CSS isn’t the most frightening and hated part of that system.
Les symptômes possibles :
Les électrochocs qui poussent à changer :
Underscores and Meaningful Dashes
Les noms de classe peuvent être ambigus
<form class="search full">
<input class="input dropdown">
<button class="button">
Search
</button>
</form>
BEM explicite le rôle de chacun
<form class="search-form c-search-form--full">
<input class="search-form__input / js-dropdown">
<button class="button">
Search
</button>
</form>
BEM explicite aussi les problèmes de jointures
<form class="search-form c-search-form--full">
<input class="search-form__input / js-dropdown">
<button class="button">
Search
</button>
</form>
<form class="search-form c-search-form--full">
<input class="search-form__input / js-dropdown">
<span class="search-form__action">
<button class="button">
Search
</button>
</span>
</form>
BEM permet de regrouper les styles par block.
Block = Namespace
Si on ne connaît pas toutes les règles d'un fichier :
Si deux règles sont en conflits,
celle avec la pus grande spécificité gagne.
Plus l'application grandit,
plus il y a de risque de conflits
#contact-page { .. } /* count 1000 by id */
.button,
[type="submit"],
:hover { ... } /* count 1 by class, attribute, state */
a,
::before { ... } /* count 0.1 by element */
Niveau facile
.header a { ... }
Niveau moyen
#nav .selected > a:hover { ... }
Niveau avancé
li:first-child h2 .title::before { ... }
Niveau expert
:not(:not(.title), :not(.important)) { ... }
Ces deux sélecteurs sont équivalents
:not(:not(.title), :not(.important)) { ... }
.title.important { ... }
... mais n'ont pas la même spécificité !
.news .title { ... }
.news .title { ... }
/* ... */
#sidebar .news .title { ... }
.news .title { ... }
/* ... */
#sidebar .news .title { ... }
/* ... */
.widget .news .title { ... }
.news .title { ... }
/* ... */
#sidebar .news .title { ... }
/* ... */
.widget .news .title,
#sidebar .widget .news .title { ... }
BEM limite l'effet boule de neige :
.news__title { ... }
/* ... */
.news__title--sidebar { ... }
/* ... */
.news__title--widget { ... }
On retient :
BEM a été inventé en 2011,
A l'époque, l'avenir c'était les web components !
C'est bien de préfixer ses classes BEM avec c-
?
<nav class="c-menu"></nav>
<nav class="c-menu"></nav>
Oui.
Lorsque votre projet grandit,
vous pouvez aussi ajouter des préfixes !
La home Du Figaro, c'est :
On peut enlever la classe si elle est redondante avec l'élément ?
<button class="c-button"></button>
/* or */
<button></button>
<button></button>
Non.
On peut enlever le nom du block des modifieurs ?
<div class="c-search-form c-search-form--full"></div>
/* or */
<div class="c-search-form full"></div>
<div class="c-search-form full"></div>
Non.
On peut n'utiliser que le modifieur ?
<div class="c-search-form c-search-form--full"></div>
/* or */
<div class="c-search-form--full"></div>
<div class="c-search-form--full"></div>
Non.
Est-ce qu'un modifieur de block peut affecter un élément ?
.c-search-form--full .c-search-form__input { … }
.c-search-form--full .c-search-form__input { … }
Oui.
C'est une exception où ne peut pas limiter la spécificité des sélecteurs.
Est-ce la bonne façon de déclarer les éléments d'élément ?
.c-search-form__label__icon { … }
.c-search-form__label__icon { … }
Non. Il n'y a pas d'élément d'élément. On préfère :
.c-search-form__label-icon { … }
.c-search-form__icon { … }
On retient :
Google, Twitter, BBC, theguardian, Financial Time, DuckDuckGo, Dropbox, JetBrains, SoundCloud, WordPress, BuzzFeed, Overblog, 6play, LeFigaro, ...
BEM est une méthodologie tout terrain :
Surtout BEM respecte la philosophie des CSS
Surtout BEM respecte la philosophie des CSS
Thomas Zilliox, expert CSS freelance.
Découvre le CSS depuis 12 ans maintenant.
J'arrive enfin à produire du code maintenable !
Et avec 16 développeurs front-end actifs ?
Toujours maintenable ?
Les modifieurs sont un hack !
BEM permet à un élément de se déplacer sans changer de nom.
<div class="block block--big-title">
<div class="block__title">
<div class="block__icon"></div>
</div>
</div>
Alors on évite les opérateurs entre les classes :
.block--big-title > .block__title { … } /* non */
.block--big-title .block__title { … } /* oui */
Pour limiter la spécificité des sélecteurs,
on préfère les modifieurs d'éléments aux modifieurs de blocks :
<div class="block">
<div class="block__title block__title--big"></div>
</div>
Pour limiter la dépendance entre plusieurs règles CSS,
on préfère encore plus créer un nouveau sélecteur :
<div class="block">
<div class="block__big-title"></div>
</div>
Tout le principe de BEM est basé sur l'isolation des styles.
Attention aux partage de code :
@extends
en Sass@mixins
en SassC'est aussi valable pour l'implémentation des blocks :
<div class="block">
<div class="block__big-title"></div>
</div>
.c-alert--info,
.c-alert--warning,
.c-alert--error {
padding: 5px 10px;
}
On ne peut pas styler un composant avec son contexte.
.c-sidebar .c-article { ... } /* non */
Il faut concevoir différement, pas juste changer la façon décrire.
.c-article--sidebar { ... } /* non */
Sinon vous aller juste limiter la réutilisation de votre code.
Décrivez plutôt quel changement visuel vous souhaitez.
Utiliser un Bemlinter peut aider, il vérifie :
One of the hardest parts of BEM is deciding when to start and stop scope, and when (or not) to use it
Il faut d'abord éviter le sur-découpage.
Se laisser guider par l'usage :
Quelle est la taille maximale d'un block ?
Don’t Layout Yourself: A component should style itself, but give up the task of layouting to its parent.
On retient :
Vous ne devriez utiliser que des mixins qui ne sont pas spécifiques à votre projet :
Vos mixins ne doivent pas générer de sélecteurs !
On peut concaténer nos classes en Scss :
.block {
&__element {
...
&--modifier { ... }
}
}
Ceci génére le code CSS suivant :
.block { ... }
.block__element { ... }
.block__element--modifier { ... }
Mais un modifieur de block peut limiter cette écrite :
.block {
&__element { ... }
&--modifier &__element { ... }
}
Les variables peuvent être accesibles depuis un autre block :
$block-height: 50px;
.block {
&__element { height: $block-height; }
}
/* Leak */
.other-block { height: $block-height; }
Pour isoler vos variables :
.block {
$height: 50px;
&__element { height: $height; }
}
/* Doesn't work. No leak! */
.other-block { height: $height; }
On peut alors sauvegarder notre block dans une variable :
.block {
$block: &;
&__element {
...
#{$block}--modifier & { ... }
}
}
Vous savez combien il faut de lignes pour
convertir une chaîne de caracter en nombre
à l'aide de Sass ?
Attention, à ne pas abuser de la concaténation qui rend impossible les fonctionnalités de rechercher / remplacer
Si vous voulez des variables locales sans concaténation :
.block {
$height: 50px;
@at-root {
.block__element { height: $height; }
}
}
On retient :
BEM a de gros avantages :
On lui reproche :
Une idée est d'importer des règles d'OOCSS :
The component should still rely on OOCSS utilities as much as possible. Only styles that are not available through OOCSS utilities should be set in the component class.
<div class="c-menu">
<div class="l-grid">
<div class="l-grid__cell">
<a class="c-menu__tab"></a>
</div>
</div>
</div>
Une autre idée est de remplacer les modifieurs BEM par des classes atomiques :
<div class="c-article">
<h1 class="c-article__title u-uppercase"></h1>
<div class="c-article__status u-green"></div>
</div>
On retient :
BEM sert à donner du sens à des chaînes de caractères.
On peut donc l'utiliser à plein d'occasions.
Des questions ?
@iamtzi
tzi.fr/slides/riviera2018-bem
tzi.fr/slides/riviera2018-bem.pdf