Le couple position: absolute + relative reste le réflexe dominant pour construire overlays et modales. Il fonctionne, mais il impose de gérer manuellement le containing block, l’empilement z-index et le verrouillage du focus. Nous allons voir pourquoi ce modèle mérite d’être remplacé dans la plupart des cas, et comment l’utiliser correctement quand il reste pertinent.
Containing block et absolute CSS positioning : le piège silencieux des overlays
Un élément en position: absolute se positionne par rapport à son plus proche ancêtre positionné (c’est-à-dire un élément dont la propriété position vaut relative, absolute, fixed ou sticky). Si aucun ancêtre ne correspond, le référentiel devient le bloc initial, souvent le viewport.
Pour une modale plein écran, on pense naturellement à poser position: fixed sur le fond sombre et position: absolute sur le contenu centré à l’intérieur. Le problème survient quand un ancêtre quelconque porte une propriété transform, filter, perspective ou will-change.
Ces propriétés créent un nouveau containing block pour tous les descendants positionnés. Conséquence : un élément fixed ou absolute se retrouve prisonnier d’un conteneur intermédiaire au lieu de couvrir le viewport. L’overlay se décale, se tronque ou disparaît derrière un overflow: hidden parent.
Nous recommandons un audit rapide avant de poser un overlay en absolute/fixed : remonter le DOM pour vérifier qu’aucun ancêtre n’applique de transform. Sur un projet avec des animations CSS ou des bibliothèques tierces, ce n’est jamais garanti.

Stacking context et z-index : pourquoi la modale absolute passe sous un composant
Le z-index ne fonctionne pas comme un index global. Chaque stacking context crée une pile locale, et un élément ne peut jamais sortir de la pile de son contexte parent, quel que soit la valeur de son z-index.
Un stacking context est créé par toute combinaison de position + z-index différent de auto, mais aussi par opacity inférieure à 1, transform, filter, isolation: isolate, et d’autres propriétés moins évidentes. Sur une application à composants (React, Vue, Svelte), chaque composant stylé risque de générer son propre contexte d’empilement sans que le développeur en ait conscience.
Résultat classique : la modale reçoit z-index: 9999, mais un header avec position: sticky; z-index: 10 dans un autre contexte d’empilement la recouvre partiellement. Monter le z-index ne change rien, les deux piles sont indépendantes.
- Vérifier les stacking contexts avec l’outil dédié dans les DevTools de Chrome (onglet Layers) ou l’extension CSS Stacking Context Inspector pour Firefox
- Placer le markup de la modale le plus haut possible dans le DOM, idéalement juste avant
</body>, pour minimiser les contextes parents - Éviter
z-indexsur les conteneurs intermédiaires quand ce n’est pas strictement nécessaire, chaque valeur explicite crée un nouveau contexte
Élément dialog et top layer : remplacer absolute par la plateforme native
L’élément <dialog> avec sa méthode .showModal() projette la modale dans le top layer du navigateur. Ce top layer est un plan de rendu situé au-dessus de tout le document, hors de tout stacking context. Les problèmes de z-index et de containing block disparaissent mécaniquement.
Le pseudo-élément ::backdrop fourni automatiquement par le navigateur remplace l’overlay sombre qu’on codait manuellement avec un div en position fixed. Il est stylable en CSS pur : couleur, opacité, backdrop-filter.
En prime, .showModal() gère nativement le piège de focus (le clavier reste à l’intérieur de la modale) et la fermeture par la touche Échap. Ce sont des fonctionnalités d’accessibilité que les implémentations manuelles oublient régulièrement ou implémentent de manière incomplète.
Animer l’entrée et la sortie d’une modale dialog
La difficulté historique de <dialog> était l’animation de fermeture : l’élément quittait le top layer instantanément, empêchant toute transition de sortie. La propriété CSS overlay combinée à transition-behavior: allow-discrete résout ce cas. Elle permet de maintenir l’élément dans le top layer pendant la durée de la transition, puis de le retirer une fois l’animation terminée.
Concrètement, on déclare les transitions sur opacity, transform et overlay ensemble, et le navigateur orchestre le retrait du top layer après la fin de l’animation. Plus besoin de setTimeout en JavaScript pour retarder la suppression.

Quand absolute reste le bon choix : tooltips, badges et positionnement local
Le positionnement absolute garde toute sa pertinence pour les éléments ancrés à un parent : badges de notification sur une icône, tooltips au survol, indicateurs visuels dans un composant délimité. Dans ces cas, le containing block est connu, maîtrisé, et le risque de conflit z-index reste faible.
Le pattern fiable :
- Le parent reçoit
position: relativesans z-index explicite (pas de nouveau stacking context inutile) - L’enfant reçoit
position: absoluteavec les propriétéstop,right,bottom,leftou le raccourciinsetpour le placer - Pour un overlay local (image avec légende superposée, carte avec badge),
inset: 0sur l’enfant absolute lui fait couvrir la totalité du parent - La propriété
anchor-positioning(CSS Anchor Positioning) commence à offrir une alternative déclarative pour ancrer un élément à un autre sans calcul JavaScript, notamment pour les tooltips et popovers
Pour les modales et overlays plein écran, <dialog> avec le top layer est la solution la plus robuste. Pour le positionnement local dans un composant, absolute sur un parent relative reste la méthode la plus directe et la moins fragile, à condition de ne pas laisser un transform ou un filter traîner dans la chaîne d’ancêtres.
Le choix entre les deux approches ne relève pas de la préférence. Il dépend d’un critère simple : l’élément doit-il flotter au-dessus de toute la page, ou rester ancré visuellement à un composant précis. La réponse à cette question tranche le positionnement à utiliser.


