HTML / CSS

Sélecteurs & arborescence en CSS

Objectif : savoir cibler précisément un élément HTML grâce à sa balise, ses classes/ID, sa position dans le DOM (arborescence), ses relations (combinateurs), ses attributs, et ses états (pseudo-classes) / parties (pseudo-éléments).

1) Notion d’arborescence (DOM)

Comprendre parent / enfant / descendant

En HTML, les éléments sont organisés comme un arbre. Un élément peut contenir d’autres éléments.

Exemple HTML

<section>
  <article>
    <p>Un <strong>mot</strong> important.</p>
  </article>
</section>

Relations

  • <section> est le parent de <article>
  • <article> est l’enfant de <section>
  • <strong> est un descendant de <section>

Le CSS cible souvent en utilisant cette hiérarchie (ex : section article p).

2) Les sélecteurs (ciblage)

Sélecteur de type (balise)

p — cible toutes les balises <p>.

p {
  color: #222;
}

Sélecteur de classe

.terme — cible tous les éléments ayant class="terme".

.terme {
  font-style: italic;
}

Sélecteur d’identifiant (ID)

#intro — cible l’élément ayant id="intro" (unique dans la page).

#intro {
  border: 1px dashed #c82605;
}

Sélecteur “élément + classe”

span.terme — cible uniquement les <span> qui ont la classe terme.

span.terme {
  color: green;
}

Sélecteur groupé

div#intro, section — applique les mêmes règles à plusieurs cibles.

div#intro,
section {
  padding: 10px;
}

Pseudo-classes (états)

:hover, :focus — styles au survol / au focus (clavier).

a:hover,
a:focus {
  text-decoration: underline;
}

3) Les combinateurs

Un combinateur relie deux sélecteurs pour cibler un élément en fonction de sa relation avec un autre (descendant, enfant direct, frères…).

Descendant (espace)

section article p — cible tous les p qui sont dans article (même profondément).

section article p {
  background: #ffd133;
}

Enfant direct (>)

ul#menu01 > li — cible seulement les li enfants immédiats de ul#menu01.

ul#menu01 > li {
  background: yellow;
}

Frère adjacent (+)

h3 + p — cible le p placé juste après un h3 (même parent).

h3 + p {
  font-weight: bold;
}

Frères suivants (~)

h3 ~ p — cible tous les p frères qui suivent un h3.

h3 ~ p {
  border: 2px dotted blue;
}

Cas pratique : styliser les éléments “après” au survol

li:hover ~ li — quand on survole un li, les li suivants changent.

ul#menu02 li:hover ~ li {
  background: green;
}

Bonus (récent) : :has() “parent conditionnel”

ul:has(li:hover) — cible le parent ul si un descendant (ici un li) est survolé.
À réserver si autorisé (support navigateur à vérifier).

ul:has(li:hover) {
  outline: 2px solid #c82605;
}

4) Les sélecteurs d’attributs

Les sélecteurs d’attributs permettent de cibler un élément selon la présence ou la valeur d’un attribut HTML (ex : href, title, type…).

Présence d’un attribut

abbr[title] — cible les abbr qui ont un attribut title.

abbr[title] {
  border-bottom: 2px dotted #c82605;
}

Valeur exacte

input[type="text"] — cible les champs texte uniquement.

input[type="text"] {
  border: 1px solid green;
}

Combiner plusieurs attributs

input[type="text"][name="nom"] — cible un champ texte précis (attention : pas d’espace).

input[type="text"][name="nom"] {
  text-transform: uppercase;
}

Commence par (^=)

a[href^="http"] — cible les liens externes (http/https).

a[href^="http"],
a[href^="https"] {
  border: 1px solid red;
}

Se termine par ($=)

a[href$=".pdf"] — cible les liens vers fichiers PDF.

a[href$=".pdf"] {
  padding-right: 20px;
}

Contient (*=)

a[href*="google"] — cible si l’attribut contient une chaîne donnée (plus large).

a[href*="google"] {
  background: #fff3cd;
}

5) Les pseudo-classes propres aux liens

Les liens (<a>) ont plusieurs états. On utilise des pseudo-classes pour les styliser différemment selon l’interaction.

Astuce mémoire pour l’ordre : LoVe HAte:link, :visited, :hover, :active. (On ajoute souvent :focus pour l’accessibilité clavier.)

Lien non visité

a:link — cible un lien vers une page pas encore visitée.

a:link {
  color: black;
  text-decoration: none;
}

Lien visité

a:visited — cible un lien déjà visité par l’utilisateur.

a:visited {
  color: silver;
}

Survol

a:hover — cible le lien quand la souris est dessus.

a:hover {
  text-decoration: underline;
  color: hotpink;
}

Focus (clavier)

a:focus — cible le lien quand il est sélectionné au clavier (TAB).

a:focus {
  outline: 2px solid #c82605;
  outline-offset: 2px;
}

Active (clic en cours)

a:active — cible le lien pendant l’action du clic (moment très court).

a:active {
  transform: translateY(1px);
}

Combinaison “visité + survol”

a:visited:hover — cible les liens visités uniquement quand on les survole.

a:visited:hover {
  color: red;
}

Cibler un lien via le survol du parent

p:hover a — quand on survole le p, on stylise le lien à l’intérieur.

p:hover a {
  border-bottom: 1px dotted #808080;
  background: #f5f5f5;
  color: orange;
}

Cibler une cible d’ancre

:target — cible l’élément dont l’id correspond au # dans l’URL.

article:target {
  background: white;
  border: 1px solid #6F603D;
  padding: 20px;
}

6) Pseudo-classes propres aux formulaires

Les formulaires possèdent des états spécifiques (validation, obligation, activation, focus…) que l’on peut cibler directement en CSS, sans JavaScript.

:required

Cible les champs marqués comme obligatoires dans le HTML.

input:required,
textarea:required {
  border-left: 4px solid orange;
}

:optional

Cible les champs qui ne sont pas obligatoires.

input:optional {
  background: #f9f9f9;
}

:valid

Cible un champ dont la valeur respecte les contraintes HTML.

input:valid,
textarea:valid {
  border: 2px solid green;
}

:invalid

Cible un champ dont la valeur ne respecte pas les règles.

input:invalid,
textarea:invalid {
  border: 2px solid red;
}

:focus

Cible un champ actuellement sélectionné (clic ou clavier).

input:focus,
textarea:focus {
  outline: 2px solid #c82605;
}

:focus-within

Cible un conteneur lorsqu’un de ses champs est sélectionné.

label:focus-within {
  background: #fff3cd;
}

:enabled

Cible les éléments actifs (ex : bouton cliquable).

button:enabled {
  background: #c82605;
  color: white;
}

::placeholder

Cible le texte indicatif d’un champ.

input::placeholder,
textarea::placeholder {
  color: #999;
  font-style: italic;
}
À retenir : Grâce aux pseudo-classes des formulaires, on peut gérer la validation, les états et l’accessibilité sans JavaScript.

7) Autres pseudo-classes

Les pseudo-classes permettent de cibler un élément selon sa position (dans une liste), ou en excluant certains éléments, sans ajouter de classe dans le HTML.

Premier enfant

li:first-child — cible le 1er enfant (quel que soit le type, mais ici un li).

ul li:first-child {
  border-top: 3px solid orange;
}

Dernier enfant

li:last-child — cible le dernier enfant.

ul li:last-child {
  border-bottom: 15px solid orange;
}

n-ième enfant

li:nth-child(2) — cible le 2e enfant du parent (peu importe le type des enfants).

ul li:nth-child(2) {
  background: orange;
}

Pairs / impairs

li:nth-child(even) / li:nth-child(odd) — cible les éléments pairs / impairs.

ul li:nth-child(even) { background: green; }
ul li:nth-child(odd)  { background: #eaf7ea; }

n-ième depuis la fin

li:nth-last-child(-n+3) — cible les 3 derniers enfants (en partant de la fin).

ul li:nth-last-child(-n+3) {
  background: #DB0B32;
}

n-ième “du même type”

p:nth-of-type(3) — cible le 3e paragraphe en ne comptant que les <p>.

div p:nth-of-type(3) {
  background: red;
}

Exclure un cas

p:not(.conclusion) — cible les paragraphes sauf ceux qui ont la classe conclusion.

section p:not(.conclusion) {
  background: yellow;
}

Exclure un état (ex : non survolé)

li:not(:hover) — cible les éléments qui ne sont pas survolés.

nav ul li:not(:hover) {
  background: red;
}

Grouper sans répéter

:is(article, aside) p — cible les p dans article et dans aside (même règle).

:is(article, aside) p {
  background: red;
}

8) Les pseudo-éléments

Un pseudo-élément cible une partie d’un élément (ex : première lettre) ou permet de générer du contenu sans ajouter de balise dans le HTML.

En CSS moderne, on écrit les pseudo-éléments avec :: (même si : marche encore souvent).

Première lettre

p::first-letter — cible la première lettre (lettrine).

p::first-letter {
  font-size: 200%;
  font-weight: bold;
}

Première ligne

p::first-line — cible la première ligne d’un bloc de texte.

p::first-line {
  font-variant: small-caps;
}

Sélection de texte

p::selection — style appliqué au texte sélectionné par l’utilisateur.

p::selection {
  background: #006644;
  color: white;
}

Ajouter du contenu avant

h1::before — insère un contenu avant l’élément (texte, icône…).

h1::before {
  content: ">>>>>>> ";
  color: red;
}

Ajouter du contenu après

p.conclusion::after — insère un contenu après l’élément.

p.conclusion::after {
  content: " Fin de l'histoire";
}

Cas pratique : marquer une tâche finie

li.fini::after — ajoute un symbole après les li terminés.

li.fini::after {
  content: " \2615 ";
  font-size: 1.4em;
}

9) Bonus — Sélecteurs utiles en pratique

Ces sélecteurs ne sont pas indispensables au début, mais ils permettent d’écrire un CSS plus propre, plus maintenable et plus précis, sans ajouter inutilement des classes dans le HTML.

Sélecteur universel

* — cible tous les éléments. Souvent utilisé pour des règles globales (reset, box-model).

* {
  box-sizing: border-box;
}

:root

Cible l’élément racine du document (équivalent à html), très utilisé pour définir des variables CSS globales.

:root {
  --couleur-principale: #c82605;
}

:empty

Cible un élément sans aucun contenu (pas de texte, pas d’enfant).

p:empty {
  display: none;
}

:only-child

Cible un élément qui est le seul enfant de son parent (peu importe son type).

li:only-child {
  font-style: italic;
}

:only-of-type

Cible un élément qui est le seul de son type parmi les enfants du parent.

p:only-of-type {
  background: #fff3cd;
}

:first-of-type

Cible le premier élément d’un type donné (ex : premier paragraphe).

article p:first-of-type {
  font-weight: bold;
}

:last-of-type

Cible le dernier élément d’un type donné dans un parent.

article p:last-of-type {
  margin-bottom: 0;
}

:lang()

Cible les éléments selon la langue définie par l’attribut lang.

:lang(fr) q {
  quotes: "« " " »";
}

:is()

Permet de regrouper plusieurs sélecteurs sans répéter les règles CSS.

:is(article, aside, section) p {
  line-height: 1.6;
}

:where()

Identique à :is(), mais avec une spécificité nulle (n’écrase pas les styles).

:where(header, footer) a {
  color: inherit;
}

:has() (avancé mais supporté)

Cible un élément s’il contient un autre élément. Permet enfin un “parent conditionnel”.

ul:has(li:hover) {
  background: #f5f5f5;
}
À retenir : ces sélecteurs servent surtout à éviter d’ajouter des classes inutiles et à écrire un CSS plus expressif.