Dans ce chapitre, on va s'intéresser au positionnement en CSS. C'est un mécanisme très pratique dès qu'on veut afficher un élément au-dessus d'un autre, créer une modale, placer un badge de notification ou faire en sorte qu'un bloc reste visible pendant le défilement.
On va repartir d'un cas concret : imaginer une boîte de dialogue qui s'affiche par-dessus une page déjà existante.
La propriété position
La propriété position permet de changer la manière dont un élément est placé dans le document.
Par défaut, tous les éléments ont :
position: static;
Cela signifie qu'ils suivent le flux normal du document. Les blocs s'empilent, les éléments inline se placent les uns à côté des autres, et les propriétés comme top, right, bottom ou left n'ont pas d'effet.
À partir du moment où on change cette valeur, le comportement de l'élément devient différent.
position: absolute
Lorsqu'un élément passe en absolute, il se produit deux choses importantes :
- l'élément sort du flux du document.
- il peut être positionné précisément avec
top,right,bottometleft.
Sortir du flux signifie que les autres éléments ne tiennent plus compte de lui. Ils se comportent comme s'il n'était pas là.
Autre détail important : un élément en position absolue reprend souvent une largeur minimale, au lieu de s'étendre naturellement comme un bloc.
Une fois l'élément en position absolue, on peut préciser sa position par rapport aux bords :
.dialog {
position: absolute;
top: 10px;
left: 10px;
}
Ici, l'élément sera placé en haut à gauche, à 10px du bord.
On peut faire la même chose avec les autres côtés :
bottom: 10px;
right: 10px;
Et si on précise les quatre côtés, l'élément s'étire pour respecter ces contraintes. Sa largeur et sa hauteur deviennent alors dépendantes des quatre valeurs.
.dialog {
position: absolute;
top: 10px;
right: 10px;
bottom: 10px;
left: 10px;
}
La propriété raccourcie inset
CSS propose aussi une propriété raccourcie pour top, right, bottom et left :
.dialog {
position: absolute;
inset: 10px;
}
Cette écriture revient à écrire :
top: 10px;
right: 10px;
bottom: 10px;
left: 10px;
Comme pour margin ou padding, on peut utiliser plusieurs valeurs :
1valeur : tous les côtés2valeurs : haut/bas puis droite/gauche3valeurs4valeurs : haut, droite, bas, gauche
L'ordre reste toujours celui des aiguilles d'une montre.
L'empilement avec z-index
Quand plusieurs éléments positionnés se recouvrent, il faut déterminer lequel apparaît au-dessus. C'est le rôle de z-index.
.dialog {
position: absolute;
z-index: 3;
}
Plus la valeur est grande, plus l'élément sera placé au-dessus.
.dialog-1 {
z-index: 3;
}
.dialog-2 {
z-index: 2;
}
Dans cet exemple, .dialog-1 passera au-dessus de .dialog-2.
Si aucun z-index n'est défini, c'est l'ordre HTML qui détermine l'empilement : l'élément déclaré le plus tard dans le document apparaîtra au-dessus.
position: relative
La valeur relative a deux usages différents.
Le premier, et de loin le plus fréquent, consiste à créer un repère pour un enfant en position absolue.
.btn-border {
position: relative;
}
Quand un élément en absolute cherche son repère, il remonte dans ses ancêtres jusqu'à trouver un élément positionné. S'il trouve un parent en relative, les valeurs top, right, bottom et left seront calculées par rapport à ce parent au lieu de l'écran.
Décaler un élément avec relative
Le second usage de position: relative consiste à décaler l'élément lui-même.
.btn-border {
position: relative;
top: 30px;
right: 40px;
}
Dans ce cas, l'élément reste dans le flux du document, continue à occuper sa place, mais il est visuellement décalé.
Ce n'est pas l'usage le plus fréquent, mais il faut savoir que c'est possible.
position: fixed
La valeur fixed ressemble à absolute, mais avec une différence essentielle : l'élément est toujours positionné par rapport à l'écran visible.
.dialog {
position: fixed;
inset: 0;
}
La grande différence avec absolute, c'est que l'élément suit le défilement.
Même si on fait défiler la page, un élément en fixed reste collé à la fenêtre.
Cette valeur est particulièrement utile pour :
- les modales
- certaines notifications
- les boutons flottants
- les barres fixes
Contrairement à absolute, fixed n'est pas influencé par un parent en relative. Son repère reste toujours l'écran.
position: sticky
La valeur sticky est un peu particulière, car elle mélange deux comportements : l'élément se comporte normalement dans le flux au départ puis il devient collant quand il s'apprète à sortir de l'écran.
.hero {
position: sticky;
top: 0;
}
Ici, l'élément se comportera normalement tant qu'il n'aura pas atteint le haut de la fenêtre. Une fois cette limite franchie, il restera collé en haut comme un élément en position fixed.
C'est particulièrement utile pour :
- des entêtes qui suivent le scroll
- des menus latéraux
- des sommaires
Un piège courant avec sticky
sticky ne fonctionne que si l'élément a la possibilité de se déplacer.
Par exemple, dans une mise en page flex, si un élément est étiré à toute la hauteur disponible à cause de align-items: stretch, il peut devenir impossible de le rendre sticky.
Dans ce cas, il faut souvent changer l'alignement du conteneur :
.layout {
display: flex;
align-items: flex-start;
}
.summary {
position: sticky;
top: 0;
}
Avec flex-start, le bloc reprend une hauteur normale et sticky peut enfin fonctionner correctement.
C'est un piège très fréquent lorsqu'on veut faire un sommaire collant à côté d'un long contenu.
Le contexte d'empilement
Il y a un dernier point un peu plus technique mais important : le contexte d'empilement.
Dès qu'on commence à utiliser des éléments positionnés avec des z-index, on crée des calques. Et ces calques limitent la manière dont les enfants peuvent se superposer.
Prenons un exemple :
- un bouton
Aenrelativeavecz-index: 1 - un bouton
Benrelativeavecz-index: 2 - une notification à l'intérieur du bouton
Aavecz-index: 999
On pourrait croire que la notification passera au-dessus de tout. Pourtant, non.
Pourquoi ? Parce qu'elle reste enfermée dans le contexte d'empilement de son parent. Si le parent est en dessous de l'autre bouton, tous ses enfants le resteront aussi, même avec un z-index énorme.
Si il vous semble que vos valeurs de z-index "ne fonctionnent pas", le problème vient souvent de là.