
Here's Why Your Anchor Positioning Isn't Working
Here's Why Your Anchor Positioning Isn't Working êŽë š
Info
Check out our Winging It conversations about design, frontend, and backend development.
Winging It episode 8: CSS Anchor Positioning in Practice
Winging It episode 16: Debugging CSS Anchor Positioning
The problem
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.
TL;DR
For the best chance of having anchor positioning work, hereâs my recommendation:
- Make the anchor and the positioned element siblings.
- 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.
Troubleshooting checklist
Hereâs how to check for some of the common reasons why an anchor isnât found:
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.
Note
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.
Note
This may be changing â in our Winging It episode with Tab Atkins-Bittner, Tab identified that this restriction may not be necessary. I opened a CSS Working Group issue (w3c/csswg-drafts) proposing a change to the spec to allow this.
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.
Note
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.)
Info
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.
There are many things that can cause the anchor element to create a containing block, and positioned elements that are children will not work:
- If you set a
positionbesidesstaticon the anchor and the positioned element isposition: absolute - If you transform the anchor element somehow, with
transform,translate,scale, etc. - If the anchor element is a query container for container size queries
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.
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.
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.
Note
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.
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.
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.
Containing blocks
CSS Display Module Level 4 spec (drafts.csswg.org)
Notably, a containing block is not a box (it is a rectangle)âŠ
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.
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.
Ways to make this easier
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?
Interested in learning more about anchor positioning? Sign up for our free weekly CSS anchor positioning email course.
Sponsor us
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.