Positionnement CSS et Systemes de Coordonnees
La plupart des tutoriels vous disent ce que fait position: absolute. Celui-ci vous montre comment il pense -- comme un systeme de coordonnees avec origine, axes et containing block.
Demo en Direct : Basculer les Modes de Positionnement
Choisissez une valeur de position et faites glisser les curseurs. La boite rouge se repositionne et l'affichage des coordonnees vous montre exactement ou se trouve son point d'origine et comment top/left se traduisent en decalages de pixels. C'est le moyen le plus rapide d'interioriser la difference entre relative et absolute.
Le Positionnement comme Systeme de Coordonnees, Pas Regle de Layout
Voici le changement mental qui fait cliquer le positionnement CSS : top, right, bottom et left sont des coordonnees, pas des marges. Quand vous ecrivez top: 50px, vous placez l'element a 50 pixels en dessous d'un point d'origine specifique. La question est : origine de quoi ?
Chaque element positionne vit dans un containing block (bloc conteneur) -- la boite qui definit son origine de coordonnees. Voyez-le comme le point (0, 0) pour cet element. Le containing block est different selon la valeur de position que vous utilisez, et c'est la chose la plus confuse du positionnement CSS.
Pour position: absolute et position: fixed, l'element est retire entierement du flux normal du document. Ses coordonnees sont mesurees par rapport au containing block, pas par rapport a ses freres ou parent dans le flux normal. C'est pourquoi un element en position absolue peut superposer d'autre contenu -- il a quitte le systeme de coordonnees du flux du document.
Les Cinq Valeurs de position, Selon une Perspective de Coordonnees
| Valeur | Origine des Coordonnees (Containing Block) | Dans le Flux Normal ? | Usage Commun |
static (par defaut) | Pas d'origine -- top/left ignores | Oui, suit l'ordre du document | Tout ce qui n'a pas besoin de positionnement explicite |
relative | La position originale de l'element dans le flux | Oui, mais decale visuellement (espace original preserve) | Ajustements fins, etablir un containing block pour les enfants |
absolute | Ancetre positionne le plus proche (tout non-static), ou le containing block initial | Non -- retire du flux, les autres elements remplissent son espace | Infobulles, badges, overlays positionnes relatif au parent |
fixed | Le viewport (fenetre du navigateur), sauf si un ancetre a transform/filter/perspective | Non -- retire du flux | Barres de navigation fixes, boutons flottants, bannieres de cookies |
sticky | Ancetre de defilement le plus proche ; bascule entre relatif-au-flux et fixe au defilement | Oui, jusqu'a atteindre le seuil de defilement | En-tetes de tableau, navigation de section qui reste au defilement |
Le tableau ci-dessus est la reference. Deballonnen maintenant les trois choses qui causent le plus de confusion dans la pratique.
Containing Block : Le Concept que la Plupart des Tutoriels Passent sous Silence
Si vous devez retenir une chose de cette page, que ce soit celle-ci : position: absolute n'est pas relatif a l'element parent. Il est relatif a l'ancetre positionne le plus proche -- le premier ancetre en remontant l'arbre qui a position avec une valeur autre que static.
Cela piege tout le monde la premiere fois. Vous mettez position: absolute sur un enfant, vous definissez top: 0; left: 0;, et l'element s'envole au coin de la page au lieu du coin du parent. La raison : le parent a position: static (par defaut), donc le navigateur remonte l'arbre cherchant un ancetre positionne, n'en trouve aucun, et utilise le viewport comme containing block.
La solution est toujours la meme : ajoutez position: relative au parent. Cela etablit le parent comme containing block, et maintenant le top/left de l'enfant sont mesures depuis le bord de padding du parent.
Regle generale : si vous utilisez position: absolute sur un enfant, le parent a presque surement besoin de position: relative sans decalage. Ce motif -- parent relative, enfant absolute -- est le cheval de bataille du positionnement d'overlays, d'infobulles et de badges.
Stacking Contexts : Le Systeme de Coordonnees de l'Axe Z
Le positionnement gere X et Y. z-index gere Z -- mais il ne fonctionne pas comme la plupart des gens le pensent. z-index ne fonctionne que dans un stacking context (contexte d'empilement), et un stacking context n'est pas la meme chose que le document.
Voyez un stacking context comme une couche isolee. Les elements a l'interieur peuvent s'empiler relativement entre eux, mais la couche entiere est positionnee comme une unite contre les autres couches. Donc un z-index: 9999 dans un stacking context peut toujours etre derriere un z-index: 1 dans un stacking context different de niveau superieur.
Qu'est-ce qui cree un stacking context ?
- L'element racine (
<html>)
position: absolute ou position: relative avec z-index different de auto
position: fixed ou position: sticky (toujours, independamment du z-index)
- Tout element avec
opacity inferieur a 1
- Tout element avec
transform, filter, perspective, backdrop-filter ou will-change
mix-blend-mode different de normal
isolation: isolate
La consequence pratique : si votre modale avec z-index: 9999 apparait derriere un menu deroulant avec z-index: 10, c'est presque certainement parce que la modale est dans un stacking context (cree par un transform ou opacity sur un ancetre) qui se trouve lui-meme sous le stacking context du menu deroulant. Vous ne pouvez pas regler ca en augmentant le z-index de la modale -- vous devez sortir la modale du stacking context de l'ancetre, ou supprimer la propriete qui le cree.
Unites de Viewport et Positionnement Responsive
Quand vous utilisez position: fixed ou position: absolute avec des decalages en pourcentage, ces pourcentages sont relatifs aux dimensions du containing block, pas a la taille de l'element lui-meme. top: 50% signifie 50% de la hauteur du containing block.
Les unites de viewport vous permettent de positionner relativement a la fenetre reelle du navigateur :
| Unite | Relatif A | Cas d'Usage |
vw / vh | 1% de la largeur / hauteur du viewport | Overlays plein ecran, barres laterales fixes |
dvw / dvh | 1% du viewport dynamique (tient compte de la barre URL mobile) | Positionnement fixe mobile-first -- evite le saut de la barre URL de Safari iOS |
svw / svh | 1% du viewport minimal possible | Elements qui ne doivent jamais etre caches derriere l'UI du navigateur |
lvw / lvh | 1% du viewport maximal possible | Images de fond plein cadre |
Les unites dvh / dvw / svh / lvh sont plus recentes et resolvent le probleme de Safari mobile ou 100vh inclut la zone derriere la barre URL, causant la coupure du contenu. Utilisez 100dvh au lieu de 100vh pour les elements qui doivent remplir le viewport visible.
Motifs Reels qui Fonctionnent Vraiment
Overlay de Modale Centre
Le motif pour une modale centree qui fonctionne partout. La cle est de combiner position: fixed avec inset: 0 (raccourci pour les quatre cotes) et place-items: center :
.modal-backdrop {
position: fixed;
inset: 0; /* top:0; right:0; bottom:0; left:0 */
background: rgba(0,0,0,.5);
display: grid;
place-items: center; /* centers the modal */
z-index: 1000;
}
.modal {
background: #fff;
border-radius: 12px;
padding: 2rem;
max-width: 90vw;
max-height: 90vh;
overflow: auto;
}
En-tete de Tableau Sticky
position: sticky sur un en-tete de tableau est le moyen le plus propre de garder les etiquettes de colonne visibles pendant le defilement. L'astuce : top: 0 definit quand il s'accroche, et le conteneur de defilement doit etre le parent de defilement du tableau :
.table-scroll {
max-height: 400px;
overflow: auto;
}
.table-scroll thead th {
position: sticky;
top: 0;
background: #fff; /* must be opaque */
z-index: 1;
}
Infobulle au Survol
Le motif parent relative / enfant absolute pour les infobulles. L'infobulle est cachee par defaut et revelee au survol :
.tooltip-trigger {
position: relative; /* containing block for tooltip */
display: inline-block;
}
.tooltip {
position: absolute;
bottom: 100%; /* sits above the trigger */
left: 50%;
transform: translateX(-50%); /* horizontal center */
margin-bottom: 8px;
padding: .5rem .75rem;
background: #1a1a1a;
color: #fff;
border-radius: 6px;
font-size: .85rem;
white-space: nowrap;
opacity: 0;
pointer-events: none;
transition: opacity .2s;
}
.tooltip-trigger:hover .tooltip {
opacity: 1;
}
Cadre de Decision : Quelle position Utiliser
Arretez de memoriser ce que fait chaque valeur. Utilisez ce flux de decision a la place :
L'element doit-il superposer un autre contenu ou sortir du flux normal ?
Non → Utilisez static (par defaut). Utilisez Flexbox ou Grid pour le layout.
Oui, temporairement lors d'interaction (menu deroulant, infobulle) → relative sur le parent, absolute sur l'enfant.
L'element doit-il rester visible au defilement de la page ?
Oui, toujours → fixed (verifiez les transform sur les ancetres !)
Oui, mais seulement apres avoir defile au-dela d'un point → sticky.
Voulez-vous seulement decaler legerement un element de sa position normale ?
Oui → relative avec de petits decalages top/left.
FAQ
Pourquoi mon element z-index:9999 apparait derriere un element z-index:1 ?
Stacking contexts. Votre element z-index:9999 est probablement dans un stacking context (cree par transform, opacity ou position:fixed sur un ancetre) qui se trouve sous le stacking context contenant l'element z-index:1. Augmenter le numero n'aidera pas. Deplacez l'element hors de l'ancetre qui cree le stacking context, ou supprimez cette propriete.
Pourquoi mon element position:fixed defile avec la page ?
Un ancetre a transform, filter, perspective, will-change ou contain. Ces proprietes creent un containing block pour les descendants fixed, les faisant se comporter comme absolute. Trouvez et supprimez la propriete sur l'ancetre, ou deplacez l'element fixed plus haut dans le DOM.
Quelle est la difference entre position: relative et un decalage de margin ?
Les deux deplacent l'element visuellement, mais position: relative preserve l'espace original de l'element dans le layout -- les autres elements ne se refluident pas pour combler le vide. Un margin decale l'element et provoque le refluidage des elements environnants. Utilisez relative quand vous voulez decaler sans affecter les freres.
Devrais-je utiliser inset au lieu de top/right/bottom/left ?
Oui, pour le code moderne. inset: 0 est le raccourci de top:0; right:0; bottom:0; left:0. Vous pouvez aussi faire inset: 10px 20px pour vertical/horizontal. C'est plus court, plus lisible et a un bon support (97%+).
position affecte-t-il les performances ?
position: fixed et position: sticky peuvent causer des repeints plus frequents pendant le defilement car le navigateur doit les repositionner a chaque frame. Ajouter will-change: transform peut aider le navigateur a optimiser, mais une utilisation excessive de will-change augmente la consommation memoire. Testez sur de vrais appareils si vous voyez des saccades de defilement.
Comment positionner quelque chose relatif au centre du viewport ?
Utilisez position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); ou l'approche moderne : position: fixed; inset: 0; margin: auto; width: votre-largeur; height: votre-hauteur;. Les deux centrent l'element. L'approche transform est plus flexible pour les tailles inconnues.