Cascade CSS et priorité des sélecteurs

Openweb.eu.org > Articles  > Cascade CSS et priorité des sélecteurs

Abstract

CSS signifie « feuilles de styles en cascade »... Mais au fait, la cascade, qu’est-ce que c’est, à quoi ça sert, comment cela fonctionne ? Plongez avec nous dans la cascade sans risque de noyade !

Article

Les styles CSS appliqués finalement à une page Web ont de multiples origines simultanées : styles utilisateurs et styles par défaut de l'agent utilisateur s'ajoutent aux différentes feuilles de styles éventuellement prévues par l'auteur, pour structurer ses CSS en modules, offrir des styles alternatifs ou styler ses documents pour différents medias. La question-clé est donc le mode de combinaison de ce large éventail de styles possibles. C'est ici qu'interviennent le fonctionnement en cascade propre aux CSS et le calcul de la priorité respective des différents sélecteurs susceptibles de viser le même élément XHTML.

Les sources de style possibles

Trois séries de styles CSS d'origines différentes sont susceptibles d'être concurrentes ou combinées pour un même élément (X)HTML :

Les feuilles de style ont trois origines différentes : l'auteur, l'utilisateur et l'agent utilisateur (alias le navigateur).

Les champs d'action de ces trois feuilles de style vont se recouper, leur interaction dépendant des règles de la cascade.

La cascade de CSS définit un ordre de priorité, ou poids, pour chaque règle de style. Quand plusieurs règles sont mises en oeuvre, celle avec le plus grand poids a la préséance.

Prenons l'exemple des liens a d'un menu de navigation du type :

<ul id="menu">

<li><a href="...">lien 1</a></li>
<li><a href="...">lien 2</a></li>
<li><a href="...">lien 3</a></li>

</ul>
Voyons comment vont être déterminés la couleur de ces liens, celle de leur arrière-plan, leur graisse et leur soulignement éventuel pour un utilisateur donné ayant réglé son navigateur selon ses préférences personnelles, à partir des styles fixés par l'auteur de la page en question.

Commençons par établir la liste de tous les styles susceptibles de s'appliquer à ces liens :

  • Les styles par défaut des navigateurs graphiques sont du type :

    a {
    display: inline;
    color: blue;
    text-decoration: underline;
    }
    
  • Une feuille de style auteur, permanente pour tous les medias, peut avoir spécifié des règles générales pour tous les liens de la page (ici, la mise en gras remplaçant le soulignement) :

    <style type="text/css" media="all">
      a {
      text-decoration: none !important;
      font-weight: bold;
      }
    </style>
    
  • Une autre feuille de style auteur, pour le seul media screen, peut avoir ajouté des règles propres aux liens du menu de navigation contenu dans la page (ici, arrière-plan noir, texte blanc, graisse normale). Cette feuille correspond, dans un choix de styles alternatifs, au style « préféré », c'est-à-dire appliqué par défaut lorsque l'utilisateur ne sélectionne pas l'un des autres styles proposés :

    <style type="text/css" media="screen" title="Style1">
      #menu a {
      background-color: black;
      color: white;
      font-weight: normal;
      }
    </style>
    
    Note : —

    Cet exemple, ainsi que le précédent, fait appel à l'élément style. Mais il en serait de même pour ce qui touche à la cascade CSS et à l'ordre de priorité des sélecteurs si ces styles étaient liés au document avec l'élément link ou l'instruction xml-stylesheet. D'autre part, le cas des styles auteur inclus via l'attribut style des éléments HTML est examiné ci-dessous.

  • L'utilisateur peut avoir modifié la couleur des liens dans les options de son navigateur, et forcé le soulignement, ce qui donnera l'équivalent de :

    a {
    color: black !important;
    background-color: white !important;
    text-decoration: underline;
    }
    

Il apparaît immédiatement que plusieurs règles de styles, issues de l'agent utilisateur, de l'utilisateur lui-même ou de l'auteur de la page, entrent en concurrence pour déterminer :

  • La couleur des liens et de leur arrière-plan: bleu (agent utilisateur), blanc sur fond noir (auteur) ou noir sur fond blanc (utilisateur) ?
  • Le soulignement des liens : souligné (agent utilisateur et utilisateur) ou non (auteur) ?
  • La graisse : gras (styles généraux, auteur) ou non (styles propres au menu, auteur) ?

Tout d'abord, une sélection en 3 étapes

Pour chaque élément de l'arbre du document, et donc en particulier pour les liens a de notre menu de navigation, les moteurs de rendu CSS des navigateurs procèdent à une sélection par étapes des styles à retenir :

Etape 1 : le tri par media

Les styles potentiels de nos liens seront tout d'abord sélectionnés en fonction du media de restitution de la page. Ce media peut être explicite dans le mode de liaison de la feuille de style (la feuille de style auteur screen ci-dessus), ou implicite (absence de type de media ou media all comme ci-dessus).

Pour l'affichage à l'écran (screen), tous les styles ci-dessus du navigateur, de l'auteur et de l'utilisateur seront pris en compte. En revanche, une feuille de style auteur print, handheld ou projection ne serait pas prise en compte. De même, une propriété voice-family, propre au media oral speech serait ici écartée.

A ce stade, les propriétés retenues pour nos liens sont donc, avec leurs différentes valeurs possibles :

  • display ;
  • text-decoration ;
  • color et background-color ;
  • font-weight.

Etape 2 : le tri par origine

Ces différents styles vont à présent être sélectionnés en fonction de leur origine : les styles auteur, utilisateur et agent utilisateur ont en effet des poids différents, qui dépendent également de l'utilisation de la propriété !important. Ils se placent dans l'ordre suivant, du plus faible au plus fort :

  1. Styles par défaut de l'agent utilisateur, qui seront écrasés par tous les styles suivants ;
  2. Styles normaux de l'utilisateur (c'est à dire qui n'ont pas été marqués !important) ;
  3. Styles normaux de l'auteur (idem) ;
  4. styles de l'auteur marqués !important ;
  5. styles de l'utilisateur marqués !important, qui écraseront tous les styles précédents.

Nous rencontrons ici la valeur !important, qui peut être ajoutée dans un document CSS à n'importe quelle propriété, sur le modèle PROPRIETE: VALEUR1 !important, lui donnant alors la priorité sur une règle PROPRIETE: VALEUR2. Notons que CSS2.0 modifie CSS1.0, en donnant une plus forte priorité aux règles !important de l'utilisateur qu'aux règles !important de l'auteur. L'utilisateur peut ainsi toujours imposer ses préférences stylistiques en dernier ressort.

Passons en revue les différents styles de nos liens, par propriété :

  • display : l'auteur et l'utilisateur n'ayant rien spécifié pour cette propriété, le display: inline par défaut du navigateur est seul en lice, et va donc s'appliquer.
  • text-decoration : l'auteur ayant marqué le non-soulignement comme !important, sa règle l'emporte donc sur le soulignement voulu par les styles par défaut de l'agent utilisateur, mais aussi sur le soulignement forcé par l'utilisateur, celui-ci ne l'ayant pas marqué comme étant !important. Les liens ne seront donc pas soulignés :

  • color et background-color : cette fois, ce sont les couleurs de texte et d'arrière-plan marquées comme !important par l'utilisateur qui vont l'emporter sur celles de l'auteur.
  • font-weight : les deux styles de l'auteur restent concurrentes pour la graisse : celui de sa feuille de style générale (gras) et celui de sa feuille de style spécifique (normal). C'est à l'étape suivante que va s'effectuer le choix entre ces deux possibilités.

Etape 3 : le tri par priorité calculée des sélecteurs

Les styles restant en concurrence ont un degré de priorité variable, dépendant du sélecteur CSS utilisé et de sa syntaxe. Ce degré de priorité est calculé sous forme d'un nombre à 4 chiffres ABCD :

  • A : A=1 s'il ne s'agit pas d'un sélecteur CSS mais d'un attribut style. Sinon, A=0. De cette manière, un style placé dans l'attribut style d'un élément HTML aura systématiquement un poids plus élevé qu'un style auteur placé dans une feuille de style (ABCD = 1000, la plus haute valeur possible) ;
  • B : si A vaut 0, B est le nombre d'ids présents dans le sélecteur. Par exemple, B=2 pour le style #conteneur p#special {...} ;
  • C : si A vaut 0, C est le nombre de classes (du type .ma_classe) et de pseudo-classes (du type [hreflang=en]) dans le sélecteur. Par exemple, C=2 pour le style .article p a[hreflang=en] {...} ;
  • D : si A vaut 0, D est le nombre d'éléments HTML et de pseudo-éléments (du type :before et :after, :first-line, etc) dans le sélecteur. Par exemple, : D=2 pour le style a:after {...}.

Voici quelques exemples de sélecteurs et de règles CSS classés par ordre croissant de spécificité :

  1. * {...} : 0000 (aucun identifiant, aucune classe, aucun élément) ;
  2. p {...} : 0001 (aucun identifiant, aucune classe, un élément) ;
  3. blockquote p {...} : 0002 (aucun identifiant, aucune classe, deux éléments) ;
  4. .class {...} : 0010 (aucun identifiant, une classe, aucun élément) ;
  5. p.class {...} : 0011 (aucun identifiant, une classe, un élément) ;
  6. blockquote p.class {...} : 0012 (aucun identifiant, une classe, deux éléments) ;
  7. #id {...} : 0100 (un identifiant, aucune classe, aucun élément) ;
  8. p#id {...} : 0101 (un identifiant, aucune classe, un élément) ;
  9. blockquote p#id {...} : 0102 (un identifiant, aucune classe, deux éléments) ;
  10. .class #id {...} : 0110 (un identifiant, une classe, aucun élément) ;
  11. .class p#id {...} : 0111 (un identifiant, une classe, un élément) ;
  12. blockquote.class p#id {...} : 0112 (un identifiant, une classe, deux éléments) ;
  13. <p style="..."> : 1000 (attribut HTML style qui ne sera supplanté que par un style utilisateur normal) ;
  14. <p style="... !important"> : 1000 (attribut HTML style marqué !important qui ne sera supplanté que par un style utilisateur lui-même marqué !important).

Si nous revenons à notre exemple des styles de liens, nous pouvons calculer le degré de priorité des deux sélecteurs qui restaient en concurrence :

  • a a un degré de priorité de 0001 (un nom d'élément) ;
  • #menu a a un degré de priorité de 0101 (un identifiant et un élément).

Le deuxième sélecteur l'emporte, et les liens du menu seront donc en graisse normale.

Et en dernier ressort

Si, parvenu à ce stade, deux styles de même degré de priorité restent en concurrence, le dernier apparu dans l'ordre linéaire CSS-HTML l'emporte. Autrement dit, toutes choses étant égales par ailleurs :

  • Les règles CSS située « après » dans une feuille de style l'emportent sur celles situées « avant » ;
  • Les règles CSS contenues dans des feuilles de styles incorporées à la page Web « après » l'emportent sur celles incorporées « avant ».

Conclusion

  • Les styles de l'agent utilisateur n'agiront que dans les domaines où rien n'est spécifié par l'auteur ou l'utilisateur ;
  • Les styles !important de l'utilisateur l'emportent sur tous autres styles, mais pas ses styles normaux : les auteurs ne devraient donc pas abuser de la règle !important ;
  • Dans une combinaison de feuilles de style, !important donne plus de poids que n'importe quelle accumulation d'id, de classes ou de noms d'éléments ;

    Internet Explorer 5.x et 6.0 a cependant ici un bug portant sur la répétition d'une même propriété dans le même bloc, qui a donné lieu à un hack permettant de différencier les styles appliqués par IE de ceux appliqués par Firefox, Opera, Safari, etc :

    
    foo {
    color: red !important;
    color: blue;
    }
    

    Le comportement normal (respecté par Opera, Firefox,Safari, etc.) serait ici l'affichage en rouge, puisque le style !important est prioritaire, quel que soit l'ordre des propriétés. Mais Internet Explorer ignore dans ce cas !important, et ne retient que la dernière propriété dans l'ordre du code : le texte concerné par ce style sera donc affiché en bleu.

    Ce hack peut être utilisé en particulier pour indiquer à Internet Explorer des propriétés de dimensions compatibles avec son modèle de boîte CSS propriétaire et son implémentation défectueuse des propriétés de hauteur et de largeur minimales, etc. cependant, le risque potentiel est qu'une propriété utilisateur elle-même dénuée de !important ne sera alors pas prioritaire sur la propriété auteur ;

  • Un seul id donne à un sélecteur plus de poids que n'importe quelle accumulation de classes ou de noms d'éléments ;
  • Une seule classe donne à un sélecteur plus de poids que n'importe quelle accumulation de noms d'éléments ;
  • La présence de combinateurs + (sélecteurs d'éléments adjacents) ou > (sélecteurs d'enfants) n'a aucune influence sur la spécificité.

À propos de cet article

  • Openweb.eu.org
  • Profil : Débutant, Expert
  • Technologie : CSS
  • Thème : Mise en page
  • Auteur :
  • Publié le :
  • Mise à jour : 21 novembre 2013
  • 7 commentaires

Vos commentaires

  • ThomasG Le 20 avril 2013 à 16:47

    Merci de corriger cette erreur de typo
    idenfifiant => identifiant

  • Pascale Lambert Charreteur Le 22 avril 2013 à 12:56

    Ah ah ! excellent... 8 ans qu’elle est en ligne cette erreur, et personne pour s’en apercevoir ! Merci Thomas ! :)

  • tzi Le 20 novembre 2013 à 14:22

    Merci pour cet article très complet !
    Thomas.

    PS : Il semble y avoir une faute d’accord sur la première phrase : "à un page Web".

  • Nicolas Le 7 janvier 2014 à 01:20

    Sans aucun doute le tutoriel le plus clair du web concernant les priorités. Félicitations.

  • Erwann Le 5 août 2014 à 14:06

    Bonjour,
    dans la section tri par origine, il manque
    Styles par défaut de l’agent utilisateur marqués !important , qui surclassent les styles auteur et user marqués !important.
    L’ !important permet d’inverser l’ordre des priorités.

  • yannick Le 13 janvier 2016 à 19:43

    Ca y est j’ai compris la méthode de selection et les prioritées dans les styles CSS ! Merci, super article, clair et synthetique.

  • test Le 23 septembre 2017 à 14:37

    merci pour ton article, bon courage

Vos commentaires

modération a priori

Attention, votre message n’apparaîtra qu’après avoir été relu et approuvé.

Qui êtes-vous ?
Ajoutez votre commentaire ici

Ce champ accepte les raccourcis SPIP {{gras}} {italique} -*liste [texte->url] <quote> <code> et le code HTML <q> <del> <ins>. Pour créer des paragraphes, laissez simplement des lignes vides.

Suivre les commentaires : RSS 2.0 | Atom