Posts taggés css

Méthodologie BEM (Bloc Elément Modificateur)

0

Il existe de nombreuses manières de rédiger du code CSS. Y compris, soyons honnêtes, celle très répandue consistant à dire « le plus important, c’est que ça marche et le reste on s’en fiche ».

Mais imaginez un instant que vous deviez apporter des modifications dans un projet déjà existant et que vous tombiez dans un CSS sur quelque chose de ce genre…

body > div.content .row div.article .title > p span > a {  } 

Il est clair qu’il n’y a rien de bon à attendre de la suite… et que vous allez devoir passer beaucoup de temps avant de pouvoir apporter les modifications nécessaires sans pour autant ne pas apporter de régression dans l’existant.

Et lorsqu’il s’agit d’un gros projet nécessitant un support et des modifications en permanence, alors, tôt ou tard on commence à perdre le contrôle sur le code. On voit bien qu’il ne sera pas possible de bien coder sans avoir une approche systématique. Il existe de nombreuses normes reconnues dans le monde du web, et aujourd’hui, je vous propose d’aborder la méthodologie BEM.

BEM est une méthodologie de développement web ainsi qu’un ensemble de bibliothèques d’interface, de frameworks et d’outils complémentaires qui ont été élaborées par Yandex, le moteur de recherche russe. Son histoire a commencé en 2005.

Les concepts BEM apportent non seulement une convention de nommage des sélecteurs, mais également une vision du projet constitué par un ensemble d’entités (des blocs, des éléments, des modificateurs).

Il faut cependant souligner que BEM est aujourd’hui une méthode très largement reconnue dans le monde entier. Il suffit de jeter un œil aux entreprises qui l’utilisent : Google, BBC, Buzzfeed et beaucoup d’autres encore.

 

Pourquoi cette méthodologie a-t-elle été créée ?

Afin d’accélérer le processus de développement, il était indispensable de faciliter le support HTML et CSS des différents éléments de la page et de rendre le code de ces éléments plus indépendant.

Pour ce faire, la page a été divisée en différentes sections. C’est ainsi qu’est apparu le nouveau concept de bloc. Un bloc pouvait être constitué de divers éléments qui ne pouvaient pas être utilisés en dehors de ce bloc. Les états et le comportement d’un bloc et d’un élément pouvaient être spécifiés à l’aide d’un modificateur.

Ce sont autour de ces trois concepts clés que la majorité des règles furent créées. Et c’est ainsi que la méthodologie fut nommée selon l’acronyme reprenant la première lettre de ces trois concepts clés – Bloc, Elément et Modificateur.

Nous allons maintenant aller plus en détails dans chacun de ces concepts.

Le bloc

C’est un composant de page logiquement et fonctionnellement indépendant. Il est entièrement autonome et peut avoir son propre contexte : comportement, modèles, styles, documentation, etc. Les blocs peuvent être utilisés et réutilisés n’importe où sur une page et même dans un autre projet.

Certains blocs peuvent être imbriqués dans d’autres blocs, combinés ou utilisés pour créer d’autres blocs plus complexes.

L’élément

C’est une partie constitutive d’un bloc qui ne peut être utilisée en dehors de celui-ci et qui n’a d’existence que dans le cadre de son parent. Les éléments ne sont pas des composants obligatoires du bloc : très souvent, des petits blocs ne contiennent aucun élément.

Le modificateur

C’est une propriété d’un bloc ou d’un élément qui modifie leur apparence, leur état ou leur comportement.

Un modificateur possède un nom et peut avoir une valeur. L’utilisation des modificateurs est optionnelle. Chaque bloc et chaque élément peuvent avoir plusieurs modificateurs différents en même temps.

Pourquoi utiliser BEM ?

  • Utilisation de nom « parlant » pour les classes du code(auto-documentation).
  • Création d’espaces de noms
  • Indépendance des blocs. Cela signifie que le fonctionnement du code est prévisible et qu’il n’y a pas de croisements de noms.
  • Maintenance du code (modification, expansion) — simple et pas dangereuse.
  • Possibilité de créer ses propres bibliothèques de composants.
  • Aucune dépendance vis-à-vis de la structure du DOM
  • Réutilisation de blocs à travers un projet
  • Réutilisation de blocs dans différents projets

 

Les problèmes résolus par BEM

Problème N°1. Le composant est dépendant de son parent.

Il est relativement difficile, lorsqu’on lit du code CSS, de voir quel bloc dépend de quel autre. Cela résulte en une certaine imprévisibilité du comportement.

Partout vous avez :

.selector {color: red;}

Mais tout à coup, vous trouvez un :

.parent .selector {color: red;}

Et si, après, vous devez faire ce changement :

.selector {color: blue;}

Cela va vous prendre un temps considérable pour comprendre pourquoi la couleur n’a pas été modifiée partout. Et maintenant, imaginez un sélecteur constitué de 4 parties…

Dans BEM, il n’y a presque pas de cascade de ce type.

Problème N°2. Les sélecteurs complexes et spécifiques.

Plus le sélecteur est complexe ou spécifique, plus il est lié avec la structure de DOM.

Imaginons le menu déroulant suivant :

#nav ul li ul li { }

Et si vous avez besoin de réutiliser ce menu, mais cette fois-ci sans le parent #nav ?

Dans BEM, cette situation est Impossible. Seules les classes sont utilisées en qualité de sélecteur (pas d’id et pas de balise) et presque pas de cascade.

Problème N°3. Il y a trop de noms de classes généraux.

Utiliser des noms de classes généraux peut engendrer des répétitions et des héritages de style pas très évidents.


<div class="block">
    <h3 class="title">Titre</h3>
    <div class="contents">Contenu</div>
</div>
<style>
    .block {}
    .block .title{}
    .block .contents{}
</style>

Peut-on être certain qu’en aucun autre endroit, nous n’aurons pas :

.title{}
.contents{}

La superposition de styles peut provoquer de nombreux problèmes. Or, en BEM, chaque nom de sélecteur est unique.

Problème N°4. CSS est incompréhensible sans contexte (HTML).

Même si aujourd’hui vous êtes le seul développeur sur un projet donné, cela ne signifie pas qu’après vous aucune autre personne ne va intervenir sur ce code. D’autant plus, que vous pouvez vous aussi revenir sur ce projet beaucoup plus tard, et ne rien vous rappeler à son sujet.

.SbcPstW {..} /*Qu’est-ce que c’est ?*/.
/* C’est un conteneur de bas de page pour un article de blog  */
/* En utilisant BEM: */
.post {...}
...
.post__footer-wrap {...}
.post__footer-date {...}
.post__footer-tags {...}

Dans BEM, chaque nom de sélecteur indique son rôle dans HTML.

 

Bon à savoir

La méthodologie BEM implique que les blocs ne sont pas uniques et qu’ils peuvent toujours être réutilisés. C’est pour cette raison que dans la description des règles CSS, les attributs id ne sont pas utilisés.

Un bloc ne doit pas être dépendant des autres blocs autour de lui, et il ne doit pas affecter les blocs adjacents. Aussi, dans CSS, on n’utilise plus :

  • les balises ;
  • les sélecteurs imbriqués.

Règles de nommage des entités BEM

  • Chaque entité BEM doit avoir sa propre classe
  • Les propriétés CSS pour les blocs, les éléments et les modificateurs sont décrites uniquement dans les classes
  • Pour séparer les mots dans un nom, on utilise un trait d’union (-)
  • Pour séparer le nom du bloc et le nom de l’élément, on utilise deux tirets bas consécutifs (__)

<!-- .BEM-bloc -->.
<div class="tabbed-pane">
    <!-- .BEM-element -->.
    <div class="tabbed-pane__panel">...</div>
</div>
  • Selon la règle de Yandex, pour séparer le nom du bloc et le nom du modificateur, on utilise un seul tiret bas (_)

<div class="header header_christmas">...</div><!-- Christmas edition of the header -->
  • Harry Roberts, quant à lui, a proposé d’utiliser deux traits d’union (–)

<div class="header header--christmas">...</div><!-- Christmas edition of the header -->

Nous conseillons en général d’utiliser cette dernière car elle est plus claire et permet en un coup d’œil de bien voir la structure du code.

 

Conseils pratiques d’utilisation

Un bloc est un élément de page indépendant

  • Le nom de la classe doit être simple et court
  • Le nom de la classe doit répondre à la question : « Qu’est-ce que c’est ? »
  • Ne pas utiliser d’abréviations, sauf les plus courantes (button – btn, additional – add, description – descr, image – img ; picture – pic, etc.)
  • Le nom ne doit pas répondre à la question « Quelle est son apparence ? »

<!-- .BEM-block -->.
<div class="product">
    …
</div>

Les blocs peuvent et doivent être imbriqués les uns dans les autres

  • Il n’y a aucune restriction concernant l’imbrication de blocs, tant que nous ne tombons pas dans l’absurde
  • Les blocs imbriqués n’ont aucune propriété spécifique

<!-- .page-header — bloc BEM -->.
<div class="page-header">
    <!-- .logo — bloc BEM à l’intérieur d’un bloc BEM -->.
    <a class="logo"></a>
</div>

Certains composants d’une page sont toujours des blocs BEM

Tous les projets (mis à part ceux qui sont très petits ou qui ont une probabilité de modification proche de zéro) comprennent des composants qui, en raison de leur forte probabilité de réutilisation, sont toujours et judicieusement définis comme des blocs BEM.

Tout web designer professionnel utilise des composants existants pour construire de nouvelles pages.

  • Bouton
  • Blocs dans des formulaires (bloc de saisie de texte, bloc de choix, etc.)
  • Pagination
  • Tabs
  • Labels
  • Liens vers les réseaux sociaux
  • Articles dans des blogs
  • Produits dans un catalogue
  • Carrousel, etc.

L’élément est une partie du bloc BEM

  • Le nom de la classe est généré à partir du nom du bloc séparé du nom de l’élément par deux tirets bas (__)
  • Le nom de la classe doit être simple et court
  • Le nom de la classe doit répondre à la question :« Qu’est-ce que c’est ? »
  • Ne pas utiliser d’abréviations,sauf les plus courantes (button – btn, additional – add, description – descr, image – img ; picture – pic etc.)
  • Le nom ne doit pas répondre à la question « Quelle est son apparence ? »

<!-- . bloc BEM -->.
<div class="product">
    <!-- .product__image — élément BEM du bloc BEM product-->.
    <img class="product__image">
    <!-- .product__description — élément BEM du bloc BEM product-->.
    <p class="product__description">…</p>
    <!-- .product__more-link — BEM élément BEM du bloc BEM product-->.
    <a class="product__more-link" href="#">…</a>
</div>

L’élément ne doit pas être utilisé en dehors du bloc puisque

  • On perd la logique du code
  • Il est difficile de donner un style à des éléments qui peuvent se trouver à n’importe quel endroit (float, positionnement absolu et d’autres styles de cet élément peuvent « casser » la mise en page)

Il peut ne pas y avoir d’éléments

Tous les blocs ne doivent pas forcément avoir d’éléments : un bouton, par exemple,est toujours un bloc BEM, mais il est relativement rare qu’il contienne des éléments.

<!-- .Pas d’erreur : bloc sans éléments  -->.
<button class="common-btn">Télécharger</button>

Comment distinguer un bloc BEM et un élément BEM ?

Posez-vous tout simplement la question suivante : « Puis-je avoir besoin de cette entité séparément, de manière indépendante ? Ou n’aurai-je besoin d’elle qu’à l’intérieur de son parent ? » Si vous en avez besoin séparément, il s’agit alors d’un bloc BEM. Si elle n’a de sens qu’à l’intérieur de son parent, c’est un élément BEM.

En cas de doute, optez plutôt pour le bloc BEM.

Le mix est la combinaison d’un bloc BEM et d’un élément BEM sur le même nœud de DOM

N’oubliez pas que vous avez la possibilité de combiner sur une même balise aussi bien une classe de niveau élément BEM d’un bloc parent que sa propre classe du bloc BEM. Les classes de blocs BEM doivent être écrites en premier.

Il faut noter cependant qu’avec cette approche le code devient moins lisible.

Prenons un exemple.

Dans un projet, les boutons sont réalisés grâce au bloc button. Vous devez le placer dans la zone de recherche (search-form) et définir les marges du bouton. A cet effet, nous utilisons un mix du bloc button et de l’élément button du bloc search-form :


<div class="search-form">
    <button class="button search-form__button">Search</button>
</div>

Le mix nous permet d’utiliser un bouton universel qui ne sait rien des marges par rapport aux limites du formulaire concerné. Ici, le formulaire de recherche se trouve être l’élément search-form__button, qui sait où il doit se trouver ainsi que le bloc button qu’il faut afficher.

L’arborescence de BEM est plate à la différence de DOM

Dans les classes des éléments BEM, il est impossible de définir une hiérarchie, l’utilisation de deux fois ou plus deux caractères ‘__’ est interdite (un seul niveau).


<div class="promo">
    <div class="promo__description">…</div>
    <!-- . Il n’y a pas d’erreur  -->.
    <a class="promo__link" href="#">…</a>
</div>

<div class="promo">
    <div class="promo__description">…</div>
    <!-- . Il y une erreur. Tentative de création d’une hiérarchie  -->.
    <a class="promo__description__link" href="#">…</a>
</div>

Le modificateur est une classe supplémentaire pour changer l’apparence ou le comportement d’un bloc ou d’un élément

  • Le nom de la classe est généré à partir du nom du bloc (ou de l’élément) séparé du nom du modificateur par deux trait d’union (–)
  • Le nom de la classe doit être simple et court
  • Le nom de la classe doit répondre aux questions :« Qu’est-ce que c’est ? », « Qu’est-ce qu’il modifie ? », « Qu’est-ce qui différencie cette classe des autres ? »
  • Évitez d’utiliser des abréviations, sauf les plus courantes

<!-- . product—large est un BEM modificateur-->.
<div class="product product--large">
    …
</div>

Un modificateur ne peut pas être utilisé de manière isolée

La classe d’un modificateur ne doit jamais être utilisée de manière isolée, mais toujours et seulement avec la classe qu’il modifie.


<!--  Il n’y a pas d’erreur. Le modificateur va avec la classe qu’il modifie    -->.
<div class="product product--large">
    …
</div>
<!--  Il y une erreur. Modificateur sans la classe qu’il modifie    -->.
<div class=" product--large">
    …
</div>

Les imbrications de sélecteurs

  • Moins il y a de niveaux, mieux c’est
  • Il ne faut pas utiliser plus de 3 niveaux hiérarchiques (on ne compte pas les pseudo-éléments, les pseudo-sélecteurs et les MediasQueries)
  • Il faut utiliser avec parcimonie les sélecteurs d’éléments fils (>) ou sélecteurs de voisins (+)
  • Laissez toujours une ligne blanche avant le sélecteur imbriqué ou @media
  • Faites toujours une indentation supplémentaire pour les imbrications

Esperluette (&)

  • Il faut utiliser l’esperluetteseulement dans les cas suivants :
    • devant un séparateur d’élément BEM
    • devant un séparateur de modificateur BEM
    • devantun pseudo-élément ou un pseudo-sélecteur
  • Il ne faut jamais utiliser l’esperluette à l’intérieur des noms de blocs, d’éléments ou de modificateurs

.promo {
    /** Correct : l’esperluette se trouve devant une pseudo-classe **/
    & :hover { …}

    /** Correct : l’esperluette se trouve devant un séparateur d’élément BEM **/
    & __item {
        /** Pas correct : l’esperluette se trouve à l’intérieur du nom de l’élément **/
    	& -link{ …}
    }

    /** Pas correct : l’esperluette se trouve à l’intérieur d’un nom de bloc **/
    & -shover{ …}

    /** Correct : l’esperluette se trouve devant un séparateur de modificateur **/
    & --large{ …}
}

Organisation des fichiers : un bloc BEM = un fichier

Lorsque vous travaillez avec des préprocesseurs CSS, le système de fichiers fonctionne de manière très simple : chaque bloc est décrit dans son propre fichier. Le fichier avec les styles du bloc BEM doit être nommé de la même manière que le bloc.

Ce système concerne également les préprocesseurs HTML (pug, handlbars etc.).

Deux exemples d’organisation de fichiers :

src/

blocks/# dossier avec des blocs BEM

page-header/# dossier de bloc BEM page-header

img/# images que l’on utilise dans le bloc BEM

page-header.less# style de bloc BEM

page-header.pug# html de bloc BEM

page-header.js   # script de bloc BEM

page-footer/      # dossier de bloc BEM

logo/# dossier de bloc BEM

less/global/# dossier avec les styles généraux

global-fonts.less # initialisation des polices de caractère

global.less# styles body, liens, etc.

global-type.less # typographie

mixins/# dossier avec des mixins

style.less# ficher d’import de styles

variables.less# variables de projet

src/

templates/

     blocks/

         page-header.pug# html de bloc BEM

         page-footer.pug# html de bloc BEM

         logo.pug# html de bloc BEM

index.pug# html de la page

less/

    blocks/

         page-header.less# style de bloc BEM

         page-footer.less# style de bloc BEM

         logo.less# style de bloc BEM

img/# images du projet

scripts/# scripts du projet

vendor/# bibliothèques utilisées dans le projet

 

 

Un exemple simple de bas de page fait en utilisant BEM

Pour conclure, je vous propose de voir un exemple simple de bas de page fait en utilisant BEM.


<footer class="page-footer">
    <div class="page-footer__wrapper">
        <section class="page-footer__contacts">
            Address
            <a href="tel:+78125556666"><span class="page-footer__contacts-hidden">Tel.:</span>+9 999 9999
        </section>
        <section class="page-footer__social">
            <div class="social-links">
                <a class="social-link social-link--vk"href="#">Vk</a>
                <a class="social-link social-link--fb"href="#">Fb</a>
                <a class="social-link social-link--inst"href="#">Inst</a>
            </div>
        </section>
        <section class="page-footer__copyright">
            Fait à:
            <a class="page-footer__copyright-link btn"href="#">Copyright </a>
        </section>
    </div>
</footer>

Personnellement, j’utilise cette méthodologie de manière systématique depuis déjà deux ans et je peux dire que cela m’a significativement simplifié la vie. C’est vrai qu’au début, cela peut paraître rébarbatif et inhabituel à cause des noms de classes particulièrement longs et de la nécessité de nommer les classes pour pratiquement toutes les balises. Mais cette possibilité de travailler efficacement et en douceur sur de grands projets évolutifs et d’écrire un code élégant, propre et facilement maintenable vaut la peine de commencer à travailler avec la méthodologie BEM.

Et vous, avez-vous déjà utilisé cette méthode ? Seriez-vous prêt à l’adopter sur vos futurs projets ?

P.S. : J’ai repris dans cet article certains exemples et conseils utilisés par Nikolaï Gromov, un développeur russe, dans son blog. Et je le remercie ici-même pour son autorisation.

Retour d’expérience d’un projet basé sur Apache Cordova + AngularJS + Angular Material

0

Contexte du projet

Dans le cadre d’un projet de recherche et développement, nous avons été amenés à réaliser une application mobile qui vient compléter un site web déjà existant et qui contribue au partage des bonnes trouvailles du web. Les systèmes d’exploitation ciblés étaient Android et IOS, aussi bien sur smartphones que sur tablettes. Le temps imparti au développement de celle-ci était limité mais sans contrainte particulaire sur les technologies à utiliser.

 

Orientation technique

Notre choix technique c’est porté sur :

Apache Cordova

Apache Cordova est un Framework open-source développé par la Fondation Apache. Il permet de créer des applications mobiles cross-plateformes en HTML, CSS et JavaScript pour la plupart des OS du marché (Android, Amazon Fire OS, Bada, Blackberry10, Firefox OS, IOS, Ubuntu, Windows Phone 8, Windows 8, Tizen), tout en bénéficiant des fonctionnalités natives des appareils (localisation GPS, appareil photo, contacts, etc). Les applications qui en résultent sont dites « hybrides », ce qui signifie qu’elles ne sont pas vraiment natives, ni purement basées sur les langages HTML, CSS et Javascript.

 

L’adoption d’une plateforme hybride pour la conception de l’application mobile au détriment du développement natif s’est justifiée principalement pour des raisons de timing. En effet les développeurs affectés à cette tâche n’avaient que très peu d’expérience dans les langages de programmations spécifique à chaque plateformes mobiles (Objective-C, Java, C#, etc) et avec une deadline à respecter.

AngularJS

Développé par Google, AngularJS est un Framework JavaScript MVW (Model View Whatever) très puissant, riche en fonctionnalité, libre et open-source. Il est fondé sur l’extension du langage HTML par de nouvelles balises et attributs, ce qui va nous permettre de créer une application web. Il est basé sur le patron de conception MVC (Modèle, Vue, Contrôleur).

Voici quelques aspects d’AngularJs qui nous ont poussés à l’utiliser :

  • Architecture du projet : le code est modulaire et structurer grâce notamment à un ensemble de vues conceptuels : Template, Directives, Model, Scope, Module, Injection de dépendance, …
  • Data-binding bidirectionnel : les modèles et les vues se mettent à jour automatiquement dès lors qu’une modification sur un objet, auxquelles elles sont liées, survient.
  • Directives : une directive permet de créer de nouveaux éléments (attributs HTML) que l’on va pouvoir utiliser directement dans nos vue. Cale permet de factoriser du code et de faciliter la ré-utilisabilité des composants. Autre aspect positif, nos vues ne contiennent que du HTML.
  • Il existe une multitude de modules Angular disponible pouvant enrichir une application.

Angular Material

Angular Material est une librairie développer par Google et conçu pour les développeurs qui utilisent AngularJS. Ce projet fournit un ensemble de composants (menus, interfaces) et de fonctionnalités qui sont propre à une application mobile (exemple : le slide pour faire apparaître un menu, etc). Il est très facile à prendre en main et suffit amplement pour de petites applications.

 

Utilisation

Il existe une multitude de tutoriel sur comment développer en AngularJs ou Cordova, donc ce que je vous propose, c’est une petit récapitulatif sur les problèmes auxquels nous avons été confrontés tout au long du projet.

 

Dès le début du projet, nous avons été confrontés à un problème de taille : gérer l’ordre d’instanciation afin de ne charger les classes JavaScripts qu’après l’initialisation d’Apache Cordova.

 

Pour ce faire nous avons utilisé la librairie « RequireJs » (site officiel).

Au sein de notre application, nous avons créé un fichier « autoload.js » qui fait appel à la méthode « require() » qui comporte deux paramètres :

  • le premier étant un tableau contenant la liste des fichiers à instancier (on y placera la déclaration de nos contrôleurs, services, directives, filtres, helpers, …)
  • le second étant une fonction. C’est dans celle-ci qu’on va pouvoir déterminer les actions à mener. Dans notre car instancier Angular et la base de données seulement après que Cordova le soit.
    • On va pouvoir déterminer que Cordova a bien été initialisé grâce à la méthode :

 

1

 

Ce fichier « autoload.js » que l’on vient de créer doit bien évidement être charger sur la page HTML (fichier index.html), après avoir déclaré toutes les librairies nécessaires au bon fonctionnement de l’application (Cordova, AngularJs, Angular Material, jQuery, …).

 

Pendant la phase de développement, nous avons utilisé le simulateur de l’IDE (Telerik App Builder), mais lorsque nous déployer notre application sur un téléphone, le résultat obtenu ne correspondait pas du tout au rendu sur le simulateur. Et pour cause, la connexion à la base de données locale ne s’effectue pas de la même façon.

Pour gérer la connexion à la base de données sur un vrai appareil, nous utilisons le plugin Cordova: « sqlitePlugin ».

Ce qui permet de faire la différence avec le simulateur, c’est en se basant sur l’identifiant unique de l’appareil utilisé. En effet, chaque appareil à un identifiant qui lui est propre.

 

Voici un exemple de connexion à la base de données :

2

 

La dernière partie concerne l’intégration avec l’utilisation d’Angular Material. Il faut savoir que les toutes les versions d’Android ne sont malheureusement pas compatible, en effet seules les versions supérieurs ou égale à la 4.4 le sont. Il faudra utiliser d’autres librairies pour assurer la rétrocompatibilité des styles sur les anciennes plateformes.

 

Liens

Apache Cordova :

AngularJs :

Angular Material :

RequireJs :

 

angularjs

apache-cordova

Angular Material