Browser support
It needs anchor positioning and typed attr(). The last column is your browser, tested as this page loaded.
What it needs
| Feature | Used by | Chromium | Here |
|---|---|---|---|
| Typed attr() | Every attribute that takes a --name. Without it no anchor name resolves. | 133+ | … |
| Anchor positioning | Everything: anchor(), position-anchor, anchor-size(). | 125+ | … |
| position-area | data-⚓️-area | 129+ | … |
| anchor-center | data-⚓️-align-x, -align-y, -center-all | 125+ | … |
| position-try-fallbacks | data-⚓️-try | 128+ | … |
| position-try-order | data-⚓️-try-order | 125+ | … |
| anchor-scope | data-⚓️-scope, -scope-name | 131+ | … |
| position-visibility: anchor-visible | data-⚓️-visibility="visible" (plural spelling; singular from 157) | 125+ | … |
| position-visibility: anchor-valid | data-⚓️-visibility values that include valid | 157+ | … |
| Anchored container queries | Every data-⚓️-to target; lets insides query the chosen fallback | 143+ | … |
| @starting-style | data-⚓️-morph-from | 117+ | … |
| interpolate-size | Morphs to and from auto sizes | 129+ | … |
| popover="hint" | Optional; this site's tooltips | 133+ | … |
Other engines
Typed attr() is the one to watch: it's how a name gets from your markup into CSS, and without it the attributes are inert. Test for it, not for anchoring.
- Chrome and Edge 133+: supported. The library and this site are built and verified in Chromium.
- Safari: not in a stable release yet.
- Firefox: unverified.
Early signal only: in our audit, Playwright's Firefox 155 and WebKit 26.6 builds pass both required probes and lay this site out with the library. Neither had anchored container queries orinterpolate-size, so fallback-aware styles and morphs to auto sizes don't apply there, and WebKit took a flip-y fallback the popover didn't need. The Here column above tests the browser you're in.
Fallbacks
This site's own, which puts the page back into normal flow:
@supports not (anchor-name: attr(data-x type(<custom-ident>))) {
/* anchored regions go back into the flow, in source order */
.shell-region { position: static; }
.shell-nav { display: none; } /* the Menu button takes over */
/* popovers: the library's reset cleared the UA centring; restore it */
[popover][data-⚓️-to] { inset: 0; margin: auto; width: fit-content; height: fit-content; }
}Known limitations
From SPEC.md, verified in Chromium.
- Resolved — the "end-only inset" problem was the UA popover stylesheet, not a browser bug.
[popover]/<dialog>getinset: 0andfit-contentsizing from the UA sheet, which over-constrains any box that sets only one inset (aninset-block-end: anchor(...)alone rendered at the wrong place). The top-layer reset (section 1) clearsinset/width/height/margins inside:where(), so it has zero specificity and never beats an anchor()-driven longhand or an author class.above,before,align-bottomandalign-trailingare therefore plain logicalinset-block-end/inset-inline-endon every target type (an earliertranslateworkaround,--⚓️-tx/--⚓️-ty, was removed). Consequences: RTL and vertical writing modes work, nativeflip-block/flip-inlinework on popovers in both directions (customposition-areaflip blocks removed), anddata-⚓️-stretch-[x|y]sizes popovers correctly. Trade-off: switching between a start attribute and an end one (below<->above) changes which inset is used and inset cannot interpolate fromauto, so that swap snaps instead of tweening; same-attribute changes and size still morph. anchor-valid(data-⚓️-visibility="valid") needs Chrome 157+. The CSSWG renamedanchors-visible/anchors-validto singularanchor-visible/anchor-valid(blink-dev intents, Chrome 157, plurals kept as deprecated aliases). The old pluralanchors-validwas never shippable (reverted over spec ambiguity), so in Chromium 153CSS.supports("position-visibility", "anchors-valid")and the singular forms all returnfalse, while pluralanchors-visible,no-overflowandalwayswork. The library declares plural then singular for every value (an engine drops the declaration it doesn't parse), sovisibleworks everywhere and gains the singular spelling for free; any value includingvalid(valid,valid-no-overflow,all) silently falls back to the initial value until the engine supportsanchor-valid.tests/10-visibility-state.htmlprobes support withCSS.supportsand only treatsvalidvalues as a known gap when neither spelling parses.data-⚓️-trymeasures overflow against the target's containing block and the scrollable area. Confirmed while testing: an extraposition: absolutewrapper between a popover's anchor and the viewport, or a tall (scrollable) document, changes what counts as overflowing, so a box hanging off the bottom of the viewport can simply not flip. Anchors placed directly on a non-scrolling viewport (position: fixed) behave as expected (tests 09 and 16).position-try-fallbacksdoes not re-evaluate on scroll — confirmed live, current Chromium (153.0.8010.12). An anchor-positioned element (plain or[popover], root-document scroll or anoverflow: autoscroll container,data-⚓️-tryon any axis) picks its fallback exactly once — apparently checking overflow against the anchor's position as ofscrollY: 0/initial layout, never the actual current scroll-adjusted viewport position. Verified 5 independent ways: scrolling an already-open popover into an overflowing position (no re-flip, holds for 4.5s+ across 15 polled frames); resizing the viewport instead of scrolling (same); closing and reopening a popover while already scrolled to an overflowing position (still no flip — rules out a stale/cached fallback choice, since this is a freshshowPopover()call); and inserting a brand-new DOM node (never laid out before) at an already-scrolled, already-overflowing position (still no flip — rules out any per-element caching entirely). A page scrolled viawindow.scrollTo()before the browser's first paint pass still doesn't get correct fallback selection either, which is what pins this down precisely: the algorithm isn't stale-caching a past result, it's not factoring scroll position into its overflow check at all, ever. This directly contradicts MDN's own description of the feature ("re-evaluates continuously as the user scrolls") — worth re-testing against a future Chromium release rather than assuming MDN is simply wrong. Practical impact: any UI built on the assumption that scrolling an anchor toward a viewport edge live-triggers itsdata-⚓️-tryfallback (e.g. a tooltip that's expected to flip sides as its anchor scrolls near the top/bottom of the screen) will not work today — the fallback is only correctly chosen at the moment the element is first laid out (its very first style/layout pass,scrollYbaked in at that instant), not on later scroll events. No workaround identified; this sits below the CSS layer entirely.- Animating a fill across a reflow:
data-⚓️-fillhandles it,stretch-x+stretch-ydon't. Confirmed live building the animated-grid-reflow demo (Bramus's technique of anchoring absolutely-positioned content to a grid cell so it can animate independently of the grid's own instant reflow): a box sized purely by 4 inset longhands (stretch-x+stretch-y), or by theinset: anchor(inside)shorthand with no explicit size, visibly collapses to ~0px wide partway through atransition: insetwhen its anchor moves, even though old and new size are identical.data-⚓️-filltherefore sets both the singleinset: anchor(inside)shorthand and an explicitwidth/heightfromanchor-size(), which makes the size authoritative so only the position animates (verified sampling every frame: no collapse, in real Chrome). Chrome still reports four separateinset-*transitions for the shorthand, so why the shorthand plus explicit size works isn't established. Authorwidth/heightoverride the built-in ones.