CSS Anchor Positioning: Chaining Multiple Fallback Positions
AI generated
{ }
@
CSS · Anchor Positioning · Layout · Popover
Chaining Multiple Fallback Positions
So tooltips and popovers automatically switch sides near the screen edge

A single fallback position rarely covers every case in CSS Anchor Positioning once an anchor sits close to a screen edge. With position-try-fallbacks you can define a whole chain of alternative positions the browser tries in order until one fits, with no JavaScript and no resize or scroll listener at all.

16 min read position-try-fallbacks · position-try-order Chromium · Progressive Enhancement

1. Anchor Positioning in brief: anchor-name, anchor() and position-anchor

CSS Anchor Positioning ties a positioned element to any other element in the document, called the anchor. The anchor gets an anchor-name such as --trigger, the positioned element references it through position-anchor, and can then be placed relative to the anchor with inset-area or the newer position-area property, for example above, below, or to the side of it.

The key difference from classic absolute positioning is that the browser re-evaluates the relationship between anchor and positioned element on every layout pass. Libraries like Floating UI previously had to call getBoundingClientRect() and listen for scroll and resize events. With native Anchor Positioning the rendering engine handles that calculation right inside the layout step, avoiding jank from delayed JavaScript recalculation.

2. Why a single fallback position rarely covers every case

A tooltip that appears below its anchor by default works fine as long as the anchor sits in the upper half of the screen. But when the same button sits near the bottom of the viewport, the tooltip spills past the visible area or gets clipped by the browser. A single fixed position only covers part of the possible anchor positions within the viewport.

This was traditionally solved with JavaScript that measures available space in all four directions and switches the position dynamically. That works, but adds code, extra event listeners, and one more failure point to every project. CSS Anchor Positioning solves exactly this problem declaratively: instead of hardcoding one position, you describe an ordered list of alternatives, and the browser picks the first one that fits on its own.

3. Understanding position-try-fallbacks as an ordered list

The position-try-fallbacks property accepts a comma-separated list of alternatives. Each entry can be a built-in shorthand like flip-block, flip-inline, or flip-start, a ready-made position-area value like bottom span-right, or the name of a custom @position-try rule. The browser walks the list left to right and uses the first alternative for which the element fits entirely within the relevant containing block.

The position-try shorthand combines position-try-order and position-try-fallbacks into a single line, similar to how font bundles several typography properties. For most projects the longhand with position-try-fallbacks is preferable, because combined with the base position set on the element itself through position-area, it stays clear which position is the preferred one and which are merely fallbacks.

4. How the rendering engine evaluates the order

Evaluation strictly follows the written order: the base position from position-area counts as the first attempt, followed by the entries in position-try-fallbacks in exactly the order they are listed. As soon as a position fits over the containing block without overflow, the search stops there. In practice this means the desired default position belongs at the start, and robust but visually less elegant fallback positions belong at the end of the chain.

If none of the alternatives fits perfectly in the end, the position-try-order property, with values like most-width or most-height, decides which of the checked positions offers the most available space, and picks that as a final, pragmatic compromise. This two-stage logic, first searching for a perfectly fitting position and only then falling back to the roomiest alternative, prevents a tooltip from becoming completely invisible in a very tight viewport.

5. A tooltip with four chained fallback positions

In practice, three to four alternatives are usually enough to cleanly cover all four screen edges. The following example shows a tooltip that appears above its anchor by default, switches below when there is not enough room, then falls back to the right, and as a last resort moves to the left, each with a small safety gap set through anchor-size().

It matters that every alternative in the chain uses the same position-anchor, but references a different position-area or a named @position-try rule with its own spacing. That keeps the relationship to the anchor consistent across all four possible positions, while only the spatial orientation varies.


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

@position-try --tooltip-right {
  position-area: right;
  margin-inline-start: 0.5rem;
}

@position-try --tooltip-left {
  position-area: left;
  margin-inline-end: 0.5rem;
}

.tooltip {
  position: absolute;
  position-anchor: --info-trigger;
  position-area: top;              /* 1st attempt: above the anchor */
  margin-block-end: 0.5rem;

  position-try-fallbacks:
    flip-block,                    /* 2nd attempt: flipped below */
    --tooltip-right,                /* 3rd attempt: to the right of the anchor */
    --tooltip-left;                 /* 4th attempt: to the left of the anchor */
  position-try-order: most-height;  /* final compromise if nothing else fits */
}

6. Dynamic behavior on scroll, without a single event listener

The major practical benefit of a chained fallback list shows up while scrolling: as the anchor moves closer to the screen edge, the browser automatically switches to the next matching position in the chain as needed, without a scroll or resize listener ever firing. Re-evaluation happens within the same layout step that runs on every scroll frame anyway, making it noticeably smoother than a JavaScript solution that only reacts asynchronously to an event.

On top of that, position-visibility: no-overflow lets you specify that the positioned element gets hidden entirely once even the roomiest fallback position is no longer sufficient, instead of showing it clipped. For tooltips this is often the better outcome than a visible but half-obscured element, because a missing tooltip confuses users less than one that looks broken.

7. Chained fallbacks together with the Popover API

Anchor Positioning shows its full strength combined with the native Popover API. An element with the popover attribute gets promoted to the browser's top layer when opened, which sidesteps stacking issues with z-index and overflow: hidden on ancestor containers from the start. The fallback chain from position-try-fallbacks works identically in this context, because it operates independently of which layer the element ultimately renders in.

For an options menu bound to a button through popovertarget, that means the same fallback chain used for a plain tooltip carries over one to one, except that popover and popovertarget additionally handle opening, closing, and automatic focus management. Spatial positioning and visibility management stay two cleanly separated concerns.

8. Browser support and a fallback strategy without Anchor Positioning

CSS Anchor Positioning is still a young specification and currently fully implemented mainly in Chromium-based browsers, while Firefox and Safari are still working on their own implementations as of this writing. Anyone using the technique in production today should consistently apply progressive enhancement rather than relying on universal support.

The feature query @supports(anchor-name: --x) checks whether the browser understands Anchor Positioning and delivers the native solution inside that block. Outside of it, a simple, static fallback position using classic position: absolute with fixed inset values takes over, which does not adapt perfectly to every screen size but still shows a working, if less elegant, tooltip.


/* Static baseline for every browser */
.tooltip {
  position: absolute;
  top: 100%;
  left: 0;
  margin-block-start: 0.5rem;
}

/* Enhanced version only where Anchor Positioning is understood */
@supports (anchor-name: --x) {
  .trigger {
    anchor-name: --info-trigger;
  }

  .tooltip {
    position-anchor: --info-trigger;
    position-area: top;
    position-try-fallbacks: flip-block, flip-inline;
  }
}

9. Practical tips for robust, maintainable fallback chains

Three to four fallback positions cover nearly every use case in practice; each additional alternative makes the chain harder to follow without a noticeable benefit. The order should match natural reading flow and user expectations, usually above before below and right before left in left-to-right languages, so the preferred position also looks the most plausible visually.

The fallback chain only changes the visual position, never the order in the DOM, so screen readers and keyboard navigation stay unaffected. It still matters to test every new combination against all four screen edges and narrow mobile viewports, because ordering mistakes usually only surface where several fallbacks fail to fit at the same time.

Fallback type Effect Typical use
flip-block Mirrors position on the block axis (top/bottom) Tooltip flips from below to above near the bottom edge
flip-inline Mirrors position on the inline axis (left/right) Dropdown flips from right to left near the right edge
flip-start Mirrors both axes at once Corner cases where neither top/bottom nor left/right fits
Named @position-try rule Custom combination of position-area, margin and inset Reusable, project-specific fallback position
position-try-order: most-height Picks the roomiest of several matching options Final compromise when no fallback position fits perfectly

Mironsoft

Modern CSS, layout architecture and rendering performance

CSS that stays maintainable instead of breaking with every change?

We review existing stylesheets for specificity chaos and layout thrashing, then build a CSS architecture with cascade layers, custom properties and modern layout primitives that still makes sense after the tenth feature.

CSS Audit

Systematically uncovering specificity issues, cascade conflicts and unused selectors.

Architecture Refactoring

Introducing cascade layers, custom properties and design tokens cleanly.

Performance Tuning

Fixing layout thrashing, expensive selectors and rendering bottlenecks.

10. Summary

Chained Fallback Positions: The Essentials at a Glance

Core idea

position-try-fallbacks walks an ordered, comma-separated list of alternative positions until one fits without overflow.

Order matters

The browser evaluates left to right, so the preferred position belongs at the start of the chain and robust last resorts at the end.

No JavaScript needed

Re-evaluation happens in the native layout step, without scroll or resize listeners and without an asynchronous follow-up.

Progressive enhancement

@supports(anchor-name: --x) delivers Anchor Positioning only where the browser already understands it, with a static fallback in front.

11. FAQ: Chained Fallback Positions: The Essentials at a Glance

1What is the difference between position-try-fallbacks and position-try-order?
position-try-fallbacks defines the ordered list of fallback positions itself. position-try-order only decides which of those options gets chosen as a last resort when none fits perfectly without overflow.
2How many fallback positions should a chain have?
Three to four is almost always enough in practice to cover all four screen edges. More entries make the chain harder to follow without a noticeable extra benefit.
3Do I need a custom @position-try rule for every fallback position?
No. For simple cases the built-in shorthands flip-block, flip-inline, and flip-start are enough. Custom @position-try rules become worthwhile once a fallback position needs extra values like its own margins.
4What happens if none of the fallback positions fits?
Then position-try-order kicks in and picks whichever checked option offers the most available space. With position-visibility: no-overflow you can instead hide the element entirely rather than showing it clipped.
5Does the fallback chain react to scrolling without any custom code?
Yes. Re-evaluation runs inside the rendering engine's native layout step and updates automatically on every scroll or resize frame, with no custom event listeners at all.
6Can I combine Anchor Positioning with the Popover API?
Yes, and that is a very common use case. An element with the popover attribute uses the same fallback chain as a plain tooltip, while the Popover API additionally handles top-layer rendering and focus management.
7Which browsers already support position-try-fallbacks?
Currently mainly Chromium-based browsers support it fully. Firefox and Safari are working on their own implementations, so production use today needs an @supports check with a static fallback.
8Does the fallback chain change the order in the DOM?
No. Only the visual position changes, the DOM order and therefore the order for screen readers and keyboard navigation stays unchanged.
9How do I reliably test a fallback chain?
Best practice is manually moving the anchor to all four screen edges and additionally testing a narrow mobile viewport. Ordering mistakes usually only surface where several fallbacks fail to fit at the same time.
10Is Anchor Positioning worth it over Floating UI or Popper.js?
For new projects that mainly reach Chromium users or that accept progressive enhancement, the native solution saves an entire JavaScript bundle and avoids jank from asynchronous recalculation.