CSS — Sélecteurs, spécificité et cascade¶
Nous entrons ici dans le CSS approfondi. Jusqu’à présent, nous avons ciblé les éléments par leur type (p, h1…) ou par une classe simple. Mais le CSS offre une grammaire de ciblage bien plus riche, qui permet d’atteindre précisément le bon élément sans alourdir le HTML. Ce chapitre couvre cette grammaire — les sélecteurs — puis les deux mécanismes qui décident quelle règle l’emporte lorsque plusieurs s’appliquent : la spécificité et la cascade.
Rappel : les sélecteurs de base¶
Avant les sélecteurs avancés, remettons en place les quatre fondamentaux.
Sélecteur |
Cible |
Exemple |
|---|---|---|
Type |
Toutes les balises d’un type |
|
Classe |
Éléments portant une classe |
|
ID |
Élément portant un ID unique |
|
Universel |
Tous les éléments |
|
Classe et ID : lequel pour quoi ?¶
La classe (.ma-classe) est réutilisable sur plusieurs éléments et constitue l’outil préféré pour le style :
.button { padding: 10px 20px; }
.button-primary { background: blue; color: white; }
L”ID (#mon-id) est unique dans la page et possède une spécificité élevée, donc difficile à surcharger. On le réserve au JavaScript et aux ancres :
#unique-header { font-size: 32px; }
Cette préférence pour les classes n’est pas une lubie : elle découle directement de la spécificité, que nous détaillons plus bas.
Sélecteurs de combinaison¶
Les combinateurs expriment une relation entre éléments. Ils permettent de dire « tel élément, mais seulement à l’intérieur de tel autre », ou « juste après tel autre ».
Sélecteur |
Nom |
Cible |
|---|---|---|
|
Descendant |
Tous les B dans A (à n’importe quel niveau) |
|
Enfant direct |
B enfant immédiat de A |
|
Voisin adjacent |
B immédiatement après A (même parent) |
|
Voisins généraux |
Tous les B après A (même parent) |
/* Tous les <p> dans <article>, peu importe la profondeur */
article p { line-height: 1.6; }
/* Les <li> enfants directs de <ul> uniquement */
ul > li { list-style: disc; }
/* Le premier <p> placé juste après un <h1> */
h1 + p { font-size: 1.2em; }
La nuance entre A B et A > B est subtile mais utile : le premier descend à tous les niveaux, le second se limite aux enfants directs. Sur des structures imbriquées (un menu dans un menu, par exemple), cette distinction évite bien des effets de bord.
Pseudo-classes — l’état des éléments¶
Une pseudo-classe cible un élément selon un état particulier (survolé, en focus…) ou sa position parmi ses voisins. On la reconnaît à son : unique.
Les pseudo-classes d”interaction réagissent à l’utilisateur :
Pseudo-classe |
Cible |
Exemple |
|---|---|---|
|
Survol de la souris |
|
|
Élément ayant le focus |
|
|
Élément activé (clic) |
|
:focus mérite une attention particulière : c’est l’état d’un champ ou d’un lien atteint au clavier (touche Tab). Le styliser correctement est une question d’accessibilité — supprimer le contour de focus sans le remplacer rend un site inutilisable au clavier.
Les pseudo-classes structurelles ciblent selon la position dans le parent :
Pseudo-classe |
Cible |
Exemple |
|---|---|---|
|
Premier enfant |
|
|
Dernier enfant |
|
|
n-ième enfant |
|
Un usage très courant de :nth-child est le « zébrage » d’un tableau, qui alterne la couleur des lignes pour en améliorer la lisibilité :
tr:nth-child(odd) {
background: white;
}
tr:nth-child(even) {
background: #f5f5f5;
}
even (paires) et odd (impaires) sont des mots-clés pratiques, mais :nth-child() accepte aussi des formules comme 3n (un sur trois).
Pseudo-éléments — des parties d’éléments¶
Un pseudo-élément (noté avec un double ::) cible une partie d’un élément, ou crée du contenu décoratif qui n’existe pas dans le HTML.
Pseudo-élément |
Cible |
Exemple |
|---|---|---|
|
Contenu inséré avant |
|
|
Contenu inséré après |
|
|
Première ligne |
|
|
Première lettre |
|
Un cas typique : signaler automatiquement les liens externes par une petite icône, sans rien ajouter au HTML.
a[href^="http"]::after {
content: " 🔗";
}
Important : ::before et ::after n’affichent rien tant qu’on ne leur fournit pas une propriété content, même vide (content: ""). C’est l’oubli le plus fréquent avec ces pseudo-éléments.
Sélecteurs d’attributs¶
On peut aussi cibler les éléments d’après leurs attributs, et même d’après le début, la fin ou une portion de leur valeur.
Sélecteur |
Cible |
|---|---|
|
Éléments possédant l’attribut |
|
Attribut de valeur exacte |
|
Attribut commençant par value |
|
Attribut finissant par value |
|
Attribut contenant value |
Ces sélecteurs sont précieux pour styliser sans toucher au HTML :
/* Tous les liens externes (commencent par http) */
a[href^="http"] { color: blue; }
/* Tous les liens vers un PDF (finissent par .pdf) */
a[href$=".pdf"]::after { content: " 📄"; }
/* Tous les champs obligatoires */
input[required] { border-left: 3px solid red; }
Le moyen mnémotechnique vient des expressions régulières : ^ marque le début (« commence par »), $ marque la fin (« finit par »), * une présence quelconque (« contient »).
Spécificité CSS¶
Quand plusieurs règles ciblent le même élément avec des valeurs contradictoires, le navigateur doit trancher. Le premier critère est la spécificité : le « poids » d’un sélecteur.
Type de sélecteur |
Valeur |
Exemple |
|---|---|---|
Éléments, pseudo-éléments |
1 |
|
Classes, attributs, pseudo-classes |
10 |
|
IDs |
100 |
|
Styles inline |
1000 |
|
|
∞ |
|
On additionne les poids des éléments du sélecteur pour obtenir sa spécificité totale :
p { color: blue; } /* 1 → un élément */
.intro p { color: red; } /* 11 → une classe + un élément */
#content p { color: green; } /* 101 → un ID + un élément */
#content .intro p { color: purple; } /* 111 → l'emporte */
Plus la spécificité est élevée, plus la règle est prioritaire. C’est précisément pourquoi on évite de styliser via les id : avec leur poids de 100, ils écrasent les classes et deviennent pénibles à surcharger.
⚠️ Évitez !important : il court-circuite tout le système et complique durablement la maintenance. Quand on en arrive à empiler des !important pour se surpasser soi-même, c’est le signe que la structure des sélecteurs est à revoir.
La cascade CSS¶
La cascade est la procédure complète de résolution des conflits. Elle applique trois critères, dans cet ordre :
L’importance : une déclaration
!importantl’emporte sur les autres.La spécificité : à importance égale, le sélecteur le plus spécifique gagne (ID > classe > élément).
L’ordre d’apparition : à spécificité égale, la dernière règle définie l’emporte.
Ce troisième point explique un comportement souvent déroutant des débutants :
p { color: blue; }
p { color: red; } /* ← c'est celle-ci qui s'applique */
Les deux règles ont la même spécificité ; la seconde étant écrite après, c’est elle qui gagne. Retenez l’ordre : importance, puis spécificité, puis position. La plupart des « bizarreries » du CSS s’expliquent par l’un de ces trois critères.