Les classes CSS sont probablement le meilleur ami de l’intégrateur web, mais peuvent vite devenir un cauchemar si la réflexion ne précède pas l’action. Au-delà des conventions de nommage plus ou moins sémantiques, il existe de nombreuses stratégies pour mettre en place une architecture CSS modulable et évolutive. Un temps décriées au profit des identifiants uniques pour de viles questions de performances, les classes reprennent du poil de la bête. Sans forcément tomber dans la «classite» aiguë, voyons rapidement différentes manières d’organiser nos feuilles de style CSS.
Exemple 1
Exemple de code permettant d’appliquer un style commun aux éléments commençant par .btn-
et de décliner des styles spécifiques pour .btn-left
ou .btn-right
. Larry Botha dans About HTML semantics and front-end architecture.
[class*="btn-"] { } // Styles génériques .btn-small { } // Diminuer font-size .btn-medium { } // Taille par défaut .btn-large { } // Augmenter font-size .btn-primary { } // Faire flotter le bouton à gauche .btn-secondary { } // Faire flotter le bouton à droite .btn-left { } // Ajouter une icône à gauche des boutons .btn-right { } // Ajouter une icône à droite des boutons
Exemple 2
On peut aussi s’inspirer du modèle d’architecture de l’exemple précédent en jouant sur les classes multiples :
.btn { } // Styles génériques pour les boutons .icon-right { } // Ajouter une icône à droite de n'importe quel élément .icon-left { } // Ajouter une icône à gauche de n'importe quel élément .btn.icon-right { } // Ajouter une icône à droite du bouton .btn.icon-left { } // Ajouter une icône à gauche du bouton
Exemple 3
Autre manière d’application d’un style générique à un élément .item
déclinable selon le contexte. Rapide et pratique, cette solution présente tout de même l’inconvénient de ne pas être totalement scalable si vous décider de créer un nouveau contexte tel que #header .item {}
.item {} // styles génétiques pour item #cart .item { } // styles spécifiques pour item dans le contexte du panier #category .item { } // styles spécifiques pour item dans le contexte des catégories #product .item { } // styles spécifiques pour item dans le contexte des produits
Pour rendre ce dernier exemple plus scalable et plus performant (en évitant d’obliger le navigateur de boucler sur trop de sélecteurs), on pourrait utiliser :
.item { } .item-cart { } .item-category { } .item-product { }
L’approche des classes multiples est moins performante mais permet de modulariser votre feuille de style de manière plus fine. A condition toutefois d’en avoir vraiment besoin. En effet, leur utilisation se traduit forcément par une intrusion accrue des classes CSS dans le code HTML et nécessite plus de règles dans la feuille de style, ce qui peut manquer de… classe !
.item { } .cart { } .category { } .product { } .item.cart { } .item.category { } .item.product { }
Pour aller plus loin
- Organiser ses classes CSS — Comment ça, il n’existe pas de consensus sur l’organisation des feuilles de style CSS ?
- SMACSS — Scalable and Modular Architecture for CSS. A flexible guide to developing sites small and large. (cf. SMACSS — Architecture évolutive et modulaire pour CSS
- About HTML semantics and front-end architecture — Covers HTML semantics, components and approaches to front-end architecture, class naming patterns, and HTTP compression.
- Writing efficient CSS selectors —
The difference in speed between an ID and a class is almost totally irrelevant.
J’aime beaucoup l’exemple 1 avec :
[class*= »btn-« ] { }
Ca fonctionne correctement sur les anciens IE ?
A priori, les sélecteurs d’attributs fonctionnent correctement à partir de IE7
Hi Bruno,
Thanks for referencing my comment on Nicholas’s site!
I’ve slightly modified the way I write those classes now. Being a universal selector,
[class*=btn-]
can have a bit of impact on the speed at which it is processed, since it requires DOM traversal of every single element to check if they contain some class beginning withbtn-
.Writing efficient CSS selectors is an excellent article by Harry Roberts, and was one of a few articles that inspired me to change my ways.
Another issue is that because it’s universal, it can introduce problems should I happen to use a class starting with
btn-
, but want it to be unrelated to the behaviour of all the other buttons. I wouldn’t want to create such a class, but it doesn’t feel right targeting classes I haven’t explicitly selected for.What I do now is the following:
.btn {} /* generic class - .btn-primary is implied here, but not explicitly created */
So buttons would look so:
button primary
button secondary
Here’s a jsfiddle to illustrate how I now write the classes.
argh, all broken :/
Here’s my fiddle:
http://jsfiddle.net/mousepotatoweb/uAkgg/
Hi Larry,
Thanks for your feedback. What do you think about multiple classes to do the (almost) same task?
By the way, thanks for the link you provide, I’ve add it within the ressources section.
I’ve found that chaining classes as in your examples can be very useful, and have used it in a few of our projects.
There are things to be aware of, however. Chaining classes results in dependency, among other issues, which takes away from OOCSS modularity. I now prefer to keep my selectors as simple as possible, and name them according to the concept to which they specifically belong:
/* buttons styles */
.btn {...}
.btn-right {...}
.btn-left {...}
/* icon styles */
.icon {...}
.icon-right {...}
.icon-left {...}
I can now add
.btn-right
and.icon-right
to an element without having to worry about fixing how a.right
class may behave when combined with both.btn
and.icon
.This has resulted in a number of benefits over projects where I have chained classes:
– selectors don’t have to be overriden with ‘stronger’ selectors;
– adding and removing classes will have fewer unexpected side effects (dependency);
– classes indicate exactly which concept they belong to;
– CSS is much easier to manage; and
– finding and fixing issues is faster
This comes down to preference, though, and is how I work at the moment.