Niveau 2 — Sélecteurs

Les sélecteurs combinés

Cibler des éléments selon leur position dans l'arbre DOM grâce aux combinateurs.

1. Comprendre les sélecteurs combinés

En une phrase : Un sélecteur combiné utilise un combinateur (espace, >, ~, +) pour cibler un élément en fonction de sa relation avec un autre élément dans l'arbre DOM.

Les sélecteurs simples ciblent des éléments directement. Les sélecteurs combinés, eux, exploitent la hiérarchie parent-enfant-frère du DOM pour des ciblages plus précis.

Les 4 combinateurs essentiels :

Combinateur Nom Syntaxe Signification
(espace) Descendant A B B est un descendant de A (à n'importe quelle profondeur)
> Enfant direct A > B B est un enfant direct de A (niveau immédiat)
~ Frère général A ~ B B est un frère suivant de A (même parent, après A)
+ Frère adjacent A + B B est le frère directement suivant de A (juste après)

2. Syntaxe détaillée

2.1 Le sélecteur descendant (espace)

Définition : Le sélecteur descendant A B cible tous les éléments B qui sont des descendants de A, quelle que soit la profondeur. Il peut y avoir des éléments intermédiaires entre A et B.
/* Cible TOUS les <p> à l'intérieur d'un <article>,
   même s'ils sont dans des div intermédiaires */
article p {
  line-height: 1.8;
}

/* Cible tous les <a> dans la navigation */
nav a {
  color: white;
  text-decoration: none;
}
<article> ├── <p> ← CIBÉ ✓ (descendant direct) ├── <div> │ └── <p> ← CIBÉ ✓ (descendant à 2 niveaux) └── <section> └── <div> └── <p> ← CIBÉ ✓ (descendant à 3 niveaux)

Le sélecteur descendant cible les <p> à toutes les profondeurs dans <article>

2.2 Le sélecteur enfant direct (>)

Définition : Le sélecteur enfant direct A > B cible uniquement les éléments B qui sont des enfants directs de A — c'est-à-dire au niveau hiérarchique immédiat. Aucun élément intermédiaire n'est admis.
/* Cible uniquement les <p> enfants directs d'un <article> */
article > p {
  margin-bottom: 1rem;
}

/* Cible uniquement les <li> enfants directs d'un <ul> */
ul > li {
  padding: 0.5rem 0;
}
<article> ├── <p> ← CIBÉ ✓ (enfant direct) ├── <div> │ └── <p> ← NON ciblé ✗ (pas enfant direct) └── <p> ← CIBÉ ✓ (enfant direct)

Le sélecteur enfant direct > ne cible que le premier niveau

2.3 Le sélecteur frère général (~)

Définition : Le sélecteur frère général A ~ B cible tous les éléments B qui sont des frères suivants de A — c'est-à-dire placés après A au même niveau hiérarchique, avec le même parent. Les frères précédents ne sont pas ciblés.
/* Cible tous les <p> qui suivent un <h2> au même niveau */
h2 ~ p {
  padding-left: 1rem;
  border-left: 3px solid #e2e8f0;
}
<section> ├── <h2> ← ÉLÉMENT RÉFÉRENCE ├── <p> ← CIBÉ ✓ (frère suivant) ├── <div> │ └── <p> ← NON ciblé ✗ (pas au même niveau) ├── <p> ← CIBÉ ✓ (frère suivant) └── <p> ← CIBÉ ✓ (frère suivant)

Le sélecteur h2 ~ p cible tous les <p> après le <h2>

2.4 Le sélecteur frère adjacent (+)

Définition : Le sélecteur frère adjacent A + B cible uniquement le premier élément B qui suit directement A — le frère immédiat. Si un autre élément est entre A et B, B n'est pas ciblé.
/* Cible uniquement le premier <p> juste après un <h2> */
h2 + p {
  font-size: 1.1rem;
  font-weight: 600;
  color: #2563eb;
}

/* Cible l'input juste après un label */
label + input {
  margin-top: 0.5rem;
}
<section> ├── <h2> ← ÉLÉMENT RÉFÉRENCE ├── <p> ← CIBÉ ✓ (frère adjacent immédiat) ├── <div> │ └── <p> ← NON ciblé ✗ └── <p> ← NON ciblé ✗ (pas adjacent au h2)

Le sélecteur h2 + p cible uniquement le <p> juste après le <h2>

3. Visualisation comparative

3.1 Descendant vs Enfant direct

Comparaison en direct

/* Sélecteur descendant : espace */
article p {
  background: #dbeafe;   /* Bleu clair */
  border-left: 3px solid #2563eb;
}

/* Sélecteur enfant direct : > */
article > p {
  background: #fee2e2;   /* Rouge clair */
  border-left: 3px solid #dc2626;
}
Résultat visuel

<p> enfant direct → Rouge (enfant direct ✓)

<p> dans un <div> → Bleu (descendant ✓, enfant direct ✗)

<p> enfant direct → Rouge (enfant direct ✓)

3.2 Frère adjacent vs Frère général

Comparaison en direct

/* Frère adjacent : + (un seul élément) */
h2 + p {
  color: #2563eb;
  font-weight: 700;
}

/* Frère général : ~ (tous les éléments suivants) */
h2 ~ p {
  color: #64748b;
  padding-left: 1rem;
}

Titre h2 — Référence

<p> adjacent → Bleu gras (+ ciblé ✓, ~ ciblé ✓)

<p> dans un <div> → Gris (pas au même niveau)

<p> frère général → Gris (~ ciblé ✓, + NON ciblé ✗)

<p> autre frère → Gris (~ ciblé ✓, + NON ciblé ✗)

4. Exemples progressifs

4.1 Style de navigation avec descendant

Navigation hiérarchique

/* Le sélecteur descendant cible tous les liens dans la nav */
nav a {
  display: inline-block;
  padding: 0.5rem 1rem;
  color: white;
  text-decoration: none;
  border-radius: 6px;
}

nav a:hover {
  background: rgba(255,255,255,0.2);
}

/* L'enfant direct cible uniquement les liens de premier niveau */
nav > ul > li > a {
  font-weight: 700;
  text-transform: uppercase;
}

4.2 Style d'article avec frère adjacent

Premier paragraphe après un titre

/* Le premier paragraphe après un h2 est une "chape" */
h2 + p {
  font-size: 1.1rem;
  color: #475569;
  font-weight: 500;
  border-left: 4px solid #2563eb;
  padding-left: 1rem;
}

/* Tous les paragraphes suivants */
h2 ~ p {
  line-height: 1.8;
  margin-bottom: 1rem;
}

4.3 Formulaire avec enfant direct

Labels et inputs alignés

/* Cible les labels enfants directs du formulaire */
form > label {
  display: block;
  font-weight: 600;
  margin-bottom: 0.25rem;
  margin-top: 1rem;
}

/* Cible les inputs juste après les labels */
label + input {
  width: 100%;
  padding: 0.6rem;
  border: 2px solid #e2e8f0;
  border-radius: 6px;
  font-size: 1rem;
}

/* Cible les inputs focus */
label + input:focus {
  border-color: #2563eb;
  outline: none;
  box-shadow: 0 0 0 3px rgba(37,99,235,0.15);
}

4.4 Liste de tâches avec frère général

Griser les tâches après une tâche terminée

/* Quand une tâche est marquée "terminée",
   toutes les tâches suivantes sont grisées */
.tache-terminee ~ .tache {
  opacity: 0.5;
  text-decoration: line-through;
}

5. Erreurs fréquentes

Erreur 1 : Confondre descendant et enfant direct
/* FAUX — tu voulais cibler les <p> enfants directs */
div p { ... }    /* Ceci cible AUSSI les <p> imbriqués ! */

/* CORRECT — utiliser > pour les enfants directs uniquement */
div > p { ... }
Erreur 2 : Confondre + et ~
/* Ceci ne cible que le PREMIER <p> après <h2> */
h2 + p { ... }

/* Ceci cible TOUS les <p> après <h2> */
h2 ~ p { ... }
Erreur 3 : Espaces accidentels qui changent le sens
/* Enfant direct : pas d'espace */
h2 > p { ... }

/* Descendant : avec un espace */
h2 p { ... }

/* Attention ! Un espace parasite change tout ! */
Erreur 4 : Chaîner trop de combinaisons
/* FAUX — trop spécifique et fragile */
div > section > article > div > p > span { ... }

/* CORRECT — utiliser une classe à la place */
.article-highlight { ... }

6. Bonnes pratiques

Règles d'or :
  • Préférer > à l'espace quand tu veux cibler uniquement les enfants directs — c'est plus explicite et performant.
  • Ne pas dépasser 2-3 niveaux de profondeur dans les sélecteurs combinés.
  • Combiner avec des classes : .nav > .nav-item est préférable à nav > li.
  • Utiliser ~ et + pour les effets contextuels (style conditionnel).
  • Tester la structure HTML avant d'écrire les sélecteurs — la hiérarchie du DOM détermine leur efficacité.
/* ✅ Bonne pratique : ciblage précis avec classe */
.sidebar > .menu-item {
  padding: 0.75rem;
}

/* ✅ Bonne pratique : effet conditionnel */
.section-title + .section-content {
  margin-top: 0;
}

/* ✅ Bonne pratique : navigation profonde */
.breadcrumb > .breadcrumb-item + .breadcrumb-item::before {
  content: " / ";
  margin: 0 0.5rem;
  color: #94a3b8;
}

7. Mini-défi

Exercice 1 : Descendant vs Enfant direct

Écris deux règles CSS pour un élément <ul> contenant des <li> avec parfois des <ul> imbriquées :

  • ul li : padding de 0.5rem (descendant)
  • ul > li : border-left de 3px solid blue (enfant direct)

Solution :

ul li {
  padding: 0.5rem;
}

ul > li {
  border-left: 3px solid blue;
}

Exercice 2 : Frère adjacent

Écris un sélecteur pour cibler uniquement le <p> qui suit directement un <h1> et lui appliquer :

  • font-size: 1.2rem
  • color: #475569
  • font-style: italic

Solution :

h1 + p {
  font-size: 1.2rem;
  color: #475569;
  font-style: italic;
}

Exercice 3 : Combinaison complète

Écris un sélecteur pour cibler tous les liens <a> qui sont dans une liste <ul> qui est un enfant direct d'un <nav>. Le style :

  • text-decoration: none
  • color: #2563eb
  • font-weight: 600

Solution :

nav > ul a {
  text-decoration: none;
  color: #2563eb;
  font-weight: 600;
}

8. Projet d'application

Projet : Page d'article avec navigation

Crée une page HTML avec :

  • Un <nav> contenant un <ul> avec des liens
  • Un <article> avec des <h2> et des <p>
  • Un <aside> avec des informations supplémentaires

CSS requis (utilise les combinateurs) :

  • nav a : style de lien (descendant)
  • nav > ul : flexbox pour aligner les items (enfant direct)
  • h2 + p : style spécial pour le premier paragraphe (frère adjacent)
  • h2 ~ p : style pour les paragraphes suivants (frère général)
  • article > p:first-of-type : premier paragraphe de l'article

9. Révision

Quiz rapide

  1. Quel est le combinateur pour les descendants ?
  2. Quel combinateur cible uniquement les enfants directs ?
  3. Quelle est la différence entre + et ~ ?
  4. div > p cible un <p> à 3 niveaux de profondeur ? Oui / Non
  5. h1 + p cible tous les <p> après le <h1> ? Oui / Non
  6. Quel sélecteur est le plus performant en général ?
Réponses :
  1. L'espace : A B
  2. > : A > B
  3. + cible le frère immédiat suivant ; ~ cible tous les frères suivants
  4. Non — > ne cible que les enfants directs (niveau 1)
  5. Non — + ne cible que le premier <p> directement adjacent au <h1>
  6. Les sélecteurs d'ID et de classe sont les plus performants. Les combinateurs sont légèrement plus coûteux car le navigateur doit parcourir l'arbre DOM.