html
html copied to clipboard
Add anchor attribute
The anchor attribute can be used to set up CSS anchor positioning by setting an implicit anchor element: https://drafts.csswg.org/css-anchor-1/#implicit-anchor-element.
The CSS properties used to set up anchor positioning relationships are perfect for repeating patterns, such as:
<div class=anchor></div>
<div class=positioned></div>
<div class=anchor></div>
<div class=positioned></div>
<div class=anchor></div>
<div class=positioned></div>
<style>
.anchor { anchor-name: --foo; }
.positioned { position-anchor: --foo; }
</style>
However, for structural patterns, such as when using a Popover, an HTML attribute has less boilerplate and makes the relationship much more directly observable:
<button id=button1>Pick something #1</button>
<div popover anchor=button1>Popover for button1</div>
This structural pattern can apply to other use cases also, where unique elements are paired.
When used with the Popover API, the anchor attribute also naturally helps to create a relationship that ensures popovers are properly nested:
<button id=button>Menu 1</button>
<menu popover anchor=button>
<li id=item1>Item 1</li>
<li id=item2>Item 2</li>
</menu>
<menu popover=hint anchor=item1>
Helpful tooltip about item 1
</menu>
<menu popover=hint anchor=item2>
Helpful tooltip about item 2
</menu>
This PR adds the anchor attribute to HTML and connects it to the Popover API.
- [ ] At least two implementers are interested (and none opposed):
- [x] Tests are written and can be reviewed and commented upon at:
- https://wpt.fyi/results/html/dom/elements/global-attributes?label=master&label=experimental&aligned&q=the-anchor-attribute
- [ ] Implementation bugs are filed:
- Chromium: Already implemented
- Gecko: …
- WebKit: …
- [ ] MDN issue is filed: …
/dom.html ( diff ) /index.html ( diff ) /indices.html ( diff ) /infrastructure.html ( diff ) /popover.html ( diff ) /references.html ( diff ) /rendering.html ( diff )
Before looking at this I'd like to see https://github.com/whatwg/html/labels/topic%3A%20popover shrink a whole lot first.
I've moved my previous comment to https://github.com/whatwg/html/issues/9311.
@annevk I'm not sure I understand why this work is blocking on popover. Although popover is one place anchor would be useful, of course, it's not the only scenario - and it seems like popover's needs are addressed here. What is the scope of your concern for what needs to be investigated before anchor work can proceed?
@josepharhar @tabatkins My initial thought looking at this is whether we can leverage presentation hints in some way instead of an "implicit anchor element", while still making it work conveniently for developers.
The idea behind this seems fine to me though.
@cwilso my concern is that popover landed in the standard with lots of issues that need to be addressed and it's been taking quite a long time for them to be addressed. That makes me uncomfortable about new features.
whether we can leverage presentation hints in some way instead of an "implicit anchor element", while still making it work conveniently for developers.
I'm not sure how that would be possible. Without an implicit anchor element, you need a named anchor element, which means that, assuming we could craft an appropriate selector (not certain that's true, haven't thought about it enough) we'd have to reserve a name just for this use-case. And an element can only have one anchor name, so it would conflict with authors using an anchor name on the element for other purposes. (Even if we change to allow multiple anchor names, which there's an open issue about, we'd still conflict since CSS has never gained a way to add to a list.) So I don't think it's possible to do this, no.
Skipping past the feasibility, tho, can I ask why you want to do this? If there's a particular reason you want to lean on presentational hints instead, I'd like to know in case it impacts other things architecturally.
We want to ship this soon in chrome along with CSS anchor positioning so they can be used together. I will continue to work on the remaining popover issues, but any feedback on this attribute in the meantime would be greatly appreciated so we have time to make changes if needed.
@nt1m do you have any thoughts in response to @tabatkins's comment?
I'm not a fan of having to implement magic in the engine for implicit anchors to work, I think I prefer having engines implement attr() and have authors rely on that:
<button data-anchor-name="--anchor">...</button>
<div class="menu" data-anchored-to="--anchor">...</div>
<style>
[data-anchor-name] {
anchor-name: attr(data-anchor-name);
}
[data-anchored-to] {
position-anchor: attr(data-anchored-to)
}
or something like that. Alternatively having some built-in UA styles (using attr()) that let the authors do this easily could also be fine, but having a special attribute in HTML feels unnecessary to me?
I'm not a fan of having to implement magic in the engine for implicit anchors to work, I think I prefer having engines implement
attr()and have authors rely on that:<button data-anchor-name="--anchor">...</button> <div class="menu" data-anchored-to="--anchor">...</div> <style> [data-anchor-name] { anchor-name: attr(data-anchor-name); } [data-anchored-to] { position-anchor: attr(data-anchored-to) }or something like that. Alternatively having some built-in UA styles (using
attr()) that let the authors do this easily could also be fine, but having a special attribute in HTML feels unnecessary to me?
So two points here:
- That's a ton of boilerplate that you're proposing to make authors implement, as compared to just saying
<div anchor=foo>. - This PR doesn't include it, but there's a followup which ties the
anchorattribute linkage into the popover stack algorithms. This is a very natural extension/use ofanchorto connect dependent popovers and make them "nested". E.g.
<div popover id=foo>Popover 1</div>
<div popover anchor=foo>Popover 2</div>
In this case, a) popover 2 is anchored to popover 1 very easily, and b) when popover 2 opens, it does not close popover 1 - they're related (obviously) via the anchor attribute.
This behavior will require adding even more hacks to the attr() code above.
Can you comment on what the downside of adding anchor to the platform is? The "implicit anchor element" concept was added to the CSS spec with exactly an anchor attribute in mind. See the note just below that concept. (Also note this to-do.)
This PR doesn't include it, but there's a followup which ties the anchor attribute linkage into the popover stack algorithms. This is a very natural extension/use of anchor to connect dependent popovers and make them "nested".
I guess this is a more compelling reason to add the anchor attribute, I originally thought the only motivation for this was to integrate with anchor positioning.
I guess this is a more compelling reason to add the anchor attribute, I originally thought the only motivation for this was to integrate with anchor positioning.
Ahh ok, thanks for the clarification. I think @josepharhar was thinking it'd be easier to review as a series of PRs, but I also don't think the changes needed to tie it into popover are too large. Perhaps it's worth us doing that now, in this PR, then?
@annevk Do you have any other thoughts on the feature?
Perhaps it's worth us doing that now, in this PR, then?
@nt1m @annevk would you prefer for me to add the popover integration to this PR? or do it afterwards?
I added the popover integration. I can remove it later if yall would prefer.
It'd be great to get a review of this PR. In the ~1 year since this PR was opened, an entire massive CSS feature for anchor positioning has been designed. It just needs this one little bit in HTML, please.
Agenda+ to discuss at WHATNOT.
@josepharhar before I take another look, can you resolve conflicts and ensure the build runs without errors? (Otherwise the preview might not be updated.)
I fixed the compile error and merged with tip of main. I'm not sure why the bot hasn't updated the commit message with the new build, based on the checks thing it looks like it worked
I pushed another commit to try to make it build again, and it did but it looks like there was an HTTP related error in the build server
With the last commit it looks like the build finally worked
Thanks for the discussion yesterday in WHATNOT about this PR. I heard several points made:
- It is confusing that
foo.anchorElementmight return an element that isn’t actually used (by CSS) as the anchor, in the case where the CSS specifies the anchor name directly. E.g.position-anchor: --another-nameortop: anchor(--another-name bottom). - There’s a potential concern about using DOM attributes as part of the layout algorithm. I don’t quite understand this one fully - if someone (@emilio?) can help me understand, I’d appreciate it!
- It might be confusing to developers that one attribute (
anchor) controls both anchor positioning and popover nesting.
Some solutions I heard:
- Rename
anchortoimplicitAnchororfallbackAnchororhostAnchor. Pro: this would make it more clear how the reference is actually used by the CSS anchor positioning spec. Con: it’s a little less clear that it would affirmatively be used for the popover linkage behavior. - Mint a unique anchor name, and have
anchorbe a presentation attribute that maps toposition-anchor: --new_magic_name. This would also have to (very magically) turn into a presentation (non-)attribute on the “target” element, mapping toanchor-name: --new_magic_name. Pro: this would not require reference to DOM attributes from layout. Cons: the fact that it affects the styles on the target element feels very new. Also, the magic name would be observable viamyElement.style.anchorName. - Use something like (or exactly) the CSS element() function, and have
anchorbe a presentation attribute that maps toposition-anchor: element(idref). Pro: this avoids the magic naming mentioned in the point above, and (likely?) avoids having a reflectedfoo.anchorElementat all. Con: it could still be overridden by author CSS that setsposition-anchorand might therefore still confuse authors. Also the same questions exist about how it’s exposed via CSSOM. - Don’t define an attribute at all, and let the developer work it out. E.g. use
data-*attributes and refer to them in CSS, e.g.anchor-name: attr(data-anchor-name);. Pro: no need for a spec change. Con: does not connect nested popovers, and forces the developer to do all of the work with a lot of boilerplate. - Slight modification of the above: assume IDs on a page are unique, and just create anchor names from idrefs directly:
button[id] {anchor-name: attr(id)}and then for the anchored element:menu[anchor] {position-anchor: attr(anchor)}. Pro: again, no need for a spec change. Con: does not connect nested popovers, and does not necessarily resolve the same way that idrefs do, e.g. when there are duplicates. - Define the anchor attribute (probably renamed) as only having the popover-nesting behavior. Treat the UA style rule that maps to CSS as a separate possibility that developers could add, or we could decide to add.
Thoughts and ideas appreciated!
Having an easy way for the popover to position itself relative to the activating element seems very useful, so removing implicit anchors would be very disappointing. We designed the concept of implicit anchors into the spec very early precisely so we could hook into this exact behavior, because it's useful.
Forcing authors to do things manually is also disappointing. It requires either (a) authors manually uniquify an anchor name for every single popover, and then specify it twice in style attributes or equivalent (once as anchor-name on the button, and again as position-anchor on the popover), or (b) authors explicitly nest the popover markup inside the button, so they can rely on anchor-scope to let them reuse a name on all the instances. Both kinda suck, when we (the UA) already know exactly what the connection is between the two. Hiding this from authors doesn't seem to be helpful to anyone.
All the other suggestions seem to invoke approximately the same amount of magic - the UA still exposes the implicit linkage between the button and the popover, it just plumbs it into the style system in slightly different ways. I prefer the method already designed into the Anchor Positioning spec, as it involves no new generic mechanisms that we'd have to work thru the implications of. It's tightly targeted at this use-case and doesn't cause any issues outside of Anchor Positioning.
Looking thru the notes, note the important aspect here that, because there's no DOM relationship between the button and popover except the invocation mechanism itself, you cannot rely on presentation attributes. You need to add styles on both elements that somehow reference each other (or that both reference some shared knowledge), and that is the fundamentally difficult part here that requires some sort of new magic.
Hearing no further suggestions after my comment above, other than one comment supporting the addition of an attribute, I'd like to Agenda+ this once more to discuss.
Of the listed options in my comment, my preference is still to add an explicit attribute like anchor which a) connects to the implicit anchor concept from CSS, and b) connects popovers to make them nested, if applicable. In working with the anchor positioning API, there are cases (e.g. web components) where an attribute provides a very natural solution to linking two elements. I think we should make cases like this flexible and easy to implement.
I'm very open to bikeshedding the attribute name to be more clear and avoid potential confusion around whether anchorElement is actually being used (and not overridden by CSS, for example). I propose implicitanchor/implicitAnchor as a more descriptive name that ties directly into the target anchor element CSS algorithm. But I'm open to other names. I'd just like to get agreement that we should add an attribute with the proposed behaviors.
I had a think on this and it dawned on me that this is currently the only way to do cross root anchoring (other than exposing a part and setting anchor name inside of that from the host). This kinda of cross root element reference is incredibly limited for reasons I'm not entirely sure of, but it does work. For that reason alone I think this is useful.
I had a think on this and it dawned on me that this is currently the only way to do cross root anchoring (other than exposing a part and setting anchor name inside of that from the host). This kinda of cross root element reference is incredibly limited for reasons I'm not entirely sure of, but it does work. For that reason alone I think this is useful.
That's right. To be a complete cross-root solution, reference targets needs to also land. But yeah that's another reason to want this attribute.
Discussing this with colleagues our main concern is that this attribute appears to be entirely presentational. We don't think we should be adding new presentational attributes to HTML.
There’s a potential concern about using DOM attributes as part of the layout algorithm. I don’t quite understand this one fully - if someone (@emilio?) can help me understand, I’d appreciate it!
It's kind of a layering violation. The platform has generally moved in the other direction (making html element names not meaningful for styling, via UA style sheet, and attributes syntax sugar for CSS, via attribute mapping).
My preference would be to at least make clear in the name that CSS overrides it... I'm also curious about @jwatt's and @fantasai's opinion on this.
Hah, I mid-aired with Anne of course :)
Just to summarize, here are the non-presentational rationales for this attribute:
- Semantically "nest" two popovers, such that they are anchor positioned to each other and one doesn't close the other.
- A solution to allow anchor positioning to cross shadow root boundaries.
Discussing this with colleagues our main concern is that this attribute appears to be entirely presentational.
What about the changes to the topmost popover ancestor algorithm? Those seem behavioral, not presentational.
At least this isn't a traditional presentational attribute, because it needs to affect the style of the anchor element in addition to itself.
It's kind of a layering violation. The platform has generally moved in the other direction (making html element names not meaningful for styling, via UA style sheet, and attributes syntax sugar for CSS, via attribute mapping).
Certainly there are idref relationships for other things like popovertarget and <label for> that establish relationships between two elements. Yes, this one also affects layout, but that's not all that it does.
My preference would be to at least make clear in the name that CSS overrides it...
I'm totally supportive of renaming it. I proposed implicitanchor to line up with the CSS concept, but I'm open to better suggestions. Perhaps another suggestion (@tabatkins @fantasai for comment) would be to make the implicit anchor element always "win"? So that it can't be overridden with CSS? Then you could just call it anchor and there would be no confusion. Also perhaps a relationship indicated in markup shouldn't be overridable by CSS? I don't know.
I'm also curious about @jwatt's and @fantasai's opinion on this.
Me too. The entire implicit anchor element concept was minted for this HTML attribute.
It seems we could accomplish the implicit anchor aspect of https://github.com/whatwg/html/pull/9144#issuecomment-2052650467 without a new attribute. By exposing the relationship between the activating element and the popover to CSS. I suspect we also have to expose that to AT and https://github.com/w3c/html-aam/pull/481 seems to back that up. (Which by the way is a problem we need to avoid going forward. We should not land new markup features without the a11y side being ready.)
Yes, this one also affects layout, but that's not all that it does.
Can you clarify what it does when we leave layout out of it?