Niveau 2 — Sélecteurs

Les pseudo-éléments

Créer des éléments virtuels et manipuler le contenu sans modifier le HTML.

1. Comprendre les pseudo-éléments

En une phrase : Un pseudo-élément est un sélecteur qui crée un élément virtuel dans le DOM ou qui cible une partie spécifique du contenu d'un élément, sans ajouter de balise HTML.

Les pseudo-éléments commencent par deux deux-points :: (contrairement aux pseudo-classes qui en ont un seul). Ils créent des éléments « fantômes » qui n'existent pas dans le HTML source.

/* Syntaxe générale */
sélecteur::pseudo-élément {
  propriété: valeur;
}

/* Exemple */
p::first-line {
  font-weight: 700;
}

Différence pseudo-classe vs pseudo-élément :

Aspect Pseudo-classe : Pseudo-élément ::
Symbole : (un seul) :: (deux)
Cible Un état ou une position Une partie du contenu ou un élément virtuel
Existe dans le HTML ? Oui (l'élément existe déjà) Non (c'est un élément créé par CSS)
Exemples :hover, :first-child ::before, ::after, ::first-line
Note : Les navigateurs acceptent encore la syntaxe à un seul : pour ::before et ::after par rétrocompatibilité, mais la syntaxe correcte est :: (deux points).

2. Syntaxe détaillée

2.1 ::before et ::after — Les incontournables

Définition : ::before et ::after créent des éléments virtuels qui sont insérés avant / après le contenu réel de l'élément. Ils nécessitent la propriété content pour exister.
/* Sans content, ::before et ::after n'existent PAS */

/* Ajouter une icône avant chaque titre */
h2::before {
  content: "→ ";
  color: #2563eb;
  font-weight: 700;
}

/* Ajouter des guillemets après un bloc de citation */
blockquote::after {
  content: """;
  font-size: 2rem;
  color: #94a3b8;
  vertical-align: -0.3em;
  margin-left: 0.25rem;
}

/* Créer un badge décoratif */
.badge::before {
  content: "★";
  margin-right: 0.5rem;
  color: #f59e0b;
}
Point crucial : La propriété content est obligatoire. Sans elle, ::before et ::after ne sont tout simplement pas rendus par le navigateur.

Exemples de valeurs pour content

/* Texte literal */
element::before {
  content: "Note : ";
}

/* Caractère Unicode */
element::before {
  content: "\2713";  /* ✓ checkmark */
}

/* Attr HTML (seulement pour ::before/::after) */
element::before {
  content: attr(data-label);
}

/* URL d'image */
element::before {
  content: url("icon.svg");
}

/* Compteur */
.element::before {
  counter-increment: compteur;
  content: counter(compteur) ". ";
}

/* Chaîne vide (utile pour les '::after' décoratifs) */
.element::after {
  content: "";
}

2.2 ::first-letter — La première lettre

Définition : ::first-letter cible la première lettre (ou le premier caractère non whitespace) d'un élément bloc. Idéal pour créer un effet « lettrine ».
/* Lettrine decorative */
article > p:first-of-type::first-letter {
  float: left;
  font-size: 3.5rem;
  line-height: 0.8;
  font-weight: 800;
  color: #2563eb;
  margin-right: 0.5rem;
  margin-top: 0.1rem;
}
Note : ::first-letter ne fonctionne que sur les éléments de type bloc (p, div, h1…), pas sur les éléments en ligne (span, a).

2.3 ::first-line — La première ligne

Définition : ::first-line cible la première ligne du texte d'un élément bloc. Le nombre de caractères affichés change avec la largeur du conteneur.
p::first-line {
  font-weight: 700;
  color: #2563eb;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
Propriétés autorisées : Seules les propriétés de police, couleur et décoration sont autorisées avec ::first-line (pas de margin, padding, etc.).

2.4 ::selection — Le texte sélectionné

Définition : ::selection cible le texte électionné par l'utilisateur (surlignage bleu par défaut). Permet de personnaliser l'expérience de copier-coller.
/* Personnaliser la sélection */
::selection {
  background: #2563eb;
  color: white;
}

/* Sélection spécifique dans un élément */
.code-block::selection {
  background: #7c3aed;
  color: white;
}

2.5 ::marker — Les puces et numéros

Définition : ::marker cible la puce () ou le numéro des éléments de <ol> et <ul>.
/* Personnaliser les puces de liste */
li::marker {
  color: #2563eb;
  font-size: 1.2em;
}

/* Numéros de liste ordonnée */
ol li::marker {
  color: #dc2626;
  font-weight: 700;
}

2.6 ::placeholder — Le texte indicatif

Définition : ::placeholder cible le texte placeholder (texte gris par défaut) des champs de formulaire (<input>, <textarea>).
input::placeholder {
  color: #94a3b8;
  font-style: italic;
  opacity: 0.7;
}

textarea::placeholder {
  color: #cbd5e1;
  font-size: 0.9rem;
}

2.7 ::file-selector-button — Le bouton de fichier

Définition : ::file-selector-button cible le bouton du sélecteur de fichier (<input type="file">).
input[type="file"]::file-selector-button {
  padding: 0.6rem 1.2rem;
  background: #7c3aed;
  color: white;
  border: none;
  border-radius: 6px;
  font-weight: 600;
  cursor: pointer;
}

input[type="file"]::file-selector-button:hover {
  background: #6d28d9;
}

3. Visualisation

┌─────────────────────────────────────────────────────────┐
│              PSEUDO-ÉLÉMENTS EN SCHÉMA                  │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  Élément HTML : <h2 class="titre">Mon titre</h2>     │
│                                                         │
│  ┌──────────────────────────────────────────────────┐   │
│  │ ::before    "→ "   Mon titre   ::after  " 🔗"   │   │
│  │  ↑                       ↑              ↑        │   │
│  │  Élément virtuel     Contenu réel   Élément      │   │
│  │  (avant)                            virtuel      │   │
│  │                                       (après)    │   │
│  └──────────────────────────────────────────────────┘   │
│                                                         │
│  ::first-letter  →  La première lettre du paragraphe   │
│  ::first-line    →  La première ligne (responsive)     │
│  ::selection     →  Le texte sélectionné               │
│  ::marker        →  La puce/numéro d'un <li>         │
│  ::placeholder   →  Le texte indicatif d'un input      │
│                                                         │
└─────────────────────────────────────────────────────────┘

Schéma des pseudo-éléments et leur positionnement

4. Exemples progressifs

4.1 Décoration avec ::before et ::after

Démonstration : Éléments décoratifs

/* Icône étoile avant chaque élément */
.icone-item::before {
  content: "★";
  position: absolute;
  left: 0.75rem;
  color: #f59e0b;
  font-size: 1.1rem;
}

/* Badge compteur après chaque élément */
.compteur-item::after {
  content: attr(data-count);
  position: absolute;
  right: 0.75rem;
  background: #2563eb;
  color: white;
  padding: 0.2rem 0.6rem;
  border-radius: 999px;
  font-size: 0.8rem;
  font-weight: 600;
}
Premier élément avec icône
Deuxième élément avec icône
Troisième élément avec icône
Élément avec compteur
Autre élément avec compteur
Dernier élément

4.2 Lien avec animation

Démonstration : Soulignement animé au survol

/* Lien avec soulignement progressif */
.lien-deco::after {
  content: "";
  position: absolute;
  bottom: 0;
  left: 0;
  width: 0;
  height: 2px;
  background: #2563eb;
  transition: width 0.3s ease;
}

.lien-deco:hover::after {
  width: 100%;
}

4.3 Lettrine avec ::first-letter

Démonstration : Première lettre stylisée

.drop-cap::first-letter {
  float: left;
  font-size: 3.5rem;
  line-height: 0.8;
  font-weight: 800;
  color: #2563eb;
  margin-right: 0.5rem;
  margin-top: 0.1rem;
}

Les pseudo-éléments sont des outils puissants du CSS moderne. Ils permettent de créer des éléments virtuels sans modifier le HTML, d'ajouter des décorations, et de personnaliser l'apparence du texte de manière élégante et efficace.

4.4 Première ligne avec ::first-line

Démonstration : La première ligne en gras

.first-line-style::first-line {
  font-weight: 700;
  color: #2563eb;
  font-size: 1.1em;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

La première ligne de ce paragraphe est automatiquement mise en gras, en bleu et en majuscules grâce au pseudo-élément ::first-line. Si tu redimensionnes la fenêtre, le texte change mais la première ligne reste toujours stylée. C'est la magie de ce pseudo-élément — il s'adapte dynamiquement à la largeur du conteneur.

4.5 Personnaliser la sélection

Démonstration : Sélectionne du texte !

.selection-custom::selection {
  background: #2563eb;
  color: white;
}

Sélectionne ce texte pour voir la sélection personnalisée en bleu avec du texte blanc. Compare avec le texte ci-dessous qui utilise la sélection par défaut du navigateur.

Ce paragraphe utilise la sélection par défaut du navigateur (bleu clair avec texte noir).

4.6 Personnaliser les puces

Démonstration : Puces violettes

.marker-list li::marker {
  color: #7c3aed;
  font-size: 1.2em;
}
  • Premier élément avec puce violette
  • Deuxième élément avec puce violette
  • Troisième élément avec puce violette

4.7 Personnaliser le placeholder

Démonstration : Placeholders stylisés

.placeholder-input::placeholder {
  color: #94a3b8;
  font-style: italic;
  opacity: 0.7;
}

.placeholder-input:focus {
  border-color: #2563eb;
  box-shadow: 0 0 0 3px rgba(37,99,235,0.15);
}

4.8 Le bouton de fichier

Démonstration : Input fichier stylisé

.file-input::file-selector-button {
  padding: 0.6rem 1.2rem;
  background: #7c3aed;
  color: white;
  border: none;
  border-radius: 8px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.2s;
}

.file-input::file-selector-button:hover {
  background: #6d28d9;
}

5. Erreurs fréquentes

Erreur 1 : Oublier la propriété content
/* FAUX — ::before n'existe PAS sans content */
.element::before {
  background: red;
  width: 20px;
  height: 20px;
}

/* CORRECT */
.element::before {
  content: "";
  background: red;
  width: 20px;
  height: 20px;
}
Erreur 2 : Utiliser ::first-letter sur un inline
/* FAUX — ne fonctionne que sur les éléments bloc */
span::first-letter {
  font-size: 2rem;
}

/* CORRECT */
p::first-letter {
  font-size: 2rem;
}
Erreur 3 : Confondre ::before/::after avec du vrai HTML
/* FAUX — les pseudo-éléments ne peuvent PAS recevoir
   d'événements souris ni avoir de tabindex */
.element::before {
  content: "Clique";
  cursor: pointer;
}
/* Le clic ne fonctionnera PAS sur cet élément virtuel */

/* CORRECT — ajouter un vrai élément HTML pour l'interaction */
.element {
  position: relative;
}
.element .deco {
  position: absolute;
  cursor: pointer;
}
Erreur 4 : Appliquer des propriétés invalides à ::first-line
/* FAUX — ::first-line n'accepte que les propriétés de texte */
p::first-line {
  margin: 1rem;       /* ✗ Pas autorisé */
  padding: 0.5rem;    /* ✗ Pas autorisé */
  border: 1px solid;  /* ✗ Pas autorisé */
}

/* CORRECT */
p::first-line {
  font-weight: 700;
  color: #2563eb;
  text-transform: uppercase;
}

6. Bonnes pratiques

Règles d'or :
  • Toujours inclure content pour ::before et ::after.
  • Utiliser attr() pour afficher des données du HTML via CSS.
  • Limiter les pseudo-éléments décoratifs à ce qui n'est pas du contenu essentiel.
  • Ne pas utiliser pour le contenu important (non sélectionnable, non copiable, non lisible par les lecteurs d'écran).
  • Tester la lisibilité des lettrines et premières lignes sur mobile.
  • Utiliser ::selection avec parcimonie — ne pas en abuser.
/* ✅ Bonne pratique : icône décorative avec ::before */
.nav-item::before {
  content: "→";
  margin-right: 0.5rem;
  color: inherit;
  opacity: 0.5;
}

/* ✅ Bonne pratique : data attribute pour du contenu dynamique */
.badge::after {
  content: attr(data-count);
  background: #dc2626;
  color: white;
  padding: 0.1rem 0.4rem;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 700;
  margin-left: 0.5rem;
}

/* ✅ Bonne pratique : soulignement animé */
.animated-link {
  position: relative;
  text-decoration: none;
}

.animated-link::after {
  content: "";
  position: absolute;
  bottom: -2px;
  left: 0;
  width: 0;
  height: 2px;
  background: currentColor;
  transition: width 0.3s ease;
}

.animated-link:hover::after {
  width: 100%;
}

7. Mini-défi

Exercice 1 : ::before et ::after

Ajoute un contenu décoratif à chaque élément <h2> :

  • ::before : le caractère § en bleu, gras
  • ::after : le caractère § en bleu, gras

Solution :

h2::before,
h2::after {
  content: "§";
  color: #2563eb;
  font-weight: 700;
  margin: 0 0.5rem;
}

Exercice 2 : Lettrine

Crée une lettrine pour le premier paragraphe d'un <article> :

  • ::first-letter : taille 4rem, couleur #7c3aed, flotté à gauche

Solution :

article > p:first-of-type::first-letter {
  float: left;
  font-size: 4rem;
  line-height: 0.8;
  font-weight: 800;
  color: #7c3aed;
  margin-right: 0.5rem;
}

Exercice 3 : Badge dynamique

Crée un badge qui affiche le nombre d'items via data-count :

  • Le badge est un ::after
  • Fond rouge, texte blanc, border-radius 999px
  • Positionné à droite de l'élément

Solution :

.badge {
  position: relative;
  padding-right: 2rem;
}

.badge::after {
  content: attr(data-count);
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  background: #dc2626;
  color: white;
  padding: 0.2rem 0.5rem;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 700;
}

Exercice 4 : ::selection personnalisée

Crée une sélection personnalisée pour un bloc de code :

  • Fond de sélection : #7c3aed
  • Couleur du texte sélectionné : white

Solution :

.code-block::selection {
  background: #7c3aed;
  color: white;
}

8. Projet d'application

Projet : Blog avec décorations CSS

Crée un fichier index.html et style.css avec :

HTML requis :

  • Un <article> avec 3 <h2> et 5 <p>
  • Une liste <ul> avec 4 items
  • Un <input> avec placeholder
  • Des éléments avec data-label et data-count

CSS requis :

  • ::before : icône décorative avant chaque <h2>
  • ::after : badge compteur avec attr(data-count)
  • ::first-letter : lettrine pour le premier paragraphe
  • ::first-line : première ligne en gras et couleur
  • ::selection : sélection personnalisée
  • ::marker : puces violettes pour la liste
  • ::placeholder : placeholder italic

9. Révision

Quiz rapide

  1. Quel est le symbole d'un pseudo-élément ?
  2. Quelle propriété est obligatoire pour ::before et ::after ?
  3. ::first-letter fonctionne sur un <span> ? Oui / Non
  4. Qu'est-ce que ::first-line cible exactement ?
  5. Peut-on cliquer sur un élément créé par ::before ?
  6. Quelle pseudo-élément personnalise le texte d'attente d'un input ?
  7. Quelle pseudo-élément personnalise les puces d'une liste ?
  8. Quelle est la différence entre ::before et :before ?
Réponses :
  1. :: (deux deux-points)
  2. content
  3. Non — uniquement sur les éléments bloc
  4. La première ligne visible du texte (s'adapte à la largeur)
  5. Non — les pseudo-éléments ne reçoivent pas d'événements
  6. ::placeholder
  7. ::marker
  8. Aucune différence fonctionnelle — ::before est la syntaxe officielle, :before est acceptée par rétrocompatibilité