Mettre ensemble cascade, héritage, spécificité et importance pour résoudre n'importe quel conflit CSS.
Pour résoudre n'importe quel conflit, suis ces 5 étapes dans l'ordre :
MÉTHODE EN 5 ÉTAPES :
━━━━━━━━━━━━━━━━━━━━━
ÉTAPE 1 — ORIGINE
┌─────────────────────────────────────────┐
│ D'où vient la règle ? │
│ User-Agent / User / Author │
└───────────────────┬─────────────────────┘
▼
ÉTAPE 2 — IMPORTANCE
┌─────────────────────────────────────────┐
│ La déclaration a-t-elle !important ? │
│ Si OUI → phase !important séparée │
└───────────────────┬─────────────────────┘
▼
ÉTAPE 3 — SPÉCIFICITÉ
┌─────────────────────────────────────────┐
│ Calcule le score (a, b, c, d) │
│ IDs / Classes / Éléments │
└───────────────────┬─────────────────────┘
▼
ÉTAPE 4 — ORDRE SOURCE
┌─────────────────────────────────────────┐
│ En cas d'égalité totale : │
│ la dernière déclaration gagne │
└───────────────────┬─────────────────────┘
▼
ÉTAPE 5 — HÉRITAGE
┌─────────────────────────────────────────┐
│ Si aucune règle ne cible l'élément : │
│ héritage du parent OU valeur initiale │
└─────────────────────────────────────────┘
Algorithme complet de résolution des conflits CSS
/* Pour chaque propriété conflictuelle, pose-toi ces questions : */
/* 1. Combien de règles s'appliquent à l'élément pour cette propriété ? */
/* 2. Quelle est l'origine de chaque règle ? */
/* 3. Laquelle a !important ? */
/* 4. Calcule la spécificité de chaque sélecteur */
/* 5. Si égalité → regarde l'ordre source */
/* 6. Si aucune règle → héritage ou valeur initiale */
/* On peut noter rapidement : */
/* IDs : N */
/* Classes + pseudo-classes + attributs : N */
/* Éléments + pseudo-éléments : N */
/* !important : ★ */
/* Exemple : #header .nav li a::before !important
→ IDs:1, Cls:1, Élm:2, ★
→ (1, 1, 2) + !important */
| Sélecteur | IDs | Classes | Éléments | Total |
|---|---|---|---|---|
* |
0 | 0 | 0 | 0 |
p |
0 | 0 | 1 | 1 |
p span |
0 | 0 | 2 | 2 |
.a |
0 | 1 | 0 | 10 |
.a .b |
0 | 2 | 0 | 20 |
.a .b .c |
0 | 3 | 0 | 30 |
#x |
1 | 0 | 0 | 100 |
#x .a |
1 | 1 | 0 | 110 |
#x .a p |
1 | 1 | 1 | 111 |
:hover |
0 | 1 | 0 | 10 |
[type="text"] |
0 | 1 | 0 | 10 |
::before |
0 | 0 | 1 | 1 |
:is(#a, .b) |
1 | 0 | 0 | 100 |
:where(#a, .b) |
0 | 0 | 0 | 0 |
style="" |
— | — | — | inline |
┌──────────────────────────────────────────────────────────────────┐ │ CALCULATEUR DE PRIORITÉS │ ├──────────────────────────────────────────────────────────────────┤ │ │ │ Colonne A (inline) Colonne B (IDs) │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ 0 ou 1 │ │ nombre d'#' │ │ │ └──────────────┘ └──────────────┘ │ │ │ │ Colonne C (classes) Colonne D (éléments) │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ .classe │ │ p, div, span │ │ │ │ :pseudo │ │ ::pseudo-élm │ │ │ │ [attribut] │ │ │ │ │ └──────────────┘ └──────────────┘ │ │ │ │ Spécial : │ │ ┌──────────────────────────────────────────┐ │ │ │ !important → phase séparée (surpasse tout)│ │ │ │ :is() → prend le max des arguments │ │ │ │ :where() → toujours 0 │ │ │ │ :has() → prend le max des arguments │ │ │ └──────────────────────────────────────────┘ │ │ │ │ Comparaison : (a,b,c,d) vs (a',b',c',d') │ │ → Comparer a vs a', puis b vs b', etc. │ │ → La première colonne qui diffère détermine le gagnant │ └──────────────────────────────────────────────────────────────────┘
Schéma du calculateur de priorités CSS
Arbre de décision pour résoudre un conflit :
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Conflit détecté sur une propriété
│
▼
Les règles ont-elles des origines différentes ?
├── OUI → L'origine la plus haute gagne
│ (Author > User > User-Agent)
└── NON ↓
│
Certaines règles ont-elles !important ?
├── OUI toutes → comparer spécificité
├── NON toutes → comparer spécificité
└── Mixte → !important gagne toujours
│
▼
Comparer les scores (a,b,c,d)
├── Plus grand score gagne
└── Scores égaux ↓
│
Ordre source : la dernière déclaration gagne
│
▼
Valeur déterminée ✓
Guide de résolution de conflit complet
Résolution détaillée
/* HTML : <p class="a b">Test</p> */
.a { color: red; } /* (0,0,1,0) = 10 */
.b { color: blue; } /* (0,0,1,0) = 10 */
/* Résolution :
1. Même origine : author ✓
2. Pas de !important ✓
3. Spécificité : 10 vs 10 → égalité
4. Ordre source : .b vient en dernier
→ color: blue gagne */
Résolution détaillée
#id { color: red !important; } /* (1,0,0) + !important */
.cls { color: blue !important; } /* (0,1,0) + !important */
/* Résolution :
1. Même origine : author ✓
2. Les deux ont !important → phase !important
3. Spécificité : (1,0,0) vs (0,1,0)
→ 100 vs 10 → ID gagne
→ color: red gagne */
Résolution détaillée
/* Feuille base.css */
p { color: black; } /* (0,0,0,1) = 1 */
/* Feuille theme.css */
p { color: blue; } /* (0,0,0,1) = 1 */
/* <style> dans le HTML */
p { color: green; } /* (0,0,0,1) = 1 */
/* Inline */
<p style="color: orange;"> /* inline */
/* Résolution :
1. Même origine : author ✓
2. Pas de !important ✓
3. Spécificité : 1 vs 1 vs 1 → égalité
4. Ordre source : inline gagne (dans le DOM, c'est le dernier nœud)
→ color: orange gagne */
Exercice 1 : Deux éléments
p { color: red; } /* (0,0,0,1) = 1 */
span { color: blue; } /* (0,0,0,1) = 1 */
/* HTML : <p><span>Test</span></p> */
/* Quelle couleur a le texte "Test" ? */
Réponse : blue — le span est ciblé
directement par span, le p hérite. Le span
a sa propre règle avec même score, mais c'est le
span qui reçoit color: blue directement.
Exercice 2 : Classe vs élément
.texte { color: red; } /* (0,0,1,0) = 10 */
p { color: blue; } /* (0,0,0,1) = 1 */
/* HTML : <p class="texte">Test</p> */
Réponse : red — la classe (10) gagne
sur l'élément (1).
Exercice 3 : ID vs classe
#titre { color: red; } /* (0,1,0,0) = 100 */
.titre { color: blue; } /* (0,0,1,0) = 10 */
/* HTML : <p id="titre" class="titre">Test</p> */
Réponse : red — l'ID (100) gagne sur
la classe (10).
Exercice 4 : Ordre source
.a { color: red; } /* (0,0,1,0) = 10, premier */
.b { color: blue; } /* (0,0,1,0) = 10, dernier */
/* HTML : <p class="a b">Test</p> */
Réponse : blue — même spécificité, la
dernière règle (.b) gagne.
Exercice 5 : Deux classes vs un ID
.a .b { color: red; } /* (0,0,2,0) = 20 */
#c { color: blue; } /* (0,1,0,0) = 100 */
/* HTML : <p class="a b" id="c">Test</p> */
Réponse : blue — l'ID (100) gagne sur
deux classes (20).
Exercice 6 : !important vs ID
.texte { color: red !important; } /* 10 + !important */
#titre { color: blue; } /* 100 sans !important */
/* HTML : <p id="titre" class="texte">Test</p> */
Réponse : red — !important surpasse la
spécificité de l'ID.
Exercice 7 : !important vs !important
#a { color: red !important; } /* (1,0,0) + !important */
.b { color: blue !important; } /* (0,1,0) + !important */
/* HTML : <p id="a" class="b">Test</p> */
Réponse : red — les deux ont
!important, c'est la spécificité qui départage (100 > 10).
Exercice 8 : Sélecteur composé
nav .menu a { color: red; } /* (0,0,1,2) = 12 */
nav a { color: blue; } /* (0,0,0,2) = 2 */
a { color: green; } /* (0,0,0,1) = 1 */
/* HTML : <nav><div class="menu"><a href="#">Lien</a></div></nav> */
Réponse : red —
nav .menu a a la spécificité la plus élevée (12 > 2 >
1).
Exercice 9 : Pseudo-classe
.link { color: blue; } /* (0,0,1,0) = 10 */
a:hover { color: red; } /* (0,0,1,1) = 11 */
/* HTML : <a href="#" class="link">Survole-moi</a> */
Réponse : Au repos : blue (même score
mais .link et a ont le même poids, ici
c'est l'ordre source). Au survol : red (11 > 10).
Exercice 10 : :is() vs :where()
:is(#id, .cls) { color: red; } /* (1,0,0) = 100 */
:where(#id, .cls) { color: blue; } /* (0,0,0) = 0 */
/* HTML : <p id="id" class="cls">Test</p> */
Réponse : red —
:is() prend la spécificité du plus spécifique (100),
:where() est toujours 0.
Exercice 11 : :has() hérite la spécificité
.card:has(.featured) { border: 2px solid gold; } /* (0,0,2,0) = 20 */
.card { border: 1px solid gray; } /* (0,0,1,0) = 10 */
.card:has(#special) { border: 3px solid red; } /* (0,1,1,0) = 110 */
/* HTML : <div class="card featured" id="special">...</div> */
Réponse : red —
.card:has(#special) a la spécificité la plus élevée
(110 > 20 > 10).
Exercice 12 : Conflit complexe multi-règles
/* CSS */
body p { color: black; } /* (0,0,0,2) = 2 */
.texte { color: red; } /* (0,0,1,0) = 10 */
#main .texte { color: blue; } /* (0,1,1,0) = 110 */
p.texte { color: green; } /* (0,0,1,1) = 11 */
/* HTML : <body><div id="main"><p class="texte">Test</p></div></body> */
Réponse : blue —
#main .texte a la spécificité la plus élevée (110).
Exercice 13 : Héritage + !important
body { color: red !important; } /* hérité par les enfants */
.texte { color: blue; } /* (0,0,1,0) = 10, pas de !important */
/* HTML : <body><p class="texte">Test</p></body> */
Réponse : red — le !important hérité
du body ne peut être écrasé que par un autre !important.
Exercice 14 : Scénario complet
/* base.css (chargé en 1er) */
* { color: black; } /* (0,0,0,0) = 0 */
/* theme.css (chargé en 2ème) */
p { color: blue; } /* (0,0,0,1) = 1 */
/* <style> dans le HTML */
.texte { color: green; } /* (0,0,1,0) = 10 */
/* Feuille override.css (chargée en 3ème) */
p.texte { color: orange !important; } /* (0,0,1,1) + !important */
/* Inline */
<p class="texte" style="color: purple;">Test</p>
/* Résolution :
1. Les 4 règles sont de type author
2. override.css a !important → phase !important
3. Les autres : inline (spécificité max) mais pas !important
4. !important gagne sur non-!important
→ color: orange gagne ! */
Réponse : orange — le !important dans
override.css bat le style inline car le style inline
n'a pas de !important.
Exercice 15 : Calcul de score complet
Calcule le score et détermine le gagnant :
#page #main .content p.intro::first-line { color: red; }
/* IDs: 2, Classes: 2, Éléments: 2 (p + ::first-line) */
/* Score : (0, 2, 2, 2) = 222 */
#main .content p.intro { color: blue; }
/* IDs: 1, Classes: 2, Éléments: 1 */
/* Score : (0, 1, 2, 1) = 121 */
/* 222 > 121 → rouge gagne */
Exercice 16 : Le piège du sélecteur universel
* { color: red; } /* (0,0,0,0) = 0 */
* * { color: blue; } /* (0,0,0,0) = 0 */
* * * { color: green; } /* (0,0,0,0) = 0 */
* * * * * * * * * * { color: yellow; } /* (0,0,0,0) = 0 */
/* HTML : <div><p><span>Test</span></p></div> */
/* Tous les scores sont 0 → c'est l'ordre source qui départage */
/* La dernière règle gagne → color: yellow */
Exercice 17 : Debugging réaliste
/* Un développeur se plaint que son style ne s'applique pas : */
/* Il veut que les liens dans .sidebar soient rouges */
.sidebar a { color: blue; } /* (0,0,1,1) = 11 */
/* Son collègue a ajouté : */
#sidebar .nav-link { color: green; } /* (0,1,1,1) = 111 */
/* Le lien a la classe "nav-link" et est dans #sidebar */
/* Question : pourquoi le bleu ne marche-t-il pas ? */
/* Réponse : le sélecteur du collègue a une spécificité plus élevée (111 > 11)
Solution : augmenter la spécificité de .sidebar a ou réfactoriser */
Exercice 18 : :where() comme solution
/* Refactoriser avec :where() pour rendre les styles surchargeables */
:where(.sidebar) a { color: blue; } /* (0,0,0,0) = 0 */
.sidebar .nav-link { color: green; } /* (0,0,2,0) = 20 */
/* Maintenant il est facile de surcharger le style de .sidebar
avec un sélecteur de classe simple */
/* FAUX : croire que 10 classes (100) battent 1 ID (100) */
.a .b .c .d .e .f .g .h .i .j { } /* (0,10,0,0) → c'est bien 100 */
#seul { } /* (0,1,0,0) → c'est bien 100 */
/* EN RÉALITÉ : la comparaison se fait colonne par colonne */
/* (0, 10, 0, 0) vs (0, 1, 0, 0) */
/* En colonne b : 10 > 1 → les classes gagnent... sauf que
en CSS standard, un ID bat toujours N classes.
Les specifications définissent que si la colonne b d'un sélecteur
est > 0 et celle de l'autre est aussi > 0, on compare.
Si un sélecteur a un ID et l'autre non, l'ID gagne. */
/* Les transitions et animations CSS ont une priorité
supérieure à !important pendant leur exécution */
.anime {
animation: slide 0.3s ease;
}
@keyframes slide {
from { transform: translateX(0); }
to { transform: translateX(100px); }
}
/* Même avec transform: none !important sur l'élément,
l'animation continuera de s'appliquer pendant l'exécution */
/* L'héritage n'est JAMAIS en compétition avec la spécificité */
.parent { color: red; } /* défini sur le parent */
.enfant { color: blue; } /* défini directement sur l'enfant */
/* Le style direct de .enfant gagne toujours sur l'héritage du parent,
même avec une spécificité plus faible.
L'héritage n'est que le DERNIER recours. */
Projet : Débugger une page avec 10 conflits
Crée une page HTML intentionallement cassée avec des conflits de cascade, puis corrige-les :
Conflits à créer puis résoudre :
Objectif : Pour chaque conflit, documenter dans un commentaire le score de chaque sélecteur et expliquer pourquoi le style actuel gagne.
Quiz rapide
#header .nav li a::before
* ?
:is() et :where() ont-ils le même
effet ?
:not() ?
:not() a la spécificité de son argument le plus
spécifique.
┌─────────────────────────────────────────────────────────────┐ │ CHEAT SHEET — CASCADE CSS │ ├─────────────────────────────────────────────────────────────┤ │ │ │ SPÉCIFICITÉ (de bas en haut) : │ │ ───────────────────────────── │ │ * → (0,0,0) = 0 │ │ p, div, span → (0,0,1) = 1 │ │ .classe, :hover → (0,1,0) = 10 │ │ #id → (1,0,0) = 100 │ │ style="" → (1,0,0,0) = inline │ │ !important → phase séparée (surpasse tout) │ │ │ │ :is() → prend la spécificité du plus spécifique │ │ :where() → toujours (0,0,0) = 0 │ │ :has() → prend la spécificité du plus spécifique │ │ │ │ ORIGINES (de bas en haut sans !important) : │ │ ───────────────────────────────────────────── │ │ User-Agent (navigateur) │ │ User (utilisateur) │ │ Author (développeur) │ │ │ │ AVEC !important → l'ordre s'INVERSE : │ │ Author !important > User !important > UA !important │ │ │ │ HÉRITAGE : │ │ ───────── │ │ Héritées : color, font-*, line-height, text-*, cursor │ │ NON héritées : margin, padding, border, width, background │ │ Mots-clés : inherit, initial, unset, revert │ │ │ │ RÈGLES D'OR : │ │ ───────────── │ │ 1. Garder la spécificité basse │ │ 2. Éviter les IDs pour le CSS │ │ 3. Utiliser !important uniquement pour les utilitaires │ │ 4. Utiliser :where() pour les defaults │ │ 5. Utiliser :is() pour des sélecteurs concis │ │ 6. Résoudre les conflits en corrigeant la cause │ └─────────────────────────────────────────────────────────────┘
Résumé complet de toutes les règles de la cascade CSS