Pendant des années, positionner une infobulle sous un bouton ou un menu contre son déclencheur passait par une bibliothèque JavaScript qui mesurait des rectangles à chaque défilement. Le positionnement d’ancrage CSS supprime cette dépendance. Devenu Baseline en 2026, il permet de rattacher un élément à un autre, de le repositionner quand il déborde de l’écran et de le masquer au bon moment, entièrement en CSS.
Le problème que résout le positionnement d’ancrage
Un menu déroulant, une infobulle ou un popover doivent se placer par rapport à un autre élément : le bouton qui les ouvre. Tant que cet ancrage n’existait pas en CSS, la seule solution fiable consistait à calculer les coordonnées en JavaScript. Des bibliothèques comme Floating UI ou, avant elle, Popper, existaient précisément pour cela : mesurer la position du déclencheur, celle de la fenêtre, puis recalculer à chaque défilement et à chaque redimensionnement.
Cette approche fonctionne, mais elle a un coût. Elle ajoute du JavaScript au paquet, impose des écouteurs d’événements sur le défilement, et introduit un décalage visuel possible entre le déplacement de la page et le repositionnement de l’élément. Le positionnement d’ancrage confie ce travail au moteur de rendu, qui l’effectue au bon moment, sans script intermédiaire.
Le tableau ci-dessous résume ce que change le passage d’une bibliothèque de positionnement au CSS natif, sur un composant de menu ou d’infobulle standard.
| Aspect | Bibliothèque JavaScript | Positionnement d’ancrage CSS |
|---|---|---|
| Poids ajouté | Quelques kilo-octets de script | Aucun script |
| Repositionnement au défilement | Recalcul via un écouteur d’événements | Assuré par le moteur de rendu |
| Repli hors écran | Logique de collision à écrire | position-try-fallbacks |
| Masquage quand l’ancre sort du champ | À gérer manuellement | position-visibility |
Ce que Floating UI faisait en JavaScript à chaque défilement, le navigateur le fait désormais nativement, au moment du rendu.
Les propriétés de base : anchor-name, position-anchor et anchor()
Le mécanisme repose sur deux rôles. Un élément est déclaré comme ancre grâce à anchor-name. Un autre, positionné en absolute ou fixed, se rattache à cette ancre avec position-anchor, puis lit ses côtés avec la fonction anchor().
.declencheur {
anchor-name: --menu-profil;
}
.infobulle {
position: absolute;
position-anchor: --menu-profil;
/* le haut de l'infobulle s'aligne sous le bas de l'ancre */
top: anchor(bottom);
left: anchor(left);
margin-top: 8px;
}
La fonction anchor() accepte les mots-clés de côté (top, bottom, start, end, center) et un pourcentage. Aucune coordonnée n’est écrite en dur : le placement suit l’ancre où qu’elle se trouve dans la page.
position-area : le placement en une déclaration
Pour les cas courants, anchor() côté par côté reste verbeux. La propriété position-area décrit le placement sur une grille de trois par trois centrée sur l’ancre, en une seule ligne.
.infobulle {
position: absolute;
position-anchor: --menu-profil;
/* placée sous l'ancre, alignée au centre horizontal */
position-area: bottom center;
margin-top: 8px;
}
Les valeurs se lisent comme un couple ligne / colonne : top left, bottom center, span-all pour occuper toute une bande. C’est la manière la plus lisible d’exprimer un placement standard.
Rester dans l’écran : position-try-fallbacks et @position-try
Un menu placé sous son bouton doit basculer au-dessus lorsqu’il n’y a plus de place en bas de l’écran. C’est le rôle des positions de repli. position-try-fallbacks énumère des solutions de remplacement que le moteur essaie dans l’ordre jusqu’à trouver celle qui tient dans la fenêtre.
.infobulle {
position: absolute;
position-anchor: --menu-profil;
position-area: bottom center;
/* si ça déborde en bas, retenter en miroir vertical, puis horizontal */
position-try-fallbacks: flip-block, flip-inline, flip-block flip-inline;
}
/* repli sur mesure, réutilisable */
@position-try --au-dessus {
position-area: top center;
margin-bottom: 8px;
margin-top: 0;
}
Les mots-clés flip-block et flip-inline couvrent l’essentiel des besoins : basculer verticalement ou horizontalement. Pour un contrôle plus fin, une règle @position-try nommée définit un jeu complet de propriétés à appliquer en repli.
Combiner avec le popover natif et masquer proprement
Le positionnement d’ancrage s’associe naturellement à l’attribut HTML popover, qui gère l’ouverture, la fermeture au clic extérieur et la couche supérieure sans JavaScript. L’ancre se déclare côté déclencheur, le popover se rattache côté CSS.
<button popovertarget="menu" style="anchor-name: --btn">Profil</button>
<div id="menu" popover style="position-anchor: --btn; position-area: bottom span-right">
<a href="/compte/">Compte</a>
<a href="/deconnexion/">Se déconnecter</a>
</div>
Reste le cas où l’ancre disparaît du champ de vision, par exemple lors d’un défilement : l’élément rattaché n’a plus de sens s’il flotte seul. La propriété position-visibility le masque automatiquement dès que son ancre sort de l’écran.
.infobulle {
position-visibility: anchors-visible;
}
Ne pas oublier l’accessibilité
Déléguer le placement au CSS ne dispense pas du travail sémantique. Un menu ouvert par l’attribut popover reçoit la gestion du focus et la fermeture par la touche Échap fournies par le navigateur, mais le lien entre le déclencheur et le contenu doit rester explicite pour les technologies d’assistance. Le bouton conserve un aria-expanded reflétant l’état d’ouverture, et le popover décrit son rôle lorsqu’il s’agit d’un menu de navigation.
<button popovertarget="menu" aria-expanded="false"
aria-controls="menu" style="anchor-name: --btn">Profil</button>
<nav id="menu" popover aria-label="Menu du compte"
style="position-anchor: --btn; position-area: bottom span-right">
<a href="/compte/">Compte</a>
<a href="/deconnexion/">Se déconnecter</a>
</nav>
Le positionnement, lui, reste purement visuel : il ne modifie ni l’ordre du document ni l’ordre de tabulation. Un élément rattaché visuellement au-dessus de son ancre demeure, dans l’arbre d’accessibilité, à la place qu’il occupe dans le code. C’est un atout, à condition de placer le popover à un endroit cohérent du balisage.
Ancre
position-area: bottom
Ancre
flip-block
→
Repli automatique quand la place manque en bas
État du support et stratégie de repli
Le positionnement d’ancrage a atteint le statut Baseline en 2026, une fois qu’il a été livré par défaut dans les trois moteurs principaux. Le placement de base fonctionne partout ; seules les positions de repli sur mesure sont arrivées un peu plus tard chez Safari.
| Moteur | Version | Prise en charge |
|---|---|---|
| Chrome / Edge | 125 (2024) | Complète, y compris les replis |
| Safari | 18.2 (base) · 18.4 (@position-try) | Placement dès 18.2, replis à partir de 18.4 |
| Firefox | Activé par défaut début 2026 | Complète |
Point de vigilance. Les positions de repli sur mesure définies par @position-try ne sont arrivées qu’avec Safari 18.4. Un composant qui dépend d’un repli complexe doit prévoir une dégradation propre sur les versions antérieures, plutôt que de laisser un menu déborder de l’écran.
Pour les publics encore sur d’anciennes versions, une amélioration progressive suffit : un placement statique par défaut, enrichi sous condition avec @supports.
.infobulle { top: 100%; left: 0; } /* repli statique */
@supports (position-anchor: --x) {
.infobulle { position-area: bottom center; }
}
Ce qu’il faut retenir
Le positionnement d’ancrage CSS remplace, pour la majorité des menus, infobulles et popovers, une dépendance JavaScript longtemps considérée comme incontournable. Trois propriétés couvrent l’essentiel : anchor-name pour désigner l’ancre, position-area pour placer, position-try-fallbacks pour rester dans l’écran. Associé à l’attribut popover, il permet de construire des composants d’interface complets sans script, avec un repli propre pour les navigateurs plus anciens.
J’ai retiré Floating UI de deux projets cette année, et le gain le plus net n’est pas la taille du paquet : c’est la disparition d’une classe entière de bugs de positionnement au défilement. Je garde toutefois une réserve — dès qu’un composant a besoin d’un placement vraiment dynamique piloté par la donnée, la logique JavaScript revient, et c’est très bien ainsi. Le natif couvre les cas courants, pas tous les cas. — Simon Janvier
Pour aller plus loin : la référence complète est documentée sur MDN — CSS anchor positioning.
