Anchor Positioning: anchor-name Tethering Without JS Math
- Last updated
- Prerequisites:
- CSS positioning (absolute/fixed)
- Understanding of inset properties and overflow
- css
- anchor-positioning
- anchor-name
- position-anchor
- popover
- tooltip
Read at your depth
The practical view
Anchor positioning lets you attach an element to another element (the anchor) without JavaScript. Mark the anchor: .btn { anchor-name: --tip; } then position the popover: .popover { position: absolute; position-anchor: --tip; left: anchor(right); bottom: anchor(top); }. inset-area: top right; is a shorthand that places the element in a named region around the anchor. Anchor functions (anchor(edge), anchor(--name edge)) resolve to the anchor's edges. This replaces manual getBoundingClientRect + coordinates math for tooltips, menus, and callouts.
The same idea in other frameworks
React tooltip/menu components can drop floating-ui geometry math for CSS anchor positioning where browser support allows.Angular overlay positioning can delegate to CSS anchors for simple anchored popovers, reserving CDK for complex cases.Vue floating-element libraries are increasingly CSS-anchor-aware; simple anchors need zero JS.Svelte actions can set anchor-name and let the browser position popovers declaratively.Legacy vs modern
getBoundingClientRect math vs anchor positioning
JS geometry must be recomputed on scroll/resize; CSS anchor positioning keeps the popover tethered automatically via the layout engine.
const r = btn.getBoundingClientRect();
pop.style.left = r.right + 'px'; pop.style.top = r.top + 'px'; // ❌ OLD.btn { anchor-name: --tip; }
.popover { position: absolute; position-anchor: --tip; inset-area: right; } /* ✅ NEW */Interview gotchas
Context
This tests whether you understand that anchor positioning is resolved by the layout engine, not computed once — the key architectural difference from manual geometry math.
The mechanical answer
The anchored element's position is recomputed as part of the layout/rendering pipeline: the engine resolves the anchor() inset values against the registered anchor's current border box at each render update. When the page scrolls or the anchor moves (including under transforms), the anchor's box position is updated and the anchored element's insets re-resolve in the same frame — no scroll/resize listeners are involved. This is why it stays perfectly attached with zero jank risk from JS sampling. With position-try-options, the engine also re-evaluates fallback placements during the same resolution, picking the first candidate that fits the scrollport.
Trap
The naive answer is 'it computes the position once at load'. It is re-resolved continuously by the layout engine as the anchor moves. Another trap: thinking it is equivalent to position: absolute relative to a wrapper — the anchor can be anywhere in the document, including in another stacking context, and the positioned element can live in the top layer. Candidates who mention the re-resolution pipeline and the anchor registry show real understanding.
Context
This probes the overflow-avoidance mechanism — the 'try these placements in order' algorithm that is the real value of anchor positioning beyond simple tethering.
The mechanical answer
position-try-options lists alternative placements (either inset-area values or named @position-try blocks). When the preferred placement would overflow the scrollport (or violate inset-modified containing block constraints), the engine re-solves the layout with the next candidate and picks the first one that fully fits. This mirrors the flip/fallback logic that floating-ui and popper.js implemented by measuring the popover's size and viewport at runtime, recomputing on every change. The CSS version runs inside the layout algorithm, so the flip is instantaneous and frame-consistent, and it also composes with scroll-driven changes. You can combine it with inset-area to express 'prefer right, else left, else below' declaratively.
Trap
The naive answer is 'it just flips when it detects overflow'. It is an ordered candidate search executed during layout resolution, not an event-driven correction — there is no flash of the wrong position and no measurement jank. Another trap: thinking position-try-options works without an anchor or inset-area setup — the candidates are resolved against the same anchor reference. Candidates who describe the try-algorithm ordering and its layout-phase execution show real depth.