Ordre d’application (cascade) et héritage des règles en CSS

Télécharger le PDF du cours


Livret PDF du cours
Dans cette nouvelle leçon, nous allons étudier et comprendre les mécanismes de cascade et d’héritage en CSS qui sont deux mécanismes fondamentaux de ce langage.

Comprendre comment fonctionne ces mécanismes va nous permettre de savoir quelle règle CSS va être appliquée à quel élément et pourquoi et ainsi de véritablement contrôler le résultat graphique de nos pages HTML.

 

Comprendre l’importance d’établir un ordre d’application des règles CSS : le problème des conflits

Pour comprendre les mécanismes fondamentaux de cascade et d’héritage en CSS, il faut avant tout comprendre ce qu’est un conflit CSS.

Parfois, plusieurs sélecteurs différents vont nous permettre d’appliquer des styles CSS à un même élément.

Imaginons par exemple un élément p auquel on attribuerait un attribut class et un attribut id. Nous allons pouvoir appliquer des styles CSS à cet élément de trois façons évidentes différentes :

  • en utilisant un sélecteur élément ;
  • en le ciblant via son attribut class ;
  • en le ciblant via son attribut id.

Définition d'attributs class et id sur des éléments HTML

Création d'un conflit de styles en CSS

Résultat suite à un conflit CSS et ordre d'application

See the Pen Cours HTML CSS 3.6.1 by Pierre (@pierregiraud) on CodePen.

Dans l’exemple ci-dessus, par exemple, nous avons une page HTML qui contient un titre de niveau 1 et trois paragraphes. Un de nos paragraphes possède un attribut class="bigorange" tandis qu’un autre possède à la fois un attribut class="bigorange" et un attribut id="green".

Enfin, un dernier paragraphe possède à la fois un attribut class="bigorange", un attribut id="yellow" et un attribut style dans lequel nous allons directement préciser un comportement pour la propriété color qui ne s’appliquera donc qu’à cet élément.

Du côté du CSS, on cible nos éléments HTML via quatre sélecteurs : un sélecteur éléments p, un sélecteur .bigorange et deux sélecteurs #green et #yellow. Certains de nos paragraphes vont donc être ciblés plusieurs fois avec plusieurs sélecteurs différents et recevoir les styles définis dans ces différents sélecteurs.

Ici, on voit que le sélecteur p est le seul sélecteur qui définit le comportement de la propriété text-decoration tandis que le sélecteur .bigorange est le seul qui définit le comportement de la propriété font-size. Il n’y aura donc pas de conflit sur ces deux propriétés puisqu’elles ne sont définies qu’une fois en CSS pour les mêmes éléments.

En revanche, on définit un comportement différent pour la propriété color au sein de chaque sélecteur. Dans ce cas-là, il va y avoir un conflit puisque le CSS va devoir déterminer quelle valeur de la propriété appliquer pour chaque élément ciblé avec plusieurs sélecteurs.

Pour comprendre comment le CSS va procéder dans ce cas, il faut avant tout bien se persuader que le CSS (comme tout autre langage web) repose sur un ensemble de règles. Les règles définissant l’ordre de préférence d’application des propriétés définies dans différents sélecteurs sont contrôlées par un mécanisme qu’on appelle la cascade. Connaitre ces règles va nous permettre de prédire quel style sera appliqué dans telle ou telle situation.

 

Le mécanisme de cascade CSS

Il n’est pas toujours simple de prédire quels styles CSS vont s’appliquer à quel élément pour la simple et bonne raison que le CSS peut être défini à des endroits différents (dans un élément style, dans la balise ouvrante d’un élément dans un attribut style ou dans un fichier CSS séparé) et qu’on va également pouvoir appliquer des styles à un élément en particulier en le ciblant via plusieurs sélecteurs CSS différents.

Il est donc essentiel de bien comprendre comment le CSS va fonctionner pour déterminer quels styles devront être appliqués à tel élément. L’ordre de préférence et d’application d’un style va dépendre de trois grands facteurs qui vont être :

  • La présence ou non du mot clef !important ;
  • La précision du sélecteur ;
  • L’ordre de déclaration dans le code ;

A noter que ces trois facteurs vont être analysés dans l’ordre donné et que le premier va primer sur le deuxième qui va primer sur le dernier : par exemple, si une règle utilise la syntaxe !important elle sera jugée comme prioritaire peu importe la précision du sélecteur ou sa place dans le code.

Le mot clef !important

La mot clef !important sert à forcer l’application d’une règle CSS. La règle en question sera alors considérée comme prioritaire sur toutes les autres déclarations et le style sera appliqué à l’élément concerné.

Nous allons placer ce mot clef à la fin d’une déclaration CSS lorsqu’on souhaite qu’un style s’applique absolument à un élément.

Support HTML illustration de la règle CSS important

Règle CSS important

L'usage de la règle CSS important force la priorité d'un style

See the Pen Cours HTML CSS 3.6.2 by Pierre (@pierregiraud) on CodePen.

Comme vous pouvez le constater dans l’exemple ci-dessus, le fait d’ajouter !important dans la définition du comportement de la propriété color liée à notre sélecteur p fait que c’est cette définition qui s’appliquera par-dessus toutes les autres.

Ici, en particulier, vous pouvez voir que tous nos paragraphes sont rouges, même lorsque la propriété color a été définie différemment dans un sélecteur de class ou d’id et même lorsqu’un comportement différent a été précisé dans un attribut style dans la balise ouvrante d’un élément en particulier.

Le mot clef !important est donc extrêmement puissant en CSS et peut ainsi sembler très pratique et très utile aux yeux des débutants. Cependant, en pratique, nous essaierons tant que possible de nous en passer tout simplement car ce mot clef est une sorte de « joker » qui court-circuite toute la logique normale du CSS.

L’utiliser à outrance et lorsque ce n’est pas strictement nécessaire peut donc amener de nombreux problèmes par la suite comme par exemple des problèmes de styles définis autrement et qui ne s’appliqueraient pas car déjà définis avec !important ailleurs dans le code.

De manière générale, on préfèrera toujours aller dans le sens des langages et essayer de respecter et d’utiliser les normes qu’ils ont mis en place.

Le degré de précision du sélecteur

Le deuxième critère déterminant dans l’application d’un style plutôt que d’un autre va être le degré de précision du sélecteur où le style a été défini une première fois par rapport aux autres degrés de précision des autres sélecteurs où le style a été à nouveau défini.

Le sélecteur le plus précis imposera ses styles aux sélecteurs moins précis en cas de conflit.

Pour rappel, la « précision » désigne ici le fait d’identifier de manière plus ou moins unique un élément. Les sélecteurs peuvent être rangés dans l’ordre suivant (du plus précis au moins précis) :

  • Un style défini dans un attribut HTML style sera toujours le plus précis et notamment plus précis qu’un style défini avec un sélecteur CSS ;
  • Le sélecteur #id va être le sélecteur le plus précis mais sera moins précis qu’un style défini dans un attribut HTML style ;
  • Un sélecteur .class ou un autre sélecteur d’attribut* (*les autres sélecteurs d’attributs sont des sélecteurs complexes que nous étudierons plus tard) ou un sélecteur de pseudo-classe** (**nous verrons ce qu’est une pseudo-classe plus tard dans ce cours) sera moins précis qu’un sélecteur #id ;
  • Un sélecteur d’élément ou de pseudo-élément*** (***nous étudierons les pseudo éléments plus tard dans ce cours) sera moins précis qu’un sélecteur d’attribut ou de pseudo-classe.

Si deux sélecteurs différents sont au même degré de précision, alors c’est le sélecteur le plus « complet » c’est-à-dire celui qui utilisera le plus de combinateurs qui sera jugé le plus précis.

Prenons immédiatement un exemple pour illustrer cela :

Sélecteurs élément et d'attributs class et id

Degré de précision et ordre de priorité des sélecteurs CSS

La précision des sélecteurs CSS détermine leur ordre d'application

See the Pen Cours HTML CSS 3.6.3 by Pierre (@pierregiraud) on CodePen.

Ici, on voit que deux propriétés sont définies dans plusieurs sélecteurs qui servent à sélectionner le même élément : les propriétés color et font-size. Ce sont donc nos deux propriétés qui vont générer des conflits.

On commence par vérifier la présence du mot clef !important : il n’est défini nulle part ici. On passe donc au deuxième critère qui est le degré de précision.

On regarde déjà si des attributs style sont présents dans le code. C’est le cas pour notre dernier paragraphe qui possède un attribut style="color:purple". Comme la règle ne peut pas être appliquée plus précisément, on sait que ce paragraphe sera de couleur violette.

Ensuite, on s’intéresse à la présence d’attributs id. Notre troisième paragraphe possède un id="green" et le sélecteur correspondant définit la règle color : green. Ce paragraphe sera donc vert.

Ensuite, on regarde la présence de sélecteur .class ou de sélecteurs d’autres attributs ou de sélecteurs de pseudo-classes. Notre deuxième élément de liste possède deux attributs class : bigorange et petit et on va définir le comportement de la propriété font-size dans chacun des deux sélecteurs associés.

Ici, les deux sélecteurs sont des sélecteurs .class et possèdent donc le même degré de précision à priori. Il va donc falloir regarder si un sélecteur est plus complet que l’autre c’est-à-dire s’il utilise différents combinateurs pour le rendre plus précis ou pas. C’est le cas de notre sélecteur ul .petit qui va finalement nous servir à ne cibler que les éléments possédant un attribut class= "petit" contenus dans un élément ul.

L’ordre d’écriture des règles

Le troisième et dernier critère qui va nous permettre de définir quel style doit primer sur tel autre et doit donc être appliqué à un élément va tout simplement être l’ordre d’écriture d’une règle dans le code.

Ce critère va être utilisé dans le cas où plusieurs sélecteurs concurrents définissent le comportement d’une même propriété et ont la même importance et la même spécificité.

La règle ici est très simple : c’est la dernière déclaration dans le code qui primera sur des déclarations précédentes.

Regardez plutôt l’exemple suivant :

Définition d'attributs HTML pour créer un conflit de style

Cas de conflit CSS où les sélecteurs ont la même priorité

En dernier recours, l'ordre d'écriture des styles CSS détermine leur priorité

See the Pen Cours HTML CSS 3.6.4 by Pierre (@pierregiraud) on CodePen.

Ici, chacun de mes deux paragraphes possèdent deux attributs class qui vont à chaque fois définir le comportement d’une même propriété. Les sélecteurs CSS associés ont la même importance et le même degré de spécificité. Il va donc falloir regarder leur ordre d’écriture pour savoir quelles règles vont être appliquées.

Ici, le sélecteur .grand apparait après le sélecteur .petit dans le code. C’est donc la taille de texte définie dans .grand qui va être appliquée à notre premier paragraphe.

De même, le sélecteur .orange apparait après le sélecteur .bleu dans le code. Le texte de notre deuxième paragraphe sera donc orange et non pas bleu.

Notez que c’est exactement la même règle d’ordre d’écriture des styles qui va s’appliquer, à sélecteur égal, pour déterminer si ce sont les styles définis dans un élément style ou si ce sont ceux définis dans un fichier CSS séparés qui vont s’appliquer.

Ici, notre titre h1 s’affiche en orange car nous avons précisé l’élément style après l’élément link qui fait appel à notre fichier CSS dans notre fichier HTML. Les styles définis dans l’élément style seront donc lus après ceux définis dans notre fichier CSS liés et seront donc appliqués dans le cas où plusieurs sélecteurs concurrents définissent le comportement d’une même propriété et ont la même importance et la même spécificité.

Pour vous en convaincre, échangeons la place des éléments link et style dans notre code HTML et observons le résultat sur notre code HTML :

Définition d'attributs HTML pour créer un conflit de style

Cas de conflit CSS où les sélecteurs ont la même priorité

En dernier recours, l'ordre d'écriture des styles CSS détermine leur priorité

Une convention en HTML va être de toujours préciser notre élément style après notre élément link dans le code pour ne pas s’embrouiller et c’est la raison pour laquelle on retient généralement qu’à sélecteur égal les styles définis dans l’élément style sont prioritaires sur ceux définis dans un fichier CSS séparé.

Notez qu’ici notre titre h1 va toujours avoir la taille définie dans le sélecteur .petit puisqu’un sélecteur d’attribut class est toujours plus précis qu’un sélecteur élément et que ce critère de précision passe avant le critère de l’ordre d’écriture des styles dans le code.

 

L’héritage en CSS

La notion d’héritage est une autre notion fondamentale du CSS. Elle signifie que certains styles CSS appliqués à un élément vont être hérités par les éléments enfants de cet élément, c’est-à-dire par les éléments contenus dans cet élément.

Cette notion d’héritage est conditionnée par deux choses :

  • Toutes les propriétés ne vont pas être héritées pour la simple et bonne raison que cela ne ferait aucun sens pour certaines de l’être ;
  • Les éléments enfants n’hériteront des styles de leur parent que si il n’y a pas de conflit c’est-à-dire uniquement dans la situation où ces mêmes styles n’ont pas été redéfinis pour ces éléments enfants en CSS.

Pour savoir quelles propriétés vont pouvoir être héritées et quelles autres ne vont pas pouvoir l’être il va soit falloir faire preuve de logique (et bien connaitre le langage CSS), soit falloir apprendre par cœur pour chaque propriété si elle peut être héritée ou pas.

Les propriétés qui vont pouvoir être héritées sont en effet celles dont l’héritage fait du sens. Par exemple, la propriété font-family qui sert à définir un jeu de polices à utiliser pour du texte va pouvoir être hérité car il semble logique que l’on souhaite avoir la même police pour tous les textes de nos différents éléments par défaut.

En revanche, les propriétés liées aux marges par exemple ou plus généralement les propriétés de mise en page et de positionnement des éléments ne vont pas pouvoir être héritées car cela ne ferait aucun sens d’un point de vue design de rajouter une marge d’une taille définie pour chaque élément enfant.

Support HTML pour illustration de la notion d'héritage en CSS

Support CSS pour illustration de la notion d'héritage en CSS

Illustration de la notion d'héritage en CSS

See the Pen Cours HTML CSS 3.6.5 by Pierre (@pierregiraud) on CodePen.

Dans l’exemple ci-dessus, je définis un jeu de police avec la propriété font-family dans mon sélecteur html. Comme tous les éléments d’une page HTML sont des enfants de cet élément (ils sont contenus dans l’élément html) et comme la propriété font-family peut être héritée, tous les textes de ma page utiliseront la police d’écriture définie dans cette propriété sauf si une autre police est définie de manière plus précise avec un sélecteur plus précis comme c’est le cas pour mon titre h1 ici.

J’attribue ensuite une marge extérieure gauche égale à 50px à mon élément ul représentant ma liste. Ma liste sera donc décalée de 50px par rapport au bord gauche de son élément parent qui est ici l’élément body qui représente la page. Cependant, comme la propriété margin ne peut pas être héritée, les éléments de liste de vont pas hériter de ce même margin-left : 50px par défaut.

Ici, vous devez bien comprendre que la marge se calcule par rapport au début de l’élément parent. La liste entière est décalée de 50px par rapport à l’élément body mais les éléments de liste ne sont pas décalés par défaut de 50px par rapport à l’élément ul qui est leur élément parent. Pour bien illustrer cela, j’ai ajouté manuellement un margin-left : 50px au deuxième élément de liste afin de vous prouver que le premier élément de liste n’a pas hérité de la propriété margin appliquée à son élément parent ul.

Notez que le CSS nous laisse toutefois la possibilité de « forcer » un héritage pour des propriétés non héritées par défaut ou plus exactement la possibilité de définir des comportements d’héritage pour chaque propriété définie dans chaque sélecteur.

Pour faire cela, nous allons pouvoir utiliser quatre valeurs qui vont fonctionner avec toutes les propriétés CSS (elles sont dites universelles) et qui vont nous permettre d’indiquer que telle propriété définie dans tel sélecteur doit avoir le même comportement que celle définie pour l’élément parent ou pas.

Ces valeurs sont les suivantes :

ValeurSignification
inheritSert à indiquer que la valeur de propriété appliquée à l’élément sélectionné est la même que celle de l’élément parent
initialSert à indiquer que la valeur de propriété appliquée à l’élément sélectionné est la même que celle définie pour cet élément dans la feuille de style par défaut du navigateur
unsetPermet de réinitialiser la propriété à sa valeur naturelle, ce qui signifie que si la propriété est naturellement héritée elle se comporte comme si on avait donné la valeur inherit. Dans le cas contraire, son comportement sera le même que si on lui avait donné la valeur initial
revertPermet la propriété à la valeur qu’elle aurait eue si aucun style ne lui avait été appliqué. La valeur de la propriété va donc être fixée à celle de la feuille de style de l’utilisateur si elle est définie ou sera récupérée dans la feuille de style par défaut de l’agent utilisateur

En pratique, la valeur la plus utilisée parmi ces quatre va être inherit. Notez également que le support pour la valeur revert n’est pas encore acquis pour la plupart des navigateurs. Je n’ai évoqué cette valeur ici que par souci d’exhaustivité mais vous déconseille de l’utiliser pour le moment. Pour cette raison, je ne l’évoquerai plus dans la suite de ce cours.

Support HTML pour démonstration valeur inherit initial CSS

Les valeurs CSS inherit et initial et l'héritage en CSS

Résultat de l'utilisation des valeurs inherit et initial en CSS

See the Pen Cours HTML CSS 3.6.6 by Pierre (@pierregiraud) on CodePen.

Ici, on définit un h1{font-family: initial;} en CSS. Ainsi, c’est la valeur de font-family définie pour cet élément dans la feuille de style par défaut du navigateur qui va être appliquée. En l’occurrence, dans mon cas, cela va être la valeur Times.

Ensuite, on demande explicitement à ce que les éléments de liste li héritent de la valeur donnée à la propriété margin-left à leur parent. Pour notre première liste, on définit margin-left: 50px. Les éléments li vont donc également posséder une marge extérieure gauche de 50px par rapport à la liste en soi qui est leur élément parent.

Pour notre deuxième liste, en revanche, on a défini une marge gauche de 10px seulement. Les éléments de liste vont donc utiliser cette même valeur pour leur propriété margin-left et être décalés de 10px par rapport à la liste en soi.

 

Conclusion sur les mécanismes de cascade et d’héritage en CSS

Les mécanismes de cascade et d’héritage en CSS vont permettre de définir via un ensemble de règles quels styles vont être appliqués à quel élément en cas de conflit.

Ces mécanismes vont en pratique très souvent entrer en jeu. En effet, la plupart des sites sont aujourd’hui complexes et vont utiliser plusieurs feuilles de styles (fichiers CSS) différentes qui vont définir de nombreuses règles à appliquer à chaque élément.

Comprendre comment ces mécanismes fonctionnent et connaitre ces règles est essentiel et fondamental puisque cela va nous permettre de toujours obtenir le résultat visuel espéré.

Notez que la cascade et l’héritage sont le cœur même du CSS et sont en grande partie sa puissance puisque ces mécanismes vont nous permettre d’un côté de pouvoir « surcharger » des styles en utilisant des sélecteurs plus ou moins précis et de l’autre côté de transmettre des styles d’un élément parent à ces enfants et donc nous éviter de définir tous les styles voulus pour chaque élément.

2 réflexions au sujet de “Ordre d’application (cascade) et héritage des règles en CSS”

  1. Salut,
    Il me semble qu’il y ait une petite erreur.
    “ Enfin, un dernier paragraphe possède à la fois un attribut class= »bigorange », un attribut id= »green » et un attribut style dans lequel nous allons directement préciser un comportement pour la propriété color qui ne s’appliquera donc qu’à cet élément.”
    C’est un attribut id=“yellow”, non ?

Laisser un commentaire