Sur la route des CSS maintenables

Introduction

CSS Maintenables
  1. CSS est simple à apprendre
  2. CSS est difficile à maîtriser
  3. CSS est difficile à maintenir
CSS Maintenables
It’s almost a challenge to find a development team that’s working on a codebase that’s more than a couple of years old where the CSS isn’t the most frightening and hated part of that system.
CSS Maintenables

Les symptômes possibles

  • Le temps de développement
  • La taille des feuilles de style
  • Le travail à plusieurs
  • L'arrivée de nouveau collaborateurs
  • Les travaux réservés aux expert

BEM, la solution !

BEM, la solution !

BEM

  • Rend vos CSS maintenables
  • Soigne du cancer
  • Ramène l'être aimé
BEM, la solution !
BEM is magic!
BEM, la solution !

Le champs d'action des méthodologies CSS

.maintainable-selector { … }
.bem-selector { … }

Top Down CSS

Top Down CSS
.news .title { … }
#sidebar .news .title { … }
.widget .news .title,
#sidebar .widget .news .title { … }
Qui n'est pas à l'aise avec la spécificité des sélecteurs ?
Top Down CSS
Top Down CSS

Il devient rapidemment impossible de connaître toutes les règles déjà écrites

  • On rajoute à la fin du fichier
  • On rallonge le fichier
  • On duplique
  • On introduit des incohérences
  • Les nouvelles ressources pleurent
Top Down CSS

On veut des styles

  1. Modulaires vs un seul fichier
    on peut se concentrer sur un problème
  2. Prévisibles vs sémantiques
    on peut comprendre le CSS depuis l'HTML

Intégration modulaire

Intégration modulaire

L'objectif est de se créer une collection de composants réutilisables.

Créer de nouvelles pages ne devrait pas forcément nécessiter d'écrire du CSS !
Intégration modulaire

Constat : L'HTML change constamment

Scénario où le CSS dépend de l'HTML
L'idéal où l'on pourrait modifier seulement le CSS à chaque modification de design n'existe (presque) pas !
Intégration modulaire

On peut concevoir des feuilles CSS indépendantes de la structure HTML

Scénario où le CSS est une couche utilisé par l'HTML
Intégration modulaire
Robinet mélangeur

Retour d'XP

Retour d'XP
Due to these efforts, we cut our average CSS bytes per page by 19% (after gzip) and HTML bytes per page by 44% (before gzip)
Retour d'XP
We started with 3348 lines of CSS and ended up with only 972, meaning we managed to delete more than 2/3 thanks to deleting unused selectors, merging similar styles, and employing CSS re-usability techniques like mixins, variables, and functions.
Retour d'XP
Factorisation de 3 sites de jeu en ligne, dans le but de créer une marque blanche. On est passé de +24 000 lignes de CSS à -4000 lignes. En 1 mois.
— Experience personnelle à Mediastay

Des sélecteurs au régime

Des sélecteurs au régime

Pas d'id

/* Header object */
#header { background-color: #464E51; }
#header a { color: hotpink; }
  • Limite la réutilisabilité
  • Trop spécifique
Des sélecteurs au régime

Pas de balise

/* Button object */
a.button { color: black; }

<button type="button" class="button"></button>
<a href="#" class="button"></a>
<input type="button" class="button" />
  • Limite la réutilisabilité
Des sélecteurs au régime

Pas de balise

/* Header object */
.header a { color: white; }
/* Button object */
.button { color: black; }
  • Évite les fuites de styles
Des sélecteurs au régime

Eviter l'imbrication

/* Article object */
.article .title { font-weight: bold; }
/* Comment object */
.comment .title { color: hotpink }

<div class="article">
    <div class="comment">
        <div class="title"></div>
    </div>
</div>
  • Évite les fuites de styles
Des sélecteurs au régime

Eviter l'imbrication


<div class="article">
    <div class="title"></div>
    <div class="comment">
        <div class="title"></div>
    </div>
</div>
  • Prévisibilité
Des sélecteurs au régime

Eviter l'imbrication, ou utiliser l'opérateur >

/* Article object */
.article > .title { font-weight: bold; }
/* Comment object */
.comment > .title { color: hotpink }
  • Évite les fuites de styles
  • Mais non prévisible !
Des sélecteurs au régime

Pas de +, ~, :nth-child(), etc.

<ul>
    <li class="box"></li>
    <li class="box"></li>
    <li class="box"></li>
</ul>
  • Prévisibilité
  • Complexité
Des sélecteurs au régime

En conclusion

  • Le sélecteur idéal est une seule classe
  • Le CSS ne contient aucune logique
  • Le style qui s'applique est prévisible

La classe
ne fait pas le module

La classe ne fait pas le module

.account-button

La classe ne fait pas le module

.account-content-button

La classe ne fait pas le module

.auth-content-form__input

La classe ne fait pas le module

Nommer le visuel ou la fonction visuelle

  • .highlight-box vs .bundle-product-discount-box
  • .primary-button vs .submit-contact-form-button

BEM

BEM

La notation BEM permet une rapide indentification du rôle d'une classe

BEM pour Block, Element et Modifier
BEM

Ils utilisent BEM sur leur site principal

Some big comapnies Et Google, Twitter, BBC, theguardian, Financial Time, etc.

Block

Block

Un block est

  • Un composant visuel ou fonctionnel
  • Indépendant de la page et des autres blocks
  • La racine d'une feuille style
  • La racine d'une logique fonctionnelle
C'est l'équivalent d'un composant des Web Components.
Block
Exemple de design
Block
Identification des blocks
Block

Ils sont indépendants

Block

Ils peuvent être réutilisés

Block

Il peuvent être imbriqués

Block

On le cible à l'aide d'une seule classe

.block-name { … }
.c-block-name { … }
.tzi-block-name { … }
.tzi-c-block-name { … }
Block

Par exemple

.c-header { … }
.c-logo { … }
.c-search-form { … }
.c-auth-form { … }
.c-top-menu { … }
Block

Chaque block a son propre fichier

Un fichier contient toutes les classes de son block
Un fichier ne contient que des classes de son block
Non négociable !
Les sélecteurs sont la clé de la maintenabilité

Element

Element

Un élément est une entité BEM représentant une portion d'un seul et même block.

Il ne peut pas être utilisé en dehors du contexte de son block référant.

Element
Exemple du concept d'élément
Element
Exemple du concept d'élément variants
Element

On le cible à l'aide d'une seule classe

.block-name__element-name { … }
.c-block-name__element-name { … }
.tzi-block-name__element-name { … }
.tzi-c-block-name__element-name { … }
Element

Par exemple

.c-search-form { … }
.c-search-form__input { … }
.c-search-form__button { … }
.c-search-form__suggestion-dropdown { … }

Modifier

Modifier

Un modifier est une entité BEM représentant l'altération de l'apparence d'un bloc ou d'un élément.

Il s'agit du même concept que les classes d'extension en OOCSS.

L'utilisation des modifiers en BEM est facultative.

Modifier
Exemple du concept de modifier
Element

On le cible à l'aide d'une seule classe

.block-name--modifier-name { … }
.block-name__element-name--modifier-name { … }
.c-block-name--modifier-name { … }
.tzi-block-name--modifier-name { … }
.tzi-c-block-name--modifier-name { … }
Element

Par exemple

.c-top-menu { … }
.c-top-menu--align-left { … }
.c-top-menu__tab { … }
.c-top-menu__tab--active { … }

Donner du sens aux classes

Donner du sens aux classes

Les noms de classe peuvent être ambigus

<form class="search full">
    <input class="input dropdown" name="query" type="search">
    <button class="button" type="submit">
        Search
    </button>
</form>
Donner du sens aux classes

En BEM, on enlève les doutes possibles

<form class="c-search-form c-search-form--full">
    <input class="c-search-form__input js-dropdown" name="query" type="search">
    <button class="c-button" type="submit">
        Search
    </button>
</form>
Donner du sens aux classes

On peut même expliciter les imbrications

<form class="c-search-form c-search-form--full">
    <input class="c-search-form__input js-dropdown" name="query" type="search" >
    <div class="c-search-form__action">
        <button class="c-button" type="submit">
            Search
        </button>
    </div>
</form>
Donner du sens aux classes

Parfois les imbrications peuvent être discrètes

<form class="c-search-form c-search-form--full">
    <input class="c-search-form__input js-dropdown" name="query" type="search" >
    <button class="c-search-form__action c-button" type="submit">
        Search
    </button>
</form>
Donner du sens aux classes

Reprennons le module media de OOCSS

<div class="media">
    <img class="img-rev" src="logo.png" alt="Foo Corp logo">
    <div class="body">
        <h3 class="title">Welcome to Foo Corp</h3>
    </div>
</div>
Donner du sens aux classes

Là encore, les classes BEM sont explicites

<div class="media">
    <img class="media__img media__img--rev" src="logo.png" alt="Foo Corp logo">
    <div class="media__body">
        <h3 class="title">Welcome to Foo Corp</h3>
    </div>
</div>

Conseils

Conseils
One of the hardest parts of BEM is deciding when to start and stop scope, and when (or not) to use it
Conseils
Don’t Layout Yourself: A component should style itself, but give up the task of layouting to its parent.
Conseils

N'hésitez pas à

  • Découper
  • Imbriquer
  • Dupliquer (oui...)
    Dry n'est pas le copain de BEM
Conseils

N'abuser pas de Sass

  • Pas de génération de sélecteur
  • Pas de @extend massif
  • Limiter aux mixins pratiques
@include clearfix();
@include text-ellipsis();
Conseils

Vous pouvez l'utiliser partout

Pratique pour nommer les factures EDF : EDF__Facture--2016.pdf