CSS Anchor Positioning & Popover API : Plus de JS pour les Popups en 2026

前端工程

CSS Anchor Positioning : La « Proclamation d'Émancipation » pour les Développeurs Frontend

Chaque développeur frontend a connu cette douleur : utiliser JS pour calculer les positions de Tooltip, gérer le débordement des limites, écouter les événements scroll et resize... Maintenant, CSS peut gérer tout cela nativement.

Rétrospective historique : en 2016 nous utilisions Popper.js, en 2020 Floating UI, et en 2026 nous avons enfin le positionnement d'ancrage CSS natif. Après 10 ans, le positionnement des popups n'est plus un travail pour JS.

Évolution du Positionnement JS au Positionnement CSS

2016    jQuery offset() + calcul manuel
        Recalcul à chaque scroll/resize

2020    Floating UI / Popper.js
        Auto-flip, offset, détection des limites
        Mais nécessite toujours init et destroy en JS

2024    CSS Anchor Positioning (Chrome 125+)
        Positionnement déclaratif CSS pur
        Le navigateur gère les limites et le défilement nativement

2026    Anchor Positioning + Popover API
        Popups CSS pur : toggle sans JS, positionnement sans JS
        Solution déclarative complète de popups

anchor-name et position-anchor

Utilisation de Base

<div class="card">
  <button class="trigger">Plus d'Actions</button>
  <div class="dropdown">Contenu du menu déroulant</div>
</div>
.trigger {
  anchor-name: --my-anchor;
}

.dropdown {
  position: fixed;
  position-anchor: --my-anchor;
  top: anchor(bottom);
  left: anchor(left);
}

Référence de la Fonction anchor()

.tooltip {
  position: fixed;
  position-anchor: --trigger-anchor;

  /* Relatif aux bords de l'ancre */
  top: anchor(bottom);
  bottom: anchor(top);
  left: anchor(left);
  right: anchor(right);

  /* Points centraux de l'ancre */
  left: anchor(50%);
  top: anchor(50%);

  /* Avec décalage */
  top: calc(anchor(bottom) + 8px);
  left: calc(anchor(left) - 4px);
}

position-area : Positionnement en Grille de Neuf Cases

Syntaxe de Neuf Cases

┌─────────────┬─────────────┬─────────────┐
│  top left   │   top center│  top right  │
│             │             │             │
├─────────────┼─────────────┼─────────────┤
│ center left │   center    │ center right│
│             │             │             │
├─────────────┼─────────────┼─────────────┤
│ bottom left │bottom center│ bottom right│
│             │             │             │
└─────────────┴─────────────┴─────────────┘
.tooltip-below {
  position-area: bottom center;
}

.tooltip-right {
  position-area: center right;
}

.dropdown-below-left {
  position-area: bottom left;
}

position-fallback et Stratégie de Fallback Multiniveau

Auto-Flip lors du Débordement des Limites

.dropdown {
  position: fixed;
  position-anchor: --trigger;

  /* Préféré : sous l'ancre */
  top: anchor(bottom);
  left: anchor(left);

  position-fallback: --dropdown-fallback;
}

@position-fallback --dropdown-fallback {
  /* Fallback 1 : au-dessus de l'ancre */
  @try {
    bottom: anchor(top);
    left: anchor(left);
  }

  /* Fallback 2 : sous l'ancre, aligné à droite */
  @try {
    top: anchor(bottom);
    right: anchor(right);
  }

  /* Fallback 3 : au-dessus de l'ancre, aligné à droite */
  @try {
    bottom: anchor(top);
    right: anchor(right);
  }
}

Popover API : Couche de Popover Native

Utilisation de Base

<button popovertarget="my-popover">Ouvrir le Popover</button>

<div id="my-popover" popover>
  <p>Ceci est du contenu de Popover natif</p>
  <button popovertarget="my-popover" popovertargetaction="hide">Fermer</button>
</div>
[popover] {
  position: fixed;
  inset: unset;
  margin: 0;
  padding: 16px;
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  background: white;
  box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
}

Combinaison Popover + Anchor

<button class="menu-trigger" popovertarget="menu-popover">Menu</button>

<div id="menu-popover" popover class="menu-dropdown">
  <a href="/profile">Profil</a>
  <a href="/settings">Paramètres</a>
  <a href="/logout">Déconnexion</a>
</div>
.menu-trigger {
  anchor-name: --menu-anchor;
}

.menu-dropdown {
  position-anchor: --menu-anchor;
  position-area: bottom left;
  margin: 4px;
}

anchor-size() : Auto-Dimensionnement Basé sur l'Élément d'Ancrage

.trigger {
  anchor-name: --select-anchor;
}

.select-dropdown {
  position: fixed;
  position-anchor: --select-anchor;
  top: anchor(bottom);
  left: anchor(left);

  /* La largeur du menu déroulant suit le bouton déclencheur */
  width: anchor-size(width);

  /* Ou définir une largeur minimale */
  min-width: anchor-size(width);
}

Pratique : Composants UI Courants en CSS Pur

Tooltip

<span class="tooltip-trigger" tabindex="0">
  Aide
  <span class="tooltip-content" role="tooltip">Ceci est un tooltip d'aide</span>
</span>
.tooltip-trigger {
  anchor-name: --tt-anchor;
  position: relative;
  cursor: help;
  text-decoration: underline dotted;
}

.tooltip-content {
  position: fixed;
  position-anchor: --tt-anchor;
  position-area: top center;
  margin: 8px;
  padding: 6px 10px;
  background: #1f2937;
  color: white;
  border-radius: 4px;
  font-size: 13px;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.15s;

  position-fallback: --tt-fallback;
}

.tooltip-trigger:hover .tooltip-content,
.tooltip-trigger:focus .tooltip-content {
  opacity: 1;
}

@position-fallback --tt-fallback {
  @try { position-area: bottom center; }
  @try { position-area: center right; }
  @try { position-area: center left; }
}
<button class="dropdown-trigger" popovertarget="dd-menu">
  Options ▾
</button>
<div id="dd-menu" popover class="dropdown-menu">
  <button class="dropdown-item">Modifier</button>
  <button class="dropdown-item">Copier</button>
  <button class="dropdown-item">Supprimer</button>
</div>
.dropdown-trigger {
  anchor-name: --dd-anchor;
}

.dropdown-menu {
  position-anchor: --dd-anchor;
  position-area: bottom left;
  margin: 4px;
  width: anchor-size(width);
  min-width: 160px;
  padding: 4px;
  border-radius: 8px;
  background: white;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);

  position-fallback: --dd-fallback;
}

.dropdown-item {
  display: block;
  width: 100%;
  padding: 8px 12px;
  border: none;
  background: none;
  text-align: left;
  border-radius: 4px;
  cursor: pointer;
}

.dropdown-item:hover {
  background: #f3f4f6;
}

@position-fallback --dd-fallback {
  @try { position-area: top left; }
}

Comparaison avec Floating UI/Popper.js

Dimension CSS Anchor + Popover Floating UI
Dépendance JS Zéro JS 12Ko gzip
Performance Natif navigateur Calcul JS
Déclaratif CSS déclaratif JS impératif
Flip de limites position-fallback middleware flip()
Décalage margin/anchor() middleware offset()
Flèche Pseudo-élément CSS Élément SVG/HTML
Éléments virtuels Non supporté Supporté
Contenu dynamique Auto-suivi Nécessite update()
Support navigateurs Chrome 125+ Tous les navigateurs
Compatible SSR Pleinement compatible Nécessite JS client

Quand Vous Avez Encore Besoin de Bibliothèques JS

Scénarios nécessitant encore Floating UI :
1. Besoin de supporter les anciens navigateurs (Safari < 17.5, Firefox < 131)
2. Besoin de positionnement d'éléments virtuels (suivi du curseur)
3. Besoin de chaînes de middleware complexes (autoUpdate, size, hide)
4. Exigences de wrapper déclaratif pour React/Vue

Scénarios où CSS Anchor fonctionne :
1. Tooltip, Dropdown, Popover et autres popups standards
2. Seulement besoin de supporter les navigateurs modernes
3. Poursuivre zéro dépendance JS
4. Scénarios sensibles aux performances

Compatibilité des Navigateurs et Polyfill

État du Support

Navigateur Anchor Positioning Popover API
Chrome 125+
Edge 125+
Safari 17.5+
Firefox 131+
iOS Safari 17.5+

Solutions Polyfill

<script src="https://cdn.jsdelivr.net/npm/@oddbird/css-anchor-positioning@0.3.0/dist/css-anchor-positioning.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@oddbird/popover-polyfill@0.4.0/dist/popover.min.js"></script>

Combinaison avec @starting-style pour les Animations de Popup

[popover] {
  opacity: 0;
  transform: translateY(-8px) scale(0.95);
  transition: opacity 0.2s, transform 0.2s, display 0.2s allow-discrete;
  overlay: none;
}

[popover]:popover-open {
  opacity: 1;
  transform: translateY(0) scale(1);
  overlay: auto;
}

@starting-style {
  [popover]:popover-open {
    opacity: 0;
    transform: translateY(-8px) scale(0.95);
  }
}

Résumé

  1. CSS Anchor Positioning est la solution ultime pour le positionnement de popups — Zéro JS, déclaratif, natif du navigateur
  2. La Popover API rend le toggle de popups également sans JS — l'attribut popovertarget gère tout en une ligne
  3. position-fallback résout le débordement des limites — Plus de calculs JS pour le flip
  4. Tous les navigateurs majeurs le supportent en 2026 — Sûr pour la production

Après 10 ans, le positionnement des popups est enfin revenu là où il appartient : le CSS. Ce n'est pas une amélioration incrémentale — c'est un changement de paradigme, tout comme Flexbox a remplacé les mises en page en float.

Essayez ces outils exécutés localement dans le navigateur — aucune inscription requise →

#CSS锚点定位#Anchor Positioning#Popover API#弹出层#CSS