Plongez dans la cascade

Le CSS, Cascading Style Sheets (feuilles de style en cascade), tout développeur front/intégrateur connaît. Mais quid de la cascade ?

La cascade, la genèse d’une page web

La cascade, c’est une histoire d’héritage. Si un élément (balise, classe, etc.) n’est pas surchargé, le navigateur l’affiche comme il a été défini auparavant. Si le navigateur ne trouve rien, il l’affiche comme il le veut.

Organisation

  1. User Agent, aka le navigateur
  2. user, aka la configuration personnalisée du navigateur
  3. Auteur, aka la feuille de style du site

Plutôt simple n’est-ce pas ?

Le style User Agent, vous l’avez tous vu : c’est le rendu par défaut d’une page HTML dans un navigateur. Chose étonnante : c’est loin d’être le design le plus sexy au monde, mais il reste cohérent et bien structuré.

Pour une page HTML codée par un intégrateur qui ne souffre pas de la divite aiguë, on obtient une mise en page « pas trop mal » sans CSS1.

Fonctionnement

À l’ouverture d’un site, le navigateur va l’afficher avec sa belle interface.

Cette interface, codée par un développeur front-end, est stylisée dans sa feuille de style. Parmi ces styles, on trouve régulièrement des styles provenant de normalize.css ou reset css. Pourquoi ?

Premièrement, l’expérience vous fera dire que la multiplicité des navigateurs garantit de moins en moins l’uniformité de l’apparence par défaut de chaque élément HTML.

Deuxièmement, toi derrière ton écran, utilisateur bien-aimé, tu as peut-être défini des styles personnalisés dans ton navigateur préféré.

Le but de ces outils est de remettre à zéro ou du moins d’uniformiser les styles et de sauter sans prendre de risque. Bien sûr, un développeur front-end averti prendra en compte tes styles personnalisés sans les annihiler.

Donc : User Agent/User > Reset/Normalize > style.css.
Et paf, ça fait des Chocapics.

La spécificité, qui est le plus !important ?

Ici c’est la loi du plus fort : le navigateur choisit un sélecteur parce qu’aucun n’est plus « fort » que lui. C’est sa spécificité.

À noter qu’ensuite, la cascade fait son œuvre et met tout le monde d’accord :
chaque déclaration surcharge (écrase, remplace) les déclarations comportant un sélecteur de même spécificité. Le dernier est donc le plus « fort ».

// Ligne 24
.box { background: #bada55 }
// Ligne 42
.box { background: #b000b5 }

Ici, les deux déclarations ont la même spécificité. Celle de la ligne 42 surcharge celle de la ligne 24. L’arrière-plan de l’élément de classe .box est donc de couleur #b000b5.

// Ligne 4
.container .box { background: #707020; }
// Ligne 24
.box { background: #bada55; }
// Ligne 42
.box { background: #b000b5; }

À la cascade la spécificité prévaut, qu’importe l’endroit où elle est déclarée.
Ainsi, une déclaration de spécificité plus importante prendra le pas et surchargera l’élément de classe .box, même si elle est écrite en début de fichier. Ici donc, l’élément de classe .box aura un arrière-plan de couleur #707020.

La spécificité, efficace et pas cher, c’est mon sélecteur que je préfère

Afin de mieux cerner la spécificité d’un sélecteur, voici comment la calculer :

sélecteur valeur exemple
universel 0.0.0.0.0 *
tag, pseudo-élement 0.0.0.0.1 body, article, p, :first-line
classe, attribut, pseudo-classe 0.0.0.1.0 .box, [id='foo'], :first-child
identifiant 0.0.1.0.0 #foo
déclaration inline 0.1.0.0.0 <p style="…">…</p>
Chuck Norris style 1.0.0.0.0 !important
#sidebar { } // Spécificité de 100
ul li:first-child a.active { } // Spécificité de 23
#sidebar .block.block-blue div.author > p { } // Spécificité de 132

Il est donc important d’écrire des sélecteurs efficaces, légers et de faire attention à l’ordre de déclaration.
Pourquoi ? Maintenabilité !

On ne peut donc pas surcharger un identifiant avec une classe (bien qu’il y ait encore peu de temps on pouvait cf. 256 Classes Override an ID).

Vous aurez noté que le principe même des techniques responsive repose sur le principe de cascade. Que vous choisissiez l’approche desktop-first, mobile-first ou content-first, c’est toujours une question de cascade CSS.

Ressources

Casse-tête en cascade

La gestion des ems

L’unité em étant dépendante du parent, elle peut vite devenir casse-tête.

<style>
  html { font-size: 62.5%; }
  p, b { font-size: 2em; }
</style>
<p>Beware I’m a <b>bada55</b></p>

Ici, l’élément html hérite de 62.5% de la taille de police du navigateur. Par défaut, elle est (censé être) définie à 16 pixels, mais peut être modifiée par l’utilisateur. Si ce n’est pas le cas, la font-size de l’élément <html> équivaut donc à 10 pixels.
Ensuite, l’élément p hérite de 2 fois la taille de police de son parent html, donc équivaut à 20 pixels.
Et enfin, l’élément b étant un enfant de p, sa taille de police équivaut à 2 fois 20 pixels, soit 40 pixels.

Une attention toute particulière à la cascade est donc primordiale lorsque vous travaillez en em. C’est juste une question d’habitude ;-)

Notez que l’utilisation d’unité relative comme em, rem et % est grandement conseillée pour des questions d’accessibilité.

Pour se simplifier la vie, et améliorer la maintenabilité par la même occasion, il est possible de donner une taille en rem aux containers : Font Size Idea : px at the Root, rem for Components, em for Text Elements.

Mauvaise spécificité

Penchons-nous sur le framework CSS Bootstrap.

On y compte à ce jour 1927 sélecteurs. En bon élève il n’applique aucun style sur des identifiants et dispose d’une spécificité moyenne de 20 (deux classes). On observe des résultats très similaires avec Foundation.

C’est donc louable, mais il cache sous cette moyenne quelques surprises comme par exemple .panel>.table-responsive:last-child>.table:last-child>tbody:last-child (83).

Et lorsqu’on veut/doit surcharger ce sélecteur, comment fait-on ?
Copier/coller du sélecteur et on utilise la cascade. Pas super maintenable. ‑_-v

En équipe il est préférable d’éviter ce genre de sélecteurs. Dans le cas d’un framework comme Bootstrap, ce sélecteur n’est pas idiot. Il simplifie l’usage du framework.

Bref, attention à votre spécificité ! Pensez maintenabilité !

Ne pas trop se reposer sur la cascade

Surcharger peut être utile, mais attention cependant à ne pas s’éparpiller. Vous pourriez arriver à trouver des déclarations inutiles après quelques passages.

// L15
.box {
  position: relative;
  padding: .5rem;
  background: #f3f3f3;
  border: 1px solid #bada55;
  font-family: 'Liberation Sans';
  font-size: 1rem;
}

// L450
.box {color: #333}

// L480
.box {color: #222; font-style: italic}

// L840
.box {padding: 1rem; word-wrap: break-word}

// etc.

Dans un contexte framework ou une approche OOCSS par exemple, la surcharge est utile. Dans d’autres, cela rend bien souvent votre feuille de style immaintenable.

La cascade, une fois que l’on a sauté dedans

Vous pouvez donc l’exploiter comme vous voulez. Si vous souhaitez travailler avec des identifiants, à votre aise. Il y a toutefois deux approches dans ce cas : la violente #monId, ou la douce [id="monId"] (IE7). Personnellement, je fais plus dans la douceur.

Vous pouvez également préférer utiliser les classes, ou même les balises et pseudo-classes uniquement (histoire de passer votre temps à jouer avec +, ~, >, :). Cette dernière approche est sympathique ; on joue à l’équilibriste, on met parfois plus de temps, mais c’est à chaque fois un petit défi.

Attention toutefois, il est préférable de faire l’équilibriste sur des side projects : paradoxalement à la spécificité, utiliser des tags et pseudo-classes uniquement diminue la compréhension des sélecteurs, et donc la maintenabilité.

Existe-t-il un plan de bataille ?

Oui, !important all the things !

Il existe diverses méthodes pour se faciliter la vie et ainsi obtenir une feuille de style consistante et maintenable. On retrouve des acronymes comme BEM, OOCSS, SMACSS, Atomic CSS, AMCSS

Pour mieux comprendre ce que ça implique dans vos feuilles de style (DRY, spécificité, poids, etc.), OpenWeb nous a proposé un excellent article qui compare ces approches : Des approches en vogue confrontées aux principes.

Conclusion

La cascade, c’est coule ! ;-P

8 commentaires sur cet article

  1. Pascal (@eQRoeil), le jeudi 18 décembre 2014 à 08:49

    Bonjour,

     » la font-size de l’élément équivaut donc à 10 pixels.
    Ensuite, l’élément p hérite de 2 fois la taille de police de son parent html, donc équivaut à 32 pixels.
    Et enfin, l’élément b étant un enfant de p, sa taille de police équivaut à 2 fois 32 pixels, soit 64 pixels. »

    si la taille de police sur html est équivalente à 10px alors c’est 20 pour p et 40 pour b

  2. Frank Taillandier, le jeudi 18 décembre 2014 à 18:32

    Il y a 10 ans déjà, Marc écrivait sur le sujet : https://marcarea.com/tuto/css-comprendre-la-cascade/

  3. Knuc, le vendredi 19 décembre 2014 à 10:28

    Un article qui n’apporte rien, déjà lu et relu ce genre d’article.
    Perte de temps.

  4. Jb Audras, le vendredi 19 décembre 2014 à 15:12

    Knuc : merci pour ce commentaire inestimable. Aigreur quand tu nous tiens :O

  5. Nico, le vendredi 19 décembre 2014 à 15:20

    Knuc : pourquoi commentes-tu cet article ? Tu devrais utiliser ton temps précieux pour trouver un vaccin contre le manque d’amabilité, et l’auto-tester. Enfin, c’est une idée.

    Merci pour cet article les gars, toujours bon à rappeler. :)

  6. Phil, le vendredi 19 décembre 2014 à 15:22

    Merci pour ces éclaircissements toujours bons à lire :-)

  7. Enguerran, le vendredi 19 décembre 2014 à 15:24

    Vérifier tout l’internet avant de partager un savoir que l’on a. Histoire de ne pas froisser ces omniscients qui peuvent perdre leur temps en relisant quelque chose qu’ils connaissent par cœur. Ce par cœur qui leur en enlève, du cœur. Car plutôt qu’une rétrospective permettant de faire avancer le sujet et les lecteurs, ils n’ont qu’une petite pointe de venin à injecter dans les commentaires afin de prouver une bonne fois pour toute qui est le roi ici bas.

  8. Matthieu, le vendredi 19 décembre 2014 à 15:53

    @Knuc > Un sujet effectivement déjà vu mais souvent demandé, comme ici. Tout développeur Web, front ou back, devrait savoir tout ça. Une pointe rappelle via un autre biais qui améliorera peut-être la compréhension des uns, confirmera la connaissance des autres. C’est tout l’intérêt.
    Si ce sujet ne t’intéresse pas, que fais-tu ici ?