Skip to content

The publication for web craftspeople Friday, 21 August 2026

Design & UX

CSS anchor positioning: menus, tooltips and popovers without JavaScript

CSS anchor positioning reached Baseline in 2026: the three major engines can now tether one element to another without a line of JavaScript. Menus, tooltips and popovers used to rely on position-calculating libraries; CSS takes the job back.

For years, placing a tooltip under a button or a menu against its trigger meant reaching for a JavaScript library that measured rectangles on every scroll. CSS anchor positioning removes that dependency. Now Baseline in 2026, it lets you tether one element to another, reposition it when it overflows the viewport, and hide it at the right moment, entirely in CSS.

The problem anchor positioning solves

A dropdown menu, a tooltip or a popover must be placed relative to another element: the button that opens it. As long as that anchoring did not exist in CSS, the only reliable option was to compute coordinates in JavaScript. Libraries such as Floating UI, and Popper before it, existed precisely for this: measure the trigger’s position, measure the viewport, then recompute on every scroll and resize.

That approach works, but it has a cost. It adds JavaScript to the bundle, requires scroll event listeners, and introduces a possible visual lag between the page moving and the element repositioning. Anchor positioning hands that work to the rendering engine, which does it at the right time, with no intermediate script.

The table below sums up what changes when you move from a positioning library to native CSS on a standard menu or tooltip component.

AspectJavaScript libraryCSS anchor positioning
Added weightA few kilobytes of scriptNo script
Repositioning on scrollRecompute via an event listenerHandled by the rendering engine
Off-screen fallbackCollision logic to writeposition-try-fallbacks
Hiding when the anchor leaves viewTo handle manuallyposition-visibility

What Floating UI did in JavaScript on every scroll, the browser now does natively, at render time.

The core properties: anchor-name, position-anchor and anchor()

The mechanism relies on two roles. An element is declared as an anchor with anchor-name. Another, positioned absolute or fixed, tethers to that anchor with position-anchor, then reads its sides with the anchor() function.

.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;
}

The anchor() function accepts side keywords (top, bottom, start, end, center) and a percentage. No coordinate is hard-coded: placement follows the anchor wherever it sits on the page.

position-area: placement in one declaration

For common cases, side-by-side anchor() stays verbose. The position-area property describes placement on a three-by-three grid centred on the anchor, in a single line.

.infobulle {
  position: absolute;
  position-anchor: --menu-profil;
  /* placée sous l'ancre, alignée au centre horizontal */
  position-area: bottom center;
  margin-top: 8px;
}

Values read as a row / column pair: top left, bottom center, span-all to cover a whole band. It is the most readable way to express a standard placement.

Staying on screen: position-try-fallbacks and @position-try

A menu placed under its button must flip above it when there is no more room at the bottom of the screen. That is the role of fallback positions. position-try-fallbacks lists alternatives that the engine tries in order until it finds one that fits the viewport.

.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;
}

The flip-block and flip-inline keywords cover most needs: flip vertically or horizontally. For finer control, a named @position-try rule defines a full set of properties to apply as a fallback.

Combining with the native popover and hiding cleanly

Anchor positioning pairs naturally with the HTML popover attribute, which handles opening, light-dismiss and the top layer without JavaScript. The anchor is declared on the trigger, the popover tethers in 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>

That leaves the case where the anchor scrolls out of view: the tethered element no longer makes sense floating on its own. The position-visibility property hides it automatically as soon as its anchor leaves the screen.

.infobulle {
  position-visibility: anchors-visible;
}

Do not forget accessibility

Delegating placement to CSS does not remove the semantic work. A menu opened by the popover attribute gets focus handling and Escape-to-close from the browser, but the link between trigger and content must stay explicit for assistive technologies. The button keeps an aria-expanded reflecting the open state, and the popover describes its role when it is a navigation menu.

<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>

Positioning itself stays purely visual: it changes neither document order nor tab order. An element visually tethered above its anchor remains, in the accessibility tree, where it sits in the markup. That is an asset, provided the popover is placed at a coherent point in the source.

Anchor

position-area: bottom

Anchor

flip-block

Automatic fallback when there is no room below

Support status and fallback strategy

Anchor positioning reached Baseline in 2026, once it shipped by default in the three main engines. Basic placement works everywhere; only custom fallback positions arrived slightly later in Safari.

EngineVersionSupport
Chrome / Edge125 (2024)Full, including fallbacks
Safari18.2 (core) · 18.4 (@position-try)Placement from 18.2, fallbacks from 18.4
FirefoxEnabled by default in early 2026Full

Watch out. Custom fallback positions defined with @position-try only arrived with Safari 18.4. A component that depends on a complex fallback must plan a clean degradation on earlier versions, rather than letting a menu overflow the screen.

For audiences still on older versions, progressive enhancement is enough: a static default placement, enriched conditionally with @supports.

.infobulle { top: 100%; left: 0; } /* repli statique */

@supports (position-anchor: --x) {
  .infobulle { position-area: bottom center; }
}

The takeaway

CSS anchor positioning replaces, for most menus, tooltips and popovers, a JavaScript dependency long considered unavoidable. Three properties cover the essentials: anchor-name to designate the anchor, position-area to place, position-try-fallbacks to stay on screen. Paired with the popover attribute, it lets you build complete interface components without a script, with a clean fallback for older browsers.

I dropped Floating UI from two projects this year, and the clearest win is not the bundle size: it is the disappearance of a whole class of positioning bugs on scroll. I do keep one reservation — as soon as a component needs truly dynamic, data-driven placement, the JavaScript logic comes back, and that is fine. Native covers the common cases, not every case. — Simon Janvier

Further reading: the full reference is documented on MDN — CSS anchor positioning.

Also on Mail Studio

” class=”lazy-load-youtube preview-lazyload preview-youtube” data-video-title=”A couple of great anchor positioning use cases” title=”Play video “A couple of great anchor positioning use cases””>https://www.youtube.com/watch?v=lXS2P3xtAUY

Read next