Sélecteurs, spécificité, cascade et héritage
Écrire « tous les paragraphes en vert » est simple. Mais comment dire « uniquement le titre du premier projet » ou « les liens du menu, quand on passe dessus » ? Et que se passe-t-il quand deux règles se contredisent ? Cette leçon répond à ces questions : vous apprendrez à cibler les éléments avec précision, et à comprendre pourquoi le navigateur choisit une règle plutôt qu’une autre. C’est l’une des notions les plus importantes du CSS.
Les sélecteurs de base
| Sélecteur | Cible | Exemple |
|---|---|---|
| Élément | Tous les éléments de ce type | p { … } |
| Classe | Les éléments portant cette classe | .carte { … } |
| Identifiant | L’unique élément portant cet id | #contact { … } |
| Universel | Tous les éléments | * { … } |
| Groupe | Plusieurs sélecteurs à la fois | h1, h2, h3 { … } |
Pour utiliser un sélecteur de classe, on ajoute l’attribut class aux éléments HTML, puis on écrit un point suivi du nom dans le CSS :
<article class="carte">…</article>
<article class="carte carte-vedette">…</article>
.carte {
background-color: white;
}
.carte-vedette {
border: 2px solid #e0a96d;
}
Un élément peut avoir plusieurs classes séparées par des espaces, et une même classe peut servir à autant d’éléments que vous voulez. L’id, en revanche, doit être unique dans la page. Privilégiez les classes pour le style : elles sont réutilisables et leur poids est plus faible, ce qui évitera des conflits.
Les combinateurs : cibler selon la position
On peut combiner des sélecteurs pour exprimer la relation entre éléments :
- Descendant (espace) :
nav acible les liens situés n’importe où dans unnav; - Enfant direct (
>) :ul > licible lesliqui sont des enfants immédiats d’unul; - Frère adjacent (
+) :h2 + pcible le paragraphe qui suit directement unh2; - Frères suivants (
~) :h2 ~ pcible tous les paragraphes frères qui suivent unh2.
nav a {
text-decoration: none;
}
.carte > h3 {
margin-top: 0;
}
h2 + p {
font-size: 1.125rem;
}
Les pseudo-classes : cibler un état ou une position
Une pseudo-classe commence par deux-points et décrit un état ou une situation :
:hover: le pointeur survole l’élément ;:focuset:focus-visible: l’élément a le focus clavier (nous y reviendrons au chapitre 5) ;:first-child,:last-child,:nth-child(2n): sélection selon la position ;:not(.cache): tout ce qui n’a pas cette classe ;:checked,:disabled,:required,:valid,:invalid: états de formulaire.
a:hover {
text-decoration: underline;
}
tbody tr:nth-child(even) {
background-color: #f0ebe2;
}
input:invalid {
border-color: #b3261e;
}
Les pseudo-éléments, eux, utilisent deux deux-points et ciblent une partie d’un élément : ::first-line (première ligne), ::first-letter (première lettre), ::before et ::after (du contenu généré, nous les rencontrerons plus tard).
Les sélecteurs d’attribut
On peut aussi cibler un élément d’après un attribut : a[href^="https"] sélectionne les liens dont l’adresse commence par « https », input[type="email"] les champs de type email, a[target="_blank"] les liens qui s’ouvrent dans un nouvel onglet.
Plusieurs règles, un seul gagnant : la cascade
Que se passe-t-il quand deux règles s’appliquent à un même élément avec des valeurs différentes ? Le mot « cascade » du nom CSS répond : le navigateur applique un ordre de priorité. Il compare, dans l’ordre :
- l’origine et l’importance : les styles du navigateur sont les plus faibles, puis viennent ceux de l’auteur du site (vous), et la mention
!importantinverse les priorités ; - la spécificité du sélecteur : plus un sélecteur est précis, plus il pèse ;
- l’ordre d’apparition : à spécificité égale, la dernière règle écrite l’emporte.
Calculer la spécificité
On peut se représenter la spécificité comme un score à trois chiffres (ID, classes, éléments) :
| Sélecteur | ID | Classes, attributs, pseudo-classes | Éléments |
|---|---|---|---|
p | 0 | 0 | 1 |
.carte | 0 | 1 | 0 |
nav a:hover | 0 | 1 | 2 |
#contact | 1 | 0 | 0 |
#contact .bouton | 1 | 1 | 0 |
On compare colonne par colonne en commençant par la gauche : un seul identifiant bat n’importe quel nombre de classes, et une seule classe bat n’importe quel nombre d’éléments. Le style en ligne (attribut style) pèse encore plus lourd. Le sélecteur universel * et la pseudo-classe :where() ne comptent pour rien.
p { color: black; } /* spécificité 0-0-1 */
.intro { color: darkgreen; } /* spécificité 0-1-0 : gagne */
p.intro { color: navy; } /* spécificité 0-1-1 : gagne encore */
Un paragraphe <p class="intro"> sera donc bleu marine, quel que soit l’ordre des trois règles.
Attention
Évitez !important. Il fait gagner une déclaration à tout prix, mais oblige ensuite à utiliser lui-même !important pour la contredire : la feuille devient ingérable. Évitez aussi les sélecteurs trop longs (body main section article div p span) : ils sont fragiles et difficiles à surcharger. Une simple classe suffit presque toujours.
L’héritage
Certaines propriétés sont héritées : si vous les appliquez à un élément, ses descendants les reçoivent automatiquement. C’est le cas de color, font-family, font-size, line-height ou text-align. Vous avez déjà vu l’effet : en réglant font-family sur body, toute la page change de police sans que vous ayez à cibler chaque élément.
D’autres propriétés ne sont pas héritées, comme margin, padding, border ou background : ce serait absurde que chaque enfant d’une boîte reçoive à son tour la même bordure. Trois mots-clés permettent de piloter ce comportement :
inherit: hérite de la valeur du parent ;initial: revient à la valeur par défaut de la propriété ;unset: agit commeinheritsi la propriété est héritée, sinon commeinitial.
a {
color: inherit; /* le lien reprend la couleur du texte qui l’entoure */
}
Structurer sa feuille de style
Pour limiter les conflits de spécificité, adoptez dès maintenant une stratégie simple :
- écrivez d’abord des règles générales sur des éléments (
body,h1,a) ; - ajoutez ensuite des classes pour les composants (
.carte,.bouton) ; - n’utilisez les identifiants que comme ancres de navigation (
#contact), pas pour le style ; - gardez une spécificité faible et homogène.
Astuce
Dans l’inspecteur, le panneau des styles liste les règles qui s’appliquent à l’élément sélectionné, de la plus prioritaire à la moins prioritaire. Les déclarations barrées sont celles qui ont perdu face à une autre. C’est le meilleur moyen de comprendre un conflit.
À vous de jouer
Voici un fragment de HTML et de CSS :
<article class="carte" id="projet-alpes">
<h3 class="titre">Les Alpes en hiver</h3>
</article>
h3 { color: black; }
.carte h3 { color: green; }
#projet-alpes .titre { color: red; }
.titre { color: blue; }
De quelle couleur sera le titre ? Calculez la spécificité de chaque règle. Puis, sans toucher à l’identifiant, que faudrait-il changer pour obtenir du bleu ?
Voir une solution
Spécificités : h3 = 0-0-1 ; .carte h3 = 0-1-1 ; #projet-alpes .titre = 1-1-0 ; .titre = 0-1-0. La règle avec l’identifiant gagne : le titre est rouge.
Pour obtenir du bleu, le plus propre est de supprimer le sélecteur par identifiant (on ne stylise pas par id) et de conserver une règle de classe. Si vous deviez absolument conserver la règle rouge, il faudrait une règle plus spécifique que 1-1-0, ce qui est une mauvaise idée : mieux vaut revoir la structure des règles.
À retenir
- Sélecteurs : élément, classe (
.), identifiant (#), universel, groupe, combinateurs (espace,>,+,~), attributs. - Les pseudo-classes (
:hover,:nth-child()…) ciblent un état ; les pseudo-éléments (::before…) une partie d’élément. - La cascade tranche selon l’importance, la spécificité (ID, classes, éléments) puis l’ordre d’écriture.
- Certaines propriétés sont héritées (texte), d’autres non (boîtes).
- Privilégiez des classes simples, évitez
!importantet les identifiants pour le style.
Dans la prochaine leçon, vous découvrez comment chaque élément est une boîte, et comment mesurer et colorer vos éléments.