Skip to main
Article
A weathered small boat in the fog, with ropes going into the water, hopefully leading to an anchor.

Here’s Why Your Anchor Positioning Isn’t Working

How to find an anchor element

It is frustrating to track down why an anchor isn’t being found. I’ve found a simple way that should work in most cases. If that doesn’t work, step through the checklist, and then dive in to get a better understanding of how Anchor Positioning works.

TL;DR – For the best chance of having anchor positioning work, here’s my recommendation:

  1. Make the anchor and the positioned element siblings.
  2. Put the anchor first in the DOM.

Go give that a try, and then come back and find out what to check next if that didn’t work.

I’ll wait.

Anchor positioning has a ton of possibilities, and is fun to play around with. But sometimes things start to break. The positioned element can’t find the anchor, it isn’t positioned correctly, and Dev Tools just says --anchor is not defined.

Then you need to figure out why… Is it related to how you’ve structured your markup, a browser bug or partial implementation, or maybe it’s how you’re using Shadow DOM?

There are many reasons why it can fail, but they all fail in the same way. This makes it really hard to troubleshoot and recover from.

Here’s how to check for some of the common reasons why an anchor isn’t found:

  1. Check that your anchor is not a parent of the positioned element. If it is, make sure the anchor is not generating a containing block for the anchor.
  2. Check that the anchor is an element or valid pseudo-element.
  3. Check that both the anchor and positioned elements are in the same anchor-scope subtree.
  4. If your anchor is absolutely positioned, make sure it comes before the positioned element in the DOM.
  5. Check that your anchor is not in a higher top layer (generated by a popover or modal dialog) than the positioned element.
  6. Check that the anchor-name is defined by styles in the same shadow or document tree where it is referred to.

If your issue isn’t on this list, let us know how you fixed it! This list isn’t exhaustive, and omits some cases with hidden content, fixed position anchors, and other less likely edge cases.

We’re also available for office hours to help work through your specific case.

The examples in this article are best viewed in a Chromium browser, version 131 or later. In the examples that show that an anchor is not found, be aware of a bug in Chromium that causes elements with a position-area rule that do not have a valid anchor to be positioned incorrectly. 🤷🏼‍♂️

Anchor as a parent to the positioned element

While a positioned element can be a child of the anchor, this is the primary place where I’ve seen anchor positioning fail.

The spec has specific requirements regarding the relationship between the containing blocks of the anchor and the positioned element – and containing blocks are essentially invisible, except in their effects, to developers. This leads to unexpected and surprising behavior.

While containing blocks deserve an entire deep dive post, in the meantime there’s a brief note at the end of this article.

The containing block for the positioned element cannot be a descendant of the containing block for the anchor. Put a different way, the space in which the positioned element can be positioned cannot be smaller than the space in which the anchor can be positioned. (Note: this is technically less accurate, but it helps me visualize the rule.)

Add this to your mental model:

The space in which the positioned element can be positioned cannot be smaller than the space in which the anchor can be positioned.

Crucially, if the anchor element is a parent to the positioned element and creates a containing box for the positioned element, anchor positioning will not work. The positioned element’s containing box will be the anchor, and the anchor’s containing box will be one of its ancestors.

See the Pen Absolute anchor order by @jamessw on CodePen.

There are many things that can cause the anchor element to create a containing block, and positioned elements that are children will not work:

This is not an exhaustive list. Because there are so many ways to get into this situation unexpectedly, I recommend not nesting positioned elements inside the anchor.

Valid anchor pseudo-elements

Most anchors will be elements, but if you’re using a pseudo-element, not all qualify. The pseudo-element must be a “fully styleable tree-abiding pseudo-element.” Tree-abiding pseudo-elements behave like regular elements, unlike pseudo-elements like ::first-letter or ::spelling-error. Some, like ::marker or ::placeholder, are not fully styleable, as they only allow some CSS properties.

The valid pseudo-elements are ::before, ::after and ::file-selector-button. ::-webkit-slider-thumb currently works as an anchor in Chrome, but as it is experimental and not part of any CSS spec, it’s unclear whether it should.

See the Pen Valid anchor pseudo-elements by @jamessw on CodePen.

Anchor scope

Anchor scope is great for making reusable anchoring rules, especially if you are anchoring on a list item or reusing styles. If you’re using anchor-scope, verify that both the anchor and positioned element are descendants of the element with the anchor-scope rule, or if the anchor itself has the anchor-scope rule, that the positioned element is a descendant of the anchor.

See the Pen Anchor Scope by @jamessw on CodePen.

Absolute anchor order

This is the motivation behind the recommended solution to have the anchor come before the positioned element in the DOM.

Generally, absolutely positioned elements are rendered after relatively positioned elements. If the anchor element is absolutely positioned, then the positioned element must come after the anchor in the DOM.

See the Pen Absolute anchor order by @jamessw on CodePen.

The “after the anchor in the DOM” check happens on the flat tree, which means that it happens after slotted content is placed and shadow hosts are filled with their children.

Top layer

If you are using dialogs as modals or popovers, you are creating top layers. If the anchor element is in a higher top layer than the positioned element, the positioned element will not be able to locate the anchor.

You can position the root popover or dialog directly using position: absolute.

See the Pen Top Layer by @jamessw on CodePen.

However, if you want to position an element that is inside the popover or dialog, you will need to use position: fixed. Note that the positioned elements are not inside their parents in this example – position: fixed moves the element’s containing block to the viewport and allows positioning to work.

See the Pen Top Layer - inside by @jamessw on CodePen.

Anchoring across shadow trees

An element in one tree can anchor to an element in another tree, as long as the relevant styles are all defined in the same style tree. In other words, if anchor-name is defined in a shadow tree, the position-anchor or anchor() styles must also be defined in that shadow tree. If the anchor-name is defined outside a shadow tree using ::part(), then the position-anchor or anchor() styles can be defined outside as well.

See the Pen Anchor on Shadow Part by @jamessw on CodePen.

Notably, a containing block is not a box (it is a rectangle)…

CSS Display Module Level 4 spec

Great, I totally understand…

You likely have run into containing blocks before. When you are positioning something with absolute positioning, it is positioned relative to its containing block.

See the Pen Containing box for absolutely positioned element by @jamessw on CodePen.

If you use percentages to define widths and heights, these are calculated relative to the element’s containing block.

To figure out an element’s containing block, find the ancestor element that the element’s position and size are relative to. This is dependent on the element’s position value, so for example, if the element is fixed position, the containing block can be the viewport, or if the element is relative position, the containing block could be generated by an ancestor <li> element.

I’ve found MDN’s guide on Identifying the containing block a helpful resource to unravel the containing block.

Troubleshooting why an anchor is not found is not fun or easy. Anchor Positioning is in its early days, but as adoption grows, I hope we can find ways to make this easier.

An important part will be to improve dev tooling when an anchor is not found. Perhaps next to a --anchor is not found message, there could be a crosshair selector to select the DOM element you thought would be the anchor. Then the Dev Tools could provide a specific message of why that particular combination would not work.

Another useful improvement would be a method to identify an element’s containing block. Perhaps there could be a new :containing-block pseudo-class that selects the element that creates the containing block, or a HTMLElement.containingBlock attribute. Because this is primarily useful while developing, it may be better to instead add a way of finding this in Dev Tools, instead of through browser APIs.

I think we also need to find better mental models to understand render order and containing blocks. Is there a way we could move this from a set of guidelines and a checklist of gotchas to avoid, to a place where these rules click and make sense to developers?

If you found this article helpful, please sponsor our work! Deep dives like this take time and energy, and we want to keep them coming!

You can also hire us to develop the Anchor Positioning polyfill or another OSS language/tool you rely on. Our client work also helps fund our educational work like this article, so get in touch with us if you have any web development needs.

Open Source Sponsors

Current Sponsors

A huge thank you to the individuals and organizations sponsoring OddBird’s open source work!

Blue-Footed Boobies

Open Collective Avatar for benface

Common Loons

Open Collective Avatar for ScheppOpen Collective Avatar for ThijsOpen Collective Avatar for AnonymousOpen Collective Avatar for Outline GbROpen Collective Avatar for Paul van BuurenOpen Collective Avatar for Mat MarquisOpen Collective Avatar for William KillerudOpen Collective Avatar for Nikita DubkoOpen Collective Avatar for Nicolas ChevobbeOpen Collective Avatar for JohannesOpen Collective Avatar for Eric PortisOpen Collective Avatar for Roman KomarovOpen Collective Avatar for Pascal DuezOpen Collective Avatar for Tyson GachOpen Collective Avatar for MayankOpen Collective Avatar for thanks.devOpen Collective Avatar for Syntax

Sponsor OddBird’s OSS Work

We love contributing back to the languages & tools that developers rely on, from CSS & Sass to browser polyfills and Python. Help us keep that work sustainable and focused on developer needs!

Recent Articles

  1. A symmetrical knot with thick rope lying on weathered wood.
    Article post type

    Anchor Positioning Is Disruptive

    New layouts will be possible

    The more I play with it, the more convinced I am that anchor positioning is going to unlock some surprising new layouts.

    see all Article posts
  2. A pay-to-use pair of binoculars at a scenic overlook.
    Article post type

    Updates to the Most Desired CSS Feature You Can’t Use Yet

    Performance, scope, and fallbacks for the anchor positioning polyfill

    Our sponsors are supporting the continued development of the CSS Anchor Positioning Polyfill. Here’s a summary of the latest updates.

    see all Article posts
  3. A green on dark-gray horizontal bar chart, with the labels cut off
    Article post type

    What do survey demographics tell us?

    Are we measuring what we meant to measure?

    There’s been a lot of interest in the results of the annual State of CSS survey, but are we asking all the right questions?

    see all Article posts