Sélecteurs, cascade et spécificité
Sélecteurs, cascade, héritage et spécificité.
Objectifs
À la fin de cette leçon, vous saurez :
- cibler des éléments avec les sélecteurs de base et les combiner ;
- calculer la spécificité d'une règle et prédire le gagnant d'un conflit ;
- distinguer cascade et héritage — deux mécanismes souvent confondus ;
- appliquer la stratégie qui évite 90 % des guerres de styles : spécificité minimale.
🔗 Pour vous rafraîchir la mémoire : la structure d'un document HTML
Relier CSS au HTML
Une ligne dans le <head> du HTML suffit :
<link rel="stylesheet" href="styles.css">
Dans styles.css, chaque règle suit le même schéma — sélecteur puis déclarations :
selecteur {
propriete: valeur;
}
h1 { color: navy; } /* sélecteur d'élément */
.sous-titre { font-size: 18px; } /* sélecteur de classe */
#menu { background: #eee; } /* sélecteur d'identifiant */
p, li { line-height: 1.6; } /* liste de sélecteurs : s'applique aux deux */
| Sélecteur | Syntaxe | Cible | Usage |
|---|---|---|---|
| d'élément | h1 | TOUTES les balises h1 | réglages globaux |
| de classe | .sous-titre | tous les éléments portant class="sous-titre" | l'outil quotidien |
| d'identifiant | #menu | L'unique élément avec id="menu" | rarement nécessaire |
Rappel du contrat HTML : class se partage entre mille éléments, id est unique dans la page (et sert aussi d'ancre). Stratégie quasi universelle : les classes pour tout, les id réservés aux ancres.
Deux sélecteurs combinés resserrent la cible :
a.bouton { ... } /* les <a> qui ONT la classe bouton */
nav a { ... } /* les <a> DESCENDANTS d'un nav */
a:hover { ... } /* les <a> SURVOLÉS par la souris (pseudo-classe) */
li:first-child { ... } /* le premier li de sa liste */
Ces combinaisons couvrent 95 % des besoins réels ; retenez surtout element.classe, parent enfant et :hover, omniprésents dès demain.
La cascade : qui gagne quand plusieurs règles visent le même élément ?
C'est LA question centrale du CSS. Le navigateur tranche en trois temps :
- Spécificité : la règle la plus précise gagne ;
- Ordre : à spécificité égale, la dernière écrite gagne ;
- Importance (
!important) : écrase tout — à bannir hors cas exceptionnels.
La spécificité se calcule comme un score à trois chiffres :
id classe élément
(1-0-0) (0-1-0) (0-0-1)
Appliquons sur un conflit volontaire :
p { color: gray; } /* 0-0-1 */
.texte-intro { color: blue; } /* 0-1-0 → GAGNE sur <p class="texte-intro"> */
#avertissement { color: red; } /* 1-0-0 → GAGNE toujours ici */
Pour un <p class="texte-intro"> : trois règles le visent ; comparaison des scores → 0-1-0 bat 0-0-1, peu importe l'ORDRE des lignes dans le fichier. Et si DEUX règles ont exactement le même score ? Alors l'ordre départage :
a { color: blue; }
a { color: green; } /* même score → c'est CETTE ligne qui gagne */
Vérification expérimentale (le meilleur moyen d'ancrer la notion) : DevTools → onglet Styles → cliquez un élément : le navigateur y liste toutes les règles qui le visent, barrées quand elles perdent — vous voyez la cascade fonctionner sous vos yeux, avec le nom du fichier et la ligne de chaque règle.
Stratégie professionnelle explicite : rester à faible spécificité (classes simples), car chaque montée en spécificité oblige à monter ENCORE plus pour dépasser ensuite. Les feuilles de style qui commencent par des #id partout finissent en champ de ruines de !important. Spécificité minimale = styles remplaçables = code maintenable.
L'héritage : la transmission verticale
Ne confondez pas avec la cascade (qui arbitre entre règles concurrentes) : l'héritage transmet une valeur AUX DESCENDANTS quand aucune règle ne vise directement ces descendants.
Certaines propriétés héritent — celles du TEXTE, logiquement :
body {
font-family: system-ui, sans-serif;
color: #222;
line-height: 1.6;
}
/* → tout le document adopte police, couleur et interlignage,
sauf éléments ciblés explicitement */
D'autres non — celles de BOÎTE :
body { border: 1px solid black; } /* seule la balise body aura une bordure ;
ni les p, ni les h1 n'en hériteront */
C'est cohérent : une police est un trait du texte qui se transmet naturellement ; une bordure ou une marge appartient à UN élément précis. Tableau de survie :
| Hérite | N'hérite pas |
|---|---|
color, font-*, line-height, text-align | margin, padding, border, background, width |
Ce mécanisme explique pourquoi on règne depuis body : trois lignes là-haut habillent tout le site.
Exercice
- Créez
styles.csslié à votre CV : police globale via body, couleur des liens, fond du header. - Ajoutez une classe
.encadreappliquée à deux éléments différents : vérifiez qu'elle touche les deux. - Faites conflit :
p { color: black }puis.intro { color: green }sur<p class="intro">. Prédisez, vérifiez dans DevTools, identifiez la règle barrée. - Inversez l'ordre des deux règles précédentes : change-t-il quelque chose ? Pourquoi ?
- Ajoutez
header p { color: white }: quel score ? Que se passe-t-il pour un<p class="intro">DANS le header ?
Résumé
- Élément / classe / id : trois forces différentes ; classes par défaut.
- Cascade = spécificité (1-0-0 > 0-1-0 > 0-0-1), puis ordre à égalité.
- DevTools → Styles montre la cascade en action, règles barrées incluses.
- Héritage ≠ cascade : transmission verticale du texte uniquement.
- Spécificité minimale = styles remplaçables = maintenance possible.
Correction disponibleCherchez d’abord par vous-même.Voir la correction
Correction
Réponses détaillées
Question 3. Le texte est vert : 0-1-0 bat 0-0-1 quel que soit l'ordre. Dans DevTools → Styles, sélectionnez ce p : la règle p { color: black } apparaît BARRÉE, battue par .intro. Apprendre à lire cette vue, c'est arrêter de deviner pourquoi « mon CSS ne s'applique pas ».
Question 4. Aucun changement : les scores diffèrent (0-1-0 vs 0-0-1), donc l'ordre est sans effet. L'ordre ne départage QUE les scores égaux — nuance fondamentale.
Question 5. Score de header p : 0-0-2 (deux éléments). Il bat p { color: black } (0-0-1) mais PERD contre .intro (0-1-0) ! Donc un <p class="intro"> dans le header reste vert — surprise classique. La leçon cachée : ajouter des sélecteurs d'éléments pour « renforcer » ne dépasse jamais une classe. Si vous devez gagner, alignez les types de sélecteurs (.header .intro) plutôt que d'empiler — ou mieux, repensez pour éviter le conflit.
Pièges fréquents observés
- « Mon style ne s'applique pas » avant toute autre hypothèse : vérifier (1) le lien stylesheet (bon chemin ? chargé dans Réseau ?), (2) la faute de frappe sur le nom de classe, (3) la spécificité dans DevTools. Dans cet ordre.
- Le sélecteur trop précis écrit au début (« je cible large ») : il deviendra impossible à dépasser proprement. Commencez générique, resserrez seulement si besoin.