Dans l'article précédent, nous avons vu les différents sélecteurs CSS. Au fur et à mesure de leur utilisation, il pourra arriver que plusieurs règles, plusieurs sélecteurs s'appliquent au même élément. Dans un tel scénario, quelle règle CSS sera appliquée à l'élément ? Pour répondre à cette question, nous aurons besoin de voir les concepts de cascade et d'héritage. Dans cet article, nous traitons de la cascade, du poids des sélecteurs et de la façon dont les propriétés héritent les unes des autres selon les différentes règles.
CSS signifie Cascading Style Sheets (ce qui signifie « feuilles de style en cascade »). L'acronyme de CSS met donc en avant la notion de cascade. Pour simplifier à l'extrême, la cascade indique l'ordre d'importance des règles CSS. Analysons plus en détails ce que cela signifie.
La cascade
La mise en forme finale d'un élément peut ếtre obtenue grâce à plusieurs règles présentes à plusieurs endroits et qui interagissent de façon complexe. C'est cette complexité qui rend CSS si puissant mais c'est également une source de confusion et de difficultés lorsqu'il s'agit de résoudre des problèmes.
Quatre sources d'informations principales forment cette cascade. Ces sources sont:
- Les styles par défaut du navigateur pour le langage à balise utilisé
- Les styles liés au document par l'utilisateur (en HTML, cela correspond aux éléments
<link>
ou<style>
qui pointent vers les feuilles de style) - Les styles définis par l'utilisateur qui consulte le document
- Les styles définis par l'auteur qui sont directement appliqués depuis les éléments (en HTML, cela correspond à utiliser l'attribut
style
)
Chaque source surcharge les autres, dans cet ordre. Les styles définis par les auteurs surchargent les styles par défaut du navigateur, les styles définis par les utilisateurs surchargent les styles définis par les auteurs et les styles « individuels » des éléments surchargent les styles des utilisateurs. Voici la règle générale de la cascade, si vous souhaitez en explorer les détails, veuillez lire notre article dédié à la cascade CSS.
CSS permet de marquer certaines propriétés comme étant importantes. Ces propriétés, quel que soit l'endroit de la cascade où elle se situent, surchargeront les autres. Cela casse la cascade naturelle et l'utilisation d'un tel marquage est donc considéré comme une mauvaise pratique.
body { color: pink !important; }
Le poids des sélecteurs
Les règles de la cascade s'appliquent pour prioriser les différentes sources. Que se passe-t-il si, pour une même source, plusieurs règles concernent le même élément ? Dans ce cas, pour prioriser les règles, on prendra en compte le poids du sélecteur. Le poids d'un sélecteur est calculé en fonction de sa spécificité :
- Niveau 1 : Sélecteur d'identifiant
- Niveau 2 : Sélecteur de classe, de pseudo-classe et d'atttribut
- Niveau 3 : Sélecteur de type et de and Pseudo-element selectors
Le sélecteur universel (*
), les combinateurs (+
, >
, ~
, ' ') et la pseudo-classe de négation (:not
) n'ont aucun effet sur la spécificité d'un sélecteur.
Pour déterminer si une règle s'applique plutôt qu'une autre on regarde :
- celle qui possède le plus de sélecteurs de niveau 1
- si le nombre de sélecteurs de niveau 1 est le même : celle qui possède le plus de sélecteurs de niveau 2
- si le nombre de sélecteur de niveau 2 est le même : celle qui possède le plus de sélecteurs de niveau 3
- enfin, si les sélecteurs ont le même poid, ce sera l'ordre des règles dans le fichier source qui importera : la règle la plus basse dans le fichier l'emportera sur une règle déclarée avant.
Prenons ce fragment de HTML par exemple :
<p id="cookie" class="crispy">Ce cookie est <span>délicieux !</span></p>
Poids de niveau 1
Cette feuille de style illustre ce qui se passe lorsqu'un sélecteur de niveau 1 entre en conflit avec d'autres sélecteurs :
<p id="cookie" class="crispy">Ce cookie est <span>délicieux !</span></p>
/* Ce sélecteur est composé d'un sélecteur de niveau 1 Poids : 1 | 0 | 0 */ #cookie { color: green; } /* Ce sélecteur n'a aucun sélecteur de niveau 1 et 2 sélecteur de niveau 2 Poids : 0 | 2 | 0 */ [id=cookie].crispy { color: red; } /* 1|0|0 > 0|2|0 : La première règle s'applique et le texte est vert. Un seul sélecteur de niveau 1 sera toujours prioritaire par rapport à X sélecteurs de niveau 2. */
Le résultat obtenu est donc :
Au vu de ce « poids », certains développeurs web considèrent qu'utiliser des sélecteurs d'identifiant est une mauvaise pratique. Mieux vaut éviter d'utiliser plus d'un sélecteur d'identifiant par règle.
Poids complexe
Dans l'exemple précédent, nous avons utilisé la notation x|y|z
pour indiquer le poids de chaque sélecteur. Cette notation permet de comparer les poids des sélecteurs simplement : en comparant chaque colonne, en commençant par celle de gauche. Voyons un exemple plus complexe où cette notation est appréciable :
<p id="cookie" class="crispy">Ce cookie est <span>délicieux !</span></p>
/* 0|1|1 Zéro sélecteur de niveau 1 Un sélecteur de niveau 2 (.crispy) Un sélecteur de niveau 3 (span) On rappelle ici que le combinateur > n'a aucun impact pour calculer le poids */ .crispy > span { color: red; } /* 0|1|2 Zéro sélecteur de niveau 1 Un sélecteur de niveau 2 (:nth-child) Deux sélecteurs de niveau 3 (p, span) */ p span:nth-child(1) { color: red } /* 0|1|2 Zéro sélecteur de niveau 1 Un sélecteur de niveau 2 (:nth-child) Deux sélecteurs de niveau 3 (p, em) Là aussi, le sélecteur universel (*) et la pseudo-classe :not pseudo-class ne comptent pas (mais le sélecteur em avec :not est compté) */ p *:nth-child(1):not(em) { color: green } /* La première règle a un poids inférieur. Les deux règles qui suivent ont le même poids. C'est donc l'ordre du code qui importent et la dernière règle surchargera la deuxième */
L'héritage
L'héritage en CSS est le dernier morceau du puzzle pour comprendre comment un style est appliqué à un élément. L'héritage s'applique de deux façons et chacune a son importance : le mélange des règles et l'héritage entre propriétés.
Le mélange des règles
Lorsque plusieurs règles correspondent au même éléments, elles s'appliquent toutes à cet élément. Nous avons vu avec la cascade comment déterminer quelle règle surcharge quelle autre. Cette surcharge ne concerne que les propriétés en conflit, sinon, toutes les règles sont appliquées.
Prenons un exemple :
Voici le code HTML :
<p>Je suis<strong> important</strong></p>
Appliquons cette feuille de style CSS :
/* 0|0|2 */ p strong { background-color: khaki; color: green; } /* 0|0|1 */ strong { text-decoration: underline; color: red; } /* À cause de son poids, la première règle surcharge la propriété color de la deuxième règle. Toutefois, la couleur d'arrière plan fournie par la première règle et la décoration fournie par la seconde s'appliquent à l'élément strong. Vous verrez également que le texte de l'élément est mis en gras grâce aux styles par défaut du navigateur. */
Le résultat obtenu est le suivant :
L'héritage entre propriétés
L'héritage entre propriétés est un peu plus subtil. Certaines propriétés appliquées à un élément peuvent hériter de la valeur d'un des éléments parents. Cela permet par exemple de déterminer la valeur qui sera appliquée pour la propriété d'un élément quand aucune n'est fournie (la valeur du parent se « propage » à l'élément enfant). L'héritage permet d'avoir à éviter de définir toutes les règles pour tous les éléments à chaque fois.
L'héritage peut avoir lieu pour toutes les propriétés mais certaines sont héritées « naturellement » comme color
ou font-family
. La valeur basique, par défaut, est définie par la feuille de style du navigateur, toutes les propriétés qui héritent « naturellement » prendront cette valeur par défaut si rien d'autre n'est spécifié.
Pour savoir si l'héritage d'une propriété CSS est naturel, consultez notre référence CSS.
CSS fournit trois valeurs spéciales pour gérer l'héritage :
inherit
: cette valeur indique que la valeur de la propriété de l'élément sera la même que la valeur de la propriété de l'élément parent (c'est la valeur par défaut pour tous les éléments dont l'héritage est naturel).initial
: cette valeur indique que la valeur de la propriété de l'élément sera la valeur définie par la feuille de style du navigateur (si la valeur n'est pas définie par la feuille de style du navigateur et que l'héritage de cette propriété est naturel, la valeur définie sera alors une copie de l'héritage naturel plutôt qu'inherit
. Les effets de bords engendrés peuvent être plutôt subtils et nous ne les verrons pas ici).unset
: cette valeur réinitialise la propriété avec sa valeur natuelle. Cela signifie que si la propriété est héritée naturellement, on aura le même effet qu'inherit
, sinon on aura le même effet qu'avecinitial
.
C'est la valeur inherit
qui va nous intéresser le plus ici car elle permet de déclarer explicitement l'héritage de la propriété d'un élément par rapport à son parent.
Illustrons ce concept avec un exemple :
Voici le code HTML utilisé :
<ul> <li>Couleur par défaut <a href="#">pour le lien</a></li> <li class="inherit">Couleur héritée <a href="#">pour le lien</a></li> <li class="initial">Couleur réinitialisée <a href="#">pour le lien</a></li> <li class="unset">Couleur non définie <a href="#">pour le lien</a> color</li> </ul>
Et voilà la feuille de style CSS appliquée :
/* On définit la couleur verte pour le corps. La propriété color est naturellement héritée, tous les fils de l'élément body auront donc cette même couleur verte */ body { color: green; } /* On remarquera ici que le navigateur fixe la couleur du lien (bleu) plutôt que d'utiliser l'héritage naturel de la propriété color. C'est pour cette raison que le premier lien de notre exemple est bleu.*/ /* Ici, on déclare explicitement que le lien contenu dans un élément héritera de son parent (ici pour propriété color). Cela signifie ici que la couleur du lien sera héritée de celle de son parent, l'élé- ment li, qui hérite naturellement de celle de ul, qui hérite naturellement de celle de l'élément body et c'est celle-ci qui est verte (comme on l'indique avec la règle précédente).*/ .inherit a { color: inherit; } /* Avec cette règle, pour tous les liens contenus dans un élément dont la classe vaut initial, on définit leur couleur avec la valeur initiale. Généralement la couleur initiale des textes du navigateur est noire. */ .initial a { color: initial } /* Enfin, pour tous les liens qui sont contenus dans un élément de classe unset, on utilise unset. La propriété color étant naturellement héritée, cela est équivalent au résultat obtenu avec inherit. On a donc, dans ce cas, des liens qui ont la même couleur que le corps : vert.*/ .unset a { color: unset; }
Le résultat obtenu est le suivant :
La suite
Félicitations, vous commencez à plonger dans toute la profondeur et la richesse de CSS. Vous connaitrez bientôt tous les concepts qui gouvernent CSS, vous pouvez d'ores et déjà commencer à étudier CSS en pratique. Si vous souhaitez parcourir les dernières étapes de ce chemin théorique, vous pouvez continuer cette série pour découvrir le modèle de boîte CSS pour manipuler la disposition du contenu en CSS.