Niveau 19 — Le Positionnement

Le Positionnement

Comprendre comment positionner les éléments dans une page web. Du positionnement statique au positionnement sticky, en passant par les mystères du z-index et des contextes d'empilement.

1. Comprendre le Positionnement

En une phrase : La propriété position contrôle comment un élément est placé dans la page — statiquement (flux normal) ou selon un modèle de positionnement spécial (relatif, absolu, fixe ou sticky).

CSS offre 5 valeurs pour la propriété position. Chacune modifie la façon dont un élément interagit avec le flux normal (le flux par défaut où les blocs s'empilent de haut en bas et les inline de gauche à droite).

Les 5 valeurs de position

Valeur Hors du flux ? Se déplace avec offset ? Conteneur de référence
static Non Non Flux normal
relative Non Oui (décalage visuel) Lui-même (position d'origine)
absolute Oui Oui Conteneur positionné le plus proche
fixed Oui Oui Le viewport (fenêtre)
sticky Non (tant que pas threshold) Oui (au scroll) Zone de scroll parente
Règle d'or : position: relative sert surtout à créer un contexte de positionnement pour les enfants absolute, et à créer un contexte de pile (stacking context) pour le z-index. Les offsets sont rarement utilisés pour le décalage visuel.

2. Syntaxe détaillée

2.1 position: static

Définition : Valeur par défaut de tous les éléments. L'élément suit le flux normal du document. Les propriétés top, right, bottom, left et z-index sont ignorées.
.element {
  position: static; /* Défaut — peut être omis */
}
FLUX NORMAL (position: static)
┌──────────────────────────────────────┐
│  ┌────────────────────────────────┐  │
│  │        Bloc 1                  │  │
│  └────────────────────────────────┘  │
│  ┌────────────────────────────────┐  │
│  │        Bloc 2                  │  │
│  └────────────────────────────────┘  │
│  ┌────────────────────────────────┐  │
│  │        Bloc 3                  │  │
│  └────────────────────────────────┘  │
└──────────────────────────────────────┘
Les éléments s'empilent verticalement
Selon l'ordre du HTML

Le flux normal — position: static est invisible

2.2 position: relative

Définition : L'élément reste dans le flux normal (sa place originale est préservée), mais les propriétés top, right, bottom, left le décalent visuellement par rapport à sa position d'origine. Crée un contexte de positionnement pour les enfants absolute.
.element {
  position: relative;
  top: 10px;    /* Décalage vers le bas */
  left: 20px;   /* Décalage vers la droite */
}
position: relative + top: 10px + left: 20px

 Position d'origine          Position après décalage
 (la place reste)            (déplacement visuel)
┌──────────────────┐        ┌──────────────────┐
│                  │        │                  │
│   ┌──────────┐   │   →    │   ┌──────────┐   │
│   │  Élément │   │        │   │  Élément │   │ ← décalé
│   └──────────┘   │        │   └──────────┘   │
│                  │        │   ↑ 10px          │
└──────────────────┘        └──────────────────┘
                             ← 20px →

Le décalage relatif — l'espace d'origine est conservé

Propriétés offset (décalage)

Propriété Direction Effet
top: 10px Vers le bas Pousse l'élément 10px vers le bas depuis sa position
right: 10px Vers la gauche Pousse l'élément 10px vers la gauche depuis sa position
bottom: 10px Vers le haut Pousse l'élément 10px vers le haut depuis sa position
left: 10px Vers la droite Pousse l'élément 10px vers la droite depuis sa position
Piège fréquent : Avec position: relative, top: 10px pousse vers le bas (pas vers le haut). Avec position: absolute, c'est pareil — top: 0 colle à l'extérieur supérieur du conteneur parent.

2.3 position: absolute

Définition : L'élément est retiré du flux normal (les autres éléments l'ignorent) et positionné par rapport au conteneur de positionnement le plus proche (un ancêtre avec position autre que static, ou le <html>).
.parent {
  position: relative; /* Crée le contexte de positionnement */
}

.enfant {
  position: absolute;
  top: 0;
  right: 0;
}
CONTENANT (position: relative)
┌──────────────────────────────────────┐
│                                      │
│   L'enfant absolu est placé         │
│   par rapport aux bords de          │
│   CE conteneur.                     │
│                                      │
│                      ┌──────────┐   │
│                      │ Enfant   │ ← position: absolute
│                      │ absolute │   top: 0; right: 0
│                      └──────────┘   │
│                                      │
└──────────────────────────────────────┘

Si aucun ancêtre n'est positionné,
le conteneur est le <html>

L'élément absolu se positionne par rapport au conteneur positionné

Le conteneur de positionnement (containing block)

Avec parent relative
Parent
Enfant absolu
Avec grand-parent relative
Grand-parent
Parent (sans position)
Enfant absolu

Propriétés offset pour absolute

top: 10px; right: 10px
Top+Right
bottom: 10px; left: 10px
Bottom+Left
top: 0; left: 0; right: 0
Pleine largeur en haut

2.4 position: fixed

Définition : L'élément est retiré du flux normal et positionné par rapport au viewport (la fenêtre du navigateur). Il reste fixe même lors du défilement. Idéal pour les headers, boutons "retour en haut", barres latérales.
.header-fixe {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 1000;
}

.retour-en-haut {
  position: fixed;
  bottom: 2rem;
  right: 2rem;
}
┌─── VIEWPORT (fenêtre) ─────────────────┐
│ ┌─────────────────────────────────────┐ │
│ │ ═══ HEADER FIXE (top: 0) ═══════════│ │ ← reste ici
│ └─────────────────────────────────────┘ │    au scroll
│                                         │
│  Contenu scrollable :                   │
│  ┌───────────────────────────────────┐  │
│  │ Ligne 1                           │  │
│  │ Ligne 2                           │  │
│  │ Ligne 3 ← le contenu défile      │  │
│  │ ...                               │  │
│  └───────────────────────────────────┘  │
│                                         │
│                          ┌──────┐       │
│                          │ ↑Top │       │ ← aussi fixe
│                          └──────┘       │
└─────────────────────────────────────────┘

position: fixed — ancré au viewport, ignore le scroll

Piège avec fixed : Si un ancêtre a transform, filter, will-change ou contain, l'élément fixed se positionne par rapport à cet ancêtre, pas le viewport ! C'est une cause fréquente de bugs.

2.5 position: sticky

Définition : Comportement hybride : l'élément se comporte comme relative tant qu'il est dans la zone visible, puis passe en fixed (collé au seuil défini) quand on dépasse son seuil de défilement (top, bottom, left, right).
.en-tete-colonne {
  position: sticky;
  top: 0;       /* Se fixe en haut quand on scroll */
  z-index: 10;
}
AVANT le scroll           PENDANT le scroll
┌────────────────────┐    ┌────────────────────┐
│ ┌────────────────┐ │    │ ══ HEADER STICKY ══│ ← fixé au top: 0
│ │  HEADER STICKY │ │    ├────────────────────┤
│ ├────────────────┤ │    │ Item 5             │
│ │  Item 1        │ │    │ Item 6             │
│ │  Item 2        │ →    │ Item 7             │
│ │  Item 3        │ SCROLL│ Item 8             │
│ │  Item 4        │ │    │ Item 9             │
│ └────────────────┘ │    │ Item 10            │
└────────────────────┘    └────────────────────┘

sticky — relatif tant que dans la zone, fixé quand on dépasse le seuil

2.6 La propriété z-index

Définition : z-index contrôle l'ordre d'empilement (stacking order) des éléments qui se chevauchent. Plus la valeur est élevée, plus l'élément est devant. Ne fonctionne que sur les éléments positionnés (pas static).
.element-derriere {
  position: absolute;
  z-index: 1;
}

.element-devant {
  position: absolute;
  z-index: 10;
}
z-index: 1
z-index: 2
z-index: 3

Le contexte d'empilement (stacking context)

Un contexte d'empilement est créé par un élément qui regroupe ses enfants dans une "pile" indépendante. Les z-index des enfants ne peuvent pas dépasser l'élément parent qui crée le contexte.

Ce qui crée un stacking context :

┌─── CONTEXTE A (z-index: 1) ──────────────────────┐
│                                                   │
│  enfant-A-1 (z-index: 999)                       │
│  enfant-A-2 (z-index: 5)                         │
│                                                   │
│  ┌─── CONTEXTE B (z-index: 2) ───────────────┐   │
│  │                                            │   │
│  │  enfant-B-1 (z-index: 999)                │   │
│  │  enfant-B-2 (z-index: 5)                  │   │
│  │                                            │   │
│  └────────────────────────────────────────────┘   │
│                                                   │
└───────────────────────────────────────────────────┘

Résultat visuel (de devant à derrière) :
  1. enfant-A-1    (contexte A, z-index: 999)
  2. enfant-B-1    (contexte B, z-index: 999 mais B < A)
  3. enfant-A-2    (contexte A, z-index: 5)
  4. enfant-B-2    (contexte B, z-index: 5)

Le z-index: 999 de B ne peut PAS dépasser A car B est "bloqué"
dans son contexte (z-index: 2 < 1 de A... non, 2 > 1)
→ Les enfants de B ne peuvent PAS dépasser B,
  et les enfants de A ne peuvent PAS dépasser A.

Les z-index sont comparés au sein du même contexte d'empilement

Ordre d'empilement par défaut (sans z-index)

Overlay (couche de contenu)
Éléments avec z-index positif
Éléments inline (texte, images)
Éléments flottants (float)
Éléments block (flux normal)
Éléments avec z-index négatif
Arrière-plan (background/bordures)

Ordre d'empilement du fond vers le premier plan

Tableau comparatif des positions

Propriété static relative absolute fixed sticky
Hors du flux Non Non Oui Oui Non*
top/right/bottom/left Ignoré Décalage visuel Positionnement Positionnement Seuil de scroll
z-index Ignoré Fonctionne Fonctionne Fonctionne Fonctionne
Scroll avec la page Oui Oui Oui Non Oui puis fixe
Espace réservé Oui Oui Non Non Oui*
Conteneur de référence Lui-même Parent positionné Viewport Parent scrollable

* sticky: hors du flux uniquement quand il est "collé"

3. Visualisation interactive

Démo des 5 positions

static
Élément

Flux normal, pas de décalage

relative
Décalé

Décalé visuellement, place préservée

absolute
Absolu

Hors du flux, positionné dans le parent

sticky
En-tête sticky ↓
Item 1
Item 2
Item 3
Item 4
Item 5
Item 6
Item 7

4. Exemples progressifs

Exemple 1 : Badge sur une image

<div class="image-conteneur">
  <img src="photo.jpg" alt="Photo">
  <span class="badge">Nouveau</span>
</div>

.image-conteneur {
  position: relative;   /* Contexte pour l'enfant absolute */
  display: inline-block;
}

.badge {
  position: absolute;
  top: 8px;
  right: 8px;
  background: red;
  color: white;
  padding: 4px 8px;
  border-radius: 999px;
  font-size: 0.75rem;
}

Exemple 2 : Tooltip

<button class="tooltip-trigger">
  Survolez-moi
  <span class="tooltip-text">Ceci est un tooltip !</span>
</button>

.tooltip-trigger {
  position: relative;
}

.tooltip-text {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  background: #1e293b;
  color: white;
  padding: 6px 12px;
  border-radius: 4px;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s;
}

.tooltip-text::after {
  content: "";
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  border: 5px solid transparent;
  border-top-color: #1e293b;
}

.tooltip-trigger:hover .tooltip-text {
  opacity: 1;
}

Exemple 3 : Modal overlay

.modal-backdrop {
  position: fixed;
  inset: 0;              /* top: 0; right: 0; bottom: 0; left: 0 */
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
}

.modal-box {
  background: white;
  padding: 2rem;
  border-radius: 8px;
  max-width: 500px;
  width: 90%;
}

Exemple 4 : Sidebar sticky dans un layout

.layout {
  display: flex;
  gap: 2rem;
}

.sidebar {
  position: sticky;
  top: 1rem;
  align-self: flex-start;
  width: 250px;
}

.contenu {
  flex: 1;
}

Exemple 5 : Header sticky avec z-index

.header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: white;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

/* Les dropdowns du menu ont besoin d'un z-index plus élevé */
.nav-dropdown {
  position: absolute;
  top: 100%;
  z-index: 200;
}

5. Erreurs fréquentes

Erreur 1 : Utiliser z-index sans positionnement
/* ❌ FAUX — z-index est ignoré */
.bloc {
  z-index: 100;
}

/* ✅ CORRECT */
.bloc {
  position: relative;  /* ou absolute, fixed, sticky */
  z-index: 100;
}
Erreur 2 : Mettre un z-index énorme pour "être sûr"
/* ❌ MAUVAISE PRATIQUE */
.dropdown { z-index: 999999; }
.modal { z-index: 9999999; }
.header { z-index: 99999; }

/* ✅ BON — Système de z-index hiérarchique */
:root {
  --z-header: 100;
  --z-dropdown: 200;
  --z-modal: 300;
  --z-notification: 400;
}
.header { z-index: var(--z-header); }
.dropdown { z-index: var(--z-dropdown); }
.modal { z-index: var(--z-modal); }
.notification { z-index: var(--z-notification); }
Erreur 3 : Oublier que fixed est cassé par transform
/* ❌ Le header fixe ne marche plus ! */
.parent-avec-transform {
  transform: scale(1);
}

.header-fixe {
  position: fixed;
  top: 0;
  /* Se positionne par rapport au parent, pas au viewport ! */
}

/* ✅ Solution : éviter transform sur les ancêtres
   ou utiliser un autre positionnement */
Erreur 4 : Absolute sans conteneur positionné
/* ❌ L'enfant se positionne par rapport au <html> */
.conteneur {
  /* pas de position */
}
.conteneur .enfant {
  position: absolute;
  top: 0; left: 0;
  /* → en haut à gauche de TOUTE la page ! */
}

/* ✅ Ajouter position: relative au parent */
.conteneur {
  position: relative;
}
Erreur 5 : Oublier inset: 0 pour les overlays
/* ❌ Incomplet — peut laisser des trous */
.overlay {
  position: fixed;
  top: 0;
  left: 0;
  /* bottom et right non définis ! */
}

/* ✅ Utiliser inset pour les 4 côtés */
.overlay {
  position: fixed;
  inset: 0;
}
Erreur 6 : Sticky ne fonctionne pas
/* ❌ Le parent empêche sticky de marcher */
.parent {
  overflow: hidden;  /* ou overflow: auto, scroll */
}
.enfant {
  position: sticky;
  top: 0;
  /* Ne fonctionnera jamais ! */
}

/* ✅ Le parent ne doit pas avoir overflow caché
   (sauf si c'est le conteneur de scroll voulu) */

6. Bonnes pratiques

Système de z-index hiérarchique :
/* Établir des niveaux clairs au début du projet */
:root {
  --z-base: 1;
  --z-dropdown: 100;
  --z-sticky: 200;
  --z-header: 300;
  --z-overlay: 400;
  --z-modal: 500;
  --z-toast: 600;
  --z-tooltip: 700;
}

/* Utiliser les variables partout */
.header { z-index: var(--z-header); }
.dropdown { z-index: var(--z-dropdown); }
.modal-backdrop { z-index: var(--z-overlay); }
.modal-content { z-index: var(--z-modal); }
.toast { z-index: var(--z-toast); }
Créer un contexte d'empilement explicite :
/* Utiliser isolation pour isoler un composant */
.composant {
  isolation: isolate;
  /* Crée un stacking context sans effet visuel */
  /* Les z-index internes ne déborderont pas */
}
Patterns de positionnement les plus courants :
  • 📌 Badge sur image → parent relative, badge absolute
  • 📌 Tooltip → trigger relative, tooltip absolute
  • 📌 Header stickysticky + z-index
  • 📌 Overlay/Modalfixed + inset: 0
  • 📌 Sidebar stickysticky + align-self: flex-start
  • 📌 Retour en hautfixed + bottom/right
  • 📌 Dropdownrelative (trigger) + absolute (menu)
  • 📌 Lightboxfixed + z-index élevé
Préférer transform aux propriétés de flux :
/* ❌ Lent (déclenche le layout) */
.enfant {
  transition: top 0.3s, left 0.3s;
}

/* ✅ Rapide (GPU accelerated) */
.enfant {
  transition: transform 0.3s;
}
.enfant:hover {
  transform: translate(20px, 10px);
}

7. Mini-défi

Défi 1 : Tooltip pure CSS

Créez un tooltip qui apparaît au survol d'un bouton, positionné au-dessus avec une flèche vers le bas.

<button class="tooltip-trigger">
  Info
  <span class="tooltip-text">Tooltip ici</span>
</button>

.tooltip-trigger { position: relative; }
.tooltip-text {
  position: absolute;
  bottom: calc(100% + 10px);
  left: 50%;
  transform: translateX(-50%);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s;
}
.tooltip-trigger:hover .tooltip-text { opacity: 1; }

Défi 2 : Badge sur image

Créez une carte avec une image et un badge "Promo" positionné en haut à droite.

Défi 3 : Header sticky

Créez un header qui reste collé en haut au scroll avec un z-index suffisant pour rester au-dessus du contenu.

Défi 4 : Overlay modal

Créez un overlay semi-transparent qui couvre toute la page avec une boîte de dialogue centrée.

.overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
}

.modal {
  background: white;
  padding: 2rem;
  border-radius: 8px;
  min-width: 300px;
}

Défi 5 : Menu dropdown

Créez un menu déroulant qui s'affiche au clic sur un bouton, positionné juste en dessous.

8. Projets pratiques

Projet 1 : Sticky header + sidebar

Créez une page avec un header sticky, une sidebar sticky, et un contenu long qui défile. La sidebar doit rester visible quand on scroll.

Projet 2 : Modal avec overlay

Créez un bouton qui ouvre une modale centrée avec un fond semi-transparent. La modale doit avoir un titre, un contenu et un bouton de fermeture.

Projet 3 : Galerie avec overlays

Créez une galerie d'images où chaque image a un badge (position: absolute) et un overlay au survol montrant le titre et la description.

Projet 4 : Tooltip system

Créez un système de tooltips avec 4 positions (top, bottom, left, right), chacune avec une flèche. Utilisez les propriétés de positionnement et le pseudo-élément ::after pour la flèche.

Projet 5 : Notification popups

Créez des notifications positionnées en fixed en haut à droite, avec un système de z-index pour qu'elles apparaissent au-dessus du contenu et les unes au-dessus des autres.

9. Révision

Récapitulatif des concepts clés

Concept Propriété Usage principal
Positionnement position static, relative, absolute, fixed, sticky
Offset top, right, bottom, left Décalage ou positionnement
Empilement z-index Ordre avant/arrière-plan
Couche complète inset Raccourci pour top+right+bottom+left
Contexte d'empilement isolation Créer un contexte isolé

Quiz rapide

  1. Quelle est la valeur par défaut de position ?
  2. Quelle position retire l'élément du flux normal ?
  3. Par rapport à quoi se positionne un élément absolute ?
  4. Pourquoi z-index ne fonctionne pas sur un élément static ?
  5. Quelle position est idéale pour un header qui reste visible au scroll ?
  6. Qu'est-ce qu'un stacking context ?
  7. Pourquoi position: fixed peut ne pas fonctionner ?
  8. Quelle propriété raccourci remplace top+right+bottom+left ?
  9. Comment créer un contexte d'empilement sans effet visuel ?
  10. Quelle est la différence entre relative et absolute ?
Réponses :
  1. static
  2. absolute, fixed et sticky (quand collé)
  3. Le conteneur de positionnement le plus proche (ancêtre avec positionstatic), ou le <html>
  4. z-index ne fonctionne que sur les éléments positionnés
  5. position: sticky + top: 0 + z-index
  6. Un groupe d'éléments qui forment une unité d'empilement indépendante
  7. Quand un ancêtre a transform, filter ou will-change, l'élément se positionne par rapport à cet ancêtre
  8. inset
  9. isolation: isolate
  10. relative reste dans le flux (place préservée), absolute en sort

Cheat sheet rapide

/* Badge sur image */
.parent { position: relative; }
.badge { position: absolute; top: 8px; right: 8px; }

/* Tooltip */
.trigger { position: relative; }
.tooltip {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
}

/* Overlay modal */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.5);
  z-index: 1000;
}

/* Header sticky */
.header {
  position: sticky;
  top: 0;
  z-index: 100;
}

/* Sidebar sticky */
.sidebar {
  position: sticky;
  top: 1rem;
  align-self: flex-start;
}

/* Retour en haut */
.back-top {
  position: fixed;
  bottom: 2rem;
  right: 2rem;
}

/* Système de z-index */
:root {
  --z-dropdown: 100;
  --z-header: 200;
  --z-modal: 300;
  --z-toast: 400;
}