Closed una closed 2 weeks ago
Thanks for putting this together @una! There's plenty of different ways we can go on the syntax, and I think we should explore a means for authors to say "I don't really care so much about fine-grained control of placement, I'll just give you my preferred position and you can move that around according to viewport constraints as you see fit".
I think there's a couple things we wouldn't be able to do with this particular syntax that seem important:
Authors who have specific preferences as to which fallback position is tried first (or fallback positions that they want to exclude) would also need some more support in the syntax. Again, interested to keep workshopping the syntax so we can support both 1) web developer who wants simple magic and 2) web developer who wants fine-tuned control.
I love the idea of providing some kind of control over how popups are anchored. So, thank you for the proposal, @una and @melanierichards and everybody behind the original proposal!
Though I have several notes here. First, two general ones:
optimize-visibility
. anchor-
.Disregarding those two points, there are obviously a lot more things considered in the original proposal. I think the essence of the proposal are two things, anchor one element to another and consider the viewport when positioning it.
Here are a few quick thoughts regarding that:
As anchoring is some kind of positioning, I agree with the proposal that this should be expressed as a new value for the position
property. But I think the value should rather be called anchored
, not anchor
, as it is referring to the anchored element.
Optimizing the positioning should happen by default, as I assume most authors will only care about the element being visible all the time. That means the default value for the related property should be optimize-visibility
(or just auto
, like it's used in many other properties, which should be defined to do the same).
The proposed positioning keywords are good. Though I'd go even a step further and allow to define the origin plus offset of the anchoring element as well as the anchored element. I.e. use the <position>
value as defined in CSS Values and Units 3 for both (plus logical keywords). The syntax definition might then look something like this:
<position> / <position>
Examples (with the first value being the one for the anchored element, the second one for the anchoring element):
anchor: top left / center;
Positions the top left corner of the anchored element at the center of the anchoring element.
anchor: inline-start block-start -20px / inline-start block-end;
Positions the inline-start block-end corner of the anchored element 20px away in block direction from the inline-start block-start corner of the anchoring element.
For left-to-right-top-to-bottom languages, that's how this would look like:
To cover the use case of the proposed @position-set
at-rule, the syntax could also be extended to take a comma-separated list of positions.
Talking about visibility, it might make sense to reuse (and maybe extend) the visibility
property. A value of visibility: visible;
for elements with position: anchored;
could indicate the UA to position the anchored element so that it's always fully visible (if possible).
To opt out from optimizing visibility, a new keyword could be introduced. I cannot think of a proper name for it right now, though.
Offsets within the viewport might be defined through the top
, right
, bottom
, and left
properties similar to how they affect position: sticky;
elements.
Let me know if anything is unclear. And it's possible that I missed something of the big picture here. So I'd appreciate any feedback on what I wrote.
Sebastian
Hi folks, great work! Everything seems to be going in a very robust way.
I second most of what @SebastianZ said, but I'd like to say I'm not sure repurposing the visibility
property would be the best way, because:
I would propose we create a different property, either optimize-positioning
(if it is to be used in contexts other than "anchoring") or anchor-optimization
(if it is to always be related to anchoring).
Another contribution I can make is to explain some possible logic for the positioning optimization, because I have had to deal with these kinds of edge cases before.
The following image shows basically three possible edge cases:
Thanks everyone for providing your thoughts here! Apologies it took me a bit to respond, was out of office last week. :)
Cross-linking here similar issues raised on the MS Edge Explainers repo.
There a lot of different ways we could go with an anchored positioning scheme, and many of these have perf/implementation implications that we will have to sort out (including the original proposal). I think before diving into a specific direction on syntax, we should revisit the use cases.
For tomorrow's discussion (and feel free to add comments here, particularly if you're unable to attend):
Thanks @leolopes for providing the edge cases! These were certainly in mind when we were putting together the position-sets()
proposals. Is it your preference that the browser automagically handle these use cases (in which case it may choose a non-preferred position/size), or would you like to have some manner of control over how these are handled? Could you describe the level of control you are looking for?
Hi @melanierichards ! I am a very strong defender of the power of defaults. A solid and well thought default will probably serve most use cases, and take from the developer's shoulders all the weight of having to specify behavior.
That said, defaults handle most cases, but not all. Every kind of control you can have is welcome, and might be what makes your solution enough to deal with the rest of the (unforeseen) cases.
The options you laid out are all valid, and maybe all of them should be baked in. The order in which you wrote them are also what I would propose: a "layered" approach, where the developer can, in order:
You see, the developer can create an extremely customized behavior for the popup if they so wish, or maybe, do nothing and let the browser deal with the problem while they go for a walk and a cup of coffee (what I would do most of the time) :)
I might not be able to attend today, but I am glad to help anyway. Please keep us posted here.
A select
is a very good example for me. I never once been let down by the browser handling the way the options are shown, so long as I can see the options and choose.
But I have been many a time disappointed by developers choosing a non-optimal way to show the custom select options, and not being able to seem them because they were off-screen.
@melanierichards asked:
What are your use cases for anchored positioning?
I've got the classic tooltip-on-hover use case on a music website (mousing over a tune name pops up a preview). Currently all the positioning is calculated in JavaScript and it certainly would be great if the browser handled it instead. Personally I don't need much in the way of control for this particular use case.
One thing though: I was wondering whether a new element is really necessary? After all, if the proposed attributes (popup
and anchor
) define the relationship, then isn't minting a new popup
element redundant? After all, the existing button
element works for the anchoring item.
Or is the idea that the element being popped up would have an explicit ARIA role? If that's case, could the existence of an anchor
attribute on any element provide the same ARIA meaning? (Though I don't think there's any precedence for this other than with explicit aria-
attributes.)
Hi @adactio, I think the purpose of having a dedicated element is two-fold:
Are responsive sidenotes a possible use case?
They're far too hard, with the CSS we have today.
I think this could be an incredibly exciting proposal for extensions, so I wanted to quickly answer the questions from that point of view.
What are your use cases for anchored positioning? What do you need to be able to achieve? As much detail as possible is great.
In 1Password, we have an inline menu which appears directly below the focused input element:
Positioning this is hard. We currently use getBoundingClientRect
to determine the field position on focus, and then add a fixed position element. This is fine for the majority of cases but doesn't work as well when a field animates in - https://discord.com/login is one example of this. I imagine the browser could do a much better job of watching for position changes and moving our menu at the same time.
A few other challenges which I don't think this spec can solve in isolation, but I wanted to mention:
How much control vs simplicity do you need over positioning?
This isn't something I've given much thought, but "I want to provide an initial position, and give the browser some hints as to which automatic changes are ok (horizontal repositioning, vertical repositioning, horizontal resizing, vertical resizing, align edges only, etc.)" feels appropriate.
The most thoroughly-implemented prior art I've seen on this is the Popper JavaScript library. Its documentation provides what is likely to be a sensible starting point for a list of desirable capabilities and sensible defaults, and goes on to describe how these are implemented as a sequence of "modifiers" to the DOM elements and their styles.
Thanks so much to everyone who has commented on this issue, your feedback truly is appreciated!
Thanks for the use case! The way you currently have this implemented:
Could you potentially describe for me how much of that behavior is important to hint to the user agent? e.g. would you want to express just (1) and have the browser do the rest? Would you want to say "place me wherever you will, but use the tooltip midpoint as a guide"? Would you want to say "only flip the positioning in a vertical direction, don't use a side position"? I suppose you would also need some way of knowing how to place/style directional elements like the tooltip "stem".
Regarding the <popup>
element, there's some other things that come for free with this element, such as top-layer rendering without clipping, inherent "transience" behaviors (e.g. "light dismiss"), user-agent-maintained mutual exclusivity of popup rendering (unless they're nested popups), etc. The explainer goes into more detail, but we think this a useful element to build on top of for many different use cases. Due to that, the accessibility semantics of the popup should be somewhat simple, and authors can layer on top of that (e.g. for a listbox
). But the various different relational properties should have internal accessibility semantics describing the relationship, as you mentioned.
Thanks for the sidenotes use case! From what I observe:
Does that describe the ideal sizing and placement behavior for you? How much of a hint would you want to give the browser about the fallback size/placement? For example, if you wanted to use automatic logic for the browser ("do what you need to do to fit this") would you be sad if the behavior at (3) was instead "browser makes the sidenote very skinny in order to fit" or "browser displays the sidenote so that it's vertically centered with the element, but may be overlapping/obscuring the element"?
Thanks for providing this use case and describing the level of control you'd like to have!
When a field is focused in an iframe, we add the menu element to the parent frame. Doing this requires a lot of work. If we could position relative to an element in another frame, that would be incredible.
Does this refer to anchoring elements in two different documents/frames to each other? Unfortunately that would be out of scope for <popup>
, due to security concerns.
Currently there is page content and browser UI, and nothing in between. It would be great if there was something like the "top-layer" concept, that allowed us as an extension to show over anything else on the page. z-index is the closest thing we have but isn't without its drawbacks.
Thanks for this feedback! I think there were some folks mulling over some ideas for a top-layer primitive; will pass this along.
Thanks for sharing Popper! Do I interpret you correctly that effectively what you'd like to see is "provide a start position, and give the browser hints as to what is ok (flip, prevent overflow, etc)"? Are there any modifiers in Popper that are extraneous to you and your use cases? Or in the reverse, is there some manner of control that feels like it's missing in the library? Or is Popper pretty much exactly what you need?
Thanks in advance to all!
Hi all, we were thinking it would be useful to have a one hour workshop soon where we look at the top use cases for anchor pos vs how we might achieve them in various syntaxes. @una volunteered to organize, so I'll defer to her on sharing additional details/coordinating!
In preparation for considering use cases, I wanted to drop in some examples we're aware of:
Disregarding that many of these are currently rendered in a separate window from the main document
datalist
/ autofill for text inputs
and the likecolor
popup value pickerdate
, datetime-local
, month
, time
, week
popup value pickersselect
listbox: high priority use case, as we'd like to use anchored positioning for a customizable select prototypetitle
tooltipsThe popup research lists a bunch of these that fall under a few classes:
Here's also a quick export of scratchpad files where we were playing around with some of the exemplary use cases and repositioning (can look at porting this Figma file to somewhere public/copy-able if there's interest):
Anchored Positioning - Boundary Awareness.pdf Anchored Positioning - Use Cases.pdf
/ cc @mfreed7 who was interested in considering top use cases for anchored positioning.
Thanks @melanierichards for putting this together! I think it will be super helpful to narrow this down to the 5 (+/- 2) key use cases, so we can really flesh out what the developer experience will look like.
I think your initial list is great, and I appreciate that you added all of the relevant items from the existing web platform. I can't think of any others, though I'm sure others will have good suggestions.
My one suggestion here would be to add something of a short "developer story" for each example. For example, there may be two types of developer looking at implementing something like a tooltip. One just Wants It To Work :tm: without any hassles - i.e. specify that it's a popup tooltip anchored to an element, and let the platform take care of all of the details. Another might want to really control where the tooltip shows up, what happens if it doesn't fit, etc. I don't necessarily think we need to enumerate all of these possibilities for each control type, but it would definitely be good to have a variety of them included. And I think this needs to be an explicit part of each example.
My one suggestion here would be to add something of a short "developer story" for each example. For example, there may be two types of developer looking at implementing something like a tooltip. One just Wants It To Work ™️ without any hassles - i.e. specify that it's a popup tooltip anchored to an element, and let the platform take care of all of the details. Another might want to really control where the tooltip shows up, what happens if it doesn't fit, etc. I don't necessarily think we need to enumerate all of these possibilities for each control type, but it would definitely be good to have a variety of them included. And I think this needs to be an explicit part of each example.
💯, @mfreed7! Once we pick our top 5ish use cases, we should have ~3 developer stories for each that can be used to write pseudo code in the workshop. It would be interesting for folks in the workshop to describe what they think the platform magic/algorithm would be in the case of "I want to provide an initial position and let the browser reposition and resize it at will, such that it fits in the viewport", just to make sure we all have the same sense of magic. :)
For those who weren't on the Open UI call, we were thinking about picking a few core use cases for anchored positioning, putting those use cases in a deck, and then having a one-hour workshop where we invite folks to pick up a use case and try to pseudo-implement it with the various different syntaxes that we have floating around. That will be instructive regarding how easy / useful / extensible a particular syntax is…or how we might evolve the syntax to support the range of developer stories (ultimate magic to ultimate control).
Please subscribe me for this workshop. Getting my head more around some of this now and I think it would be really informative as it seems a bunch of the use cases empowered by anchor positioning might be for things that aren't quite popup (or maybe I misunderstand that)... Seeing how those fit and resolve would be really helpful for me.
Sure thing @bkardell! I think it is a Good and Expected thing if anchor positioning is extended beyond popup. For the initial proposal we scoped down to browser-managed, top-layer elements (which also includes things like dialog
) due to performance concerns of doing something like this for non-top-layer, non-transient elements. That said, we've heard feedback that people might like this for non-top-layer use cases, and so we might be able to explore some solutions there…though, caveat emptor, there may still need to be restrictions or authors may expect a perf hit in some scenarios.
@melanierichards:
Thanks for the sidenotes use case! From what I observe:
- The sidenote's start position is to the right of the element (in an LTR language, anyway), and vertically centered next to the element.
- If the viewport is too vertically short to fit all the sidenote contents, the sidenote is resized vertically with scrolling overflow.
- If the viewport is too horizontally narrow, the sidenote is instead fixed-position in the top left corner of the viewport (instead of relative to the element) and is sized to fit the viewport.
Does that describe the ideal sizing and placement behavior for you?
I think you're describing one specific way that responsive sidenotes could work. The thoughtfully-compiled print and web examples in Gwern Branwen's post on the subject show that there are others. (Something I missed when I read that page for the first time was: you can hover over all of the web implementation's names in order to read a discussion of each solution and how it does or doesn't respond gracefully to various contexts.)
Generally, there seem to be two ways of structuring the DOM when doing responsive sidenotes: either you put the notes inline (which gives them appropriate block-axis positioning "naturally"; they are then floated out of their parent and into the margin for inline axis positioning), or you put the notes all together somewhere else in the DOM (e.g. all together in their own <ol>
at the end of the document, like Markdown and most other endnotes/footnote implementations on the web do), and do all of the sidenote positioning the hard, fragile way: with Javascript.
Some form of anchor positioning that let you position elements relative to other elements, no matter where they were in the DOM, seems like it could help achieve many potential sidenote layouts with arbitrary DOM structures, including, importantly, the common Markdown structure.
(Another huge problem when doing sidenotes is what to do when the density of notes is such that they start to overlap; how to get them to gracefully "stack" in the block axis? I have an intuition that anchoring a note that comes shortly after another note to that previous note, rather than to the text that it annotates, could solve this, but I honestly haven't thought through this case enough to state that anchoring is the best solution to this tricky problem.)
How much of a hint would you want to give the browser about the fallback size/placement? For example, if you wanted to use automatic logic for the browser ("do what you need to do to fit this") would you be sad if the behavior at (3) was instead "browser makes the sidenote very skinny in order to fit" or "browser displays the sidenote so that it's vertically centered with the element, but may be overlapping/obscuring the element"?
Ideally, CSS provides tools that are low-level enough that folks can choose and design different solutions for the narrow-viewport case. From Gwern's examples: some implementations employ full-viewport overlays, as you describe; some display the notes inline, directly after the text that they annotate; some whisk them away into standard footnotes; some turn them into tooltip-y hover or click popovers. Different solutions will make sense for different types of content and within different designs. Rather than one magic/rigid solution, I would prefer if CSS allowed authors to explicitly design their own solutions.
This was discussed during last week's telecon and @una will be setting up a workshop to go over the usecases and possible syntax proposals for the various use-cases to try and gain some alignment on the path forward for anchor-position.
Hey all, we have a lot of great syntax proposals here. I wanted to capture them all in one location and go through them in a workshop. If you have a proposed idea for anchor positioning, can you please add it to this deck:
https://docs.google.com/presentation/d/1g0kCtpbGHqzJybhrP1vgbQapXSZW3zMopYOjNfBf0OQ/edit?usp=sharing
I'll shortly send around a Doodle to find a time for a side-meeting to review the proposals and discuss pros and cons of each solution, hopefully narrowing it it down.
Thanks again @una for putting the deck together! I've added a couple demos: teaching UI with more opinionated re-positioning logic, and the sidenotes example from this thread. Also added an "assumptions" slide for us to collaborate on.
@melanierichards Thank you for the slides! I believe most of the added examples are also covered in the initial 3 demos, so lets maybe expand on those if they're not clear rather than add more examples. I added my syntax proposal to the doc for discussion - do you mind adding yours?
@una Will add the syntax from the explainer!
I'd like to see us cover a couple different examples to make sure we're accounting for different real-world developer stories with regards to automatic repositioning vs developer control. Example C reflects pretty simple repositioning in 1(?) axis, and may be more reflective of an "automatic repositioning" developer story (there's a fair amount of room for interpretation there, which is good for generating discussion). Demo E (Teaching UI) captures an example where the developer has specific requirements for how the element is repositioned and resized in two axes. And Demo F (Sidenotes) captures a divergent use case from both C and E where the developer wants to conditionally drop anchored positioning and use a fixed positioning scheme based on constraints of the layout viewport.
Love the proposal! One example I’m particularly interested in is a combination of anchor positioning and animation. So the position the browser chooses determines from where a pop-up animates from: anchored to bottom, animate translateY(100px); anchored to right side, animate translateX(100px) etc.
Should this be done using css custom properties inside the position-set? Or some other way I’m not seeing atm?
I know there is a need for declaratively defining what should anchor to what and what button should trigger which popup, but an issue I can see with the current id-focused syntax is how shadow roots scope IDs. For example:
<div id="my-anchor"></div>
<my-popup>
<template shadowroot="open">
<popup anchor="my-anchor">
<slot></slot>
</popup>
</template>
</my-popup>
In this case, the anchor attribute on popup cannot penetrate the shadow root and target the div. This is an issue with aria attributes that require IDs as well, which is what the accessibility object model is trying to handle, but it's only really tackling aria. For example, this is how describedby would work with the declarative version of aria delegation mechanism (not finalized):
<div id="my-label"></div>
<my-popup aria-describedby="my-label">
<template shadowroot="open">
<popup auto-aria-describedby>
<slot></slot>
</popup>
</template>
</my-popup>
Note, the RFC written only has the imperative manner written, but the declarative version is soon to be documented.
The thing is that this process generally works for "global" attributes like all aria attributes, so I can see this work for [popup]
with an [auto-popup]
, but [anchor]
is not global and only on <popup>
. I'm sure this can be handled from the WC side of this, but I can see it requiring allowing [anchor]
to be placed on other components perhaps role="popup"
? Alternatively, the <label>
tag can also describe things it wraps so that you don't have to use for="id"
. Could anchoring work somewhat similarly or be worth considering?
Alternatively much of this can be side-stepped by allowing setting anchor imperatively via HTMLPopupElement.anchor = HTMLElementInstance
as long as strong role and aria support is built into the popup proposal, then AOM can handle this with little input from the open-ui side. e.g.
<div id="myAnchor"></div>
<my-popup></my-popup>
<button>Show Popup</button>
<script>
class MyPopup extends HTMLElement {
connectedCallback() {
const sr = this.attachShadow({mode: 'open'});
sr.innerHTML = `<popup><slot></slot><popup>`;
this.#popup = sr.querySelector('popup');
}
set anchor(el) {
this.#popup?.anchor = el;
}
show() {
this.#popup?.show();
}
hide() {
this.#popup?.hide();
}
}
customElements.define('my-popup', MyPopup);
const customPopup = document.querySelector('my-popup');
customPopup.anchor = window.myAnchor;
document.querySelector('button').addEventListener('click', () => {
customPopup.show();
});
</script>
In short:
Thanks @e111077, would you mind filing a fresh issue for this topic? I'd say this impacts not just the CSS-based anchor positioning syntax, but other considerations established by the anchor
relationship. Funnily enough, I had thought that we had written up a way to declare this imperatively in the initial explainer, but now I see that we actually lost that as we made some changes and foo.anchor
is only used in an example in the open issues sections. Imperative declaration certainly seems reasonable to me!
The Open UI Community Group just discussed [Last Call for Participation] Anchor Workshop
.
The Open UI Community Group just discussed Anchor Syntax Review
.
My two cents: I would roll with a simple implementation without introducing new properties for positioning the popup – in user land we position popups with top/right/bottom/left relative to the reference element and I think that's a good starting point.
I would rather focus on auto positioning when it comes to overflow and have a property to make the popup behave like a select menu or datalist i.e. fit in the viewport. Maybe popup-overflow: <hidden|visible>
.
For those who want to implement a custom select, another handy feature would be using a selected item within the popup as anchor origin – this is what select does (see imagine above). Maybe this could be called anchor-origin
or can be something like an html attribute.
There hasn't been any discussion on this issue for a while, so we're marking it as stale. If you choose to kick off the discussion again, we'll remove the 'stale' label.
@una I did a quick skim of the historical discussion, are the use cases discussed here covered by the current CSS Anchor Positioning specification?
I'm going to go ahead and close this as anchor positioning is well beyond the realms of OpenUI at this point. If there're any use cases not covered currently an issue in the csswg repo is the best action.
Hello -- I just wanted to give my 2 cents on the anchor positioning syntax/experience (a bit more declarative than the current proposal)
Connecting Anchor
This section is the same as the proposal:
Anchor Positioning
My interpretation here would be that
anchor
is a CSS property with values relative to the connected anchor.Values:
top
/block-end
bottom
/block-end
left
/inline-start
right
/inline-end
center
These are combined in a space separated list:
You could also use them individually with defaults, (i.e.
anchor: left
would likely default toleft center
.)Viewport Optimization
I'd also propose an additional value (or property) to try to optimize for keeping the popup in the viewport. For the sake of this argument, let's call it
optimizeVisibility
, but this name is not something I am attached to.This would tell the browser to start from the anchor position, i.e. if it is
bottom center
, and try to position it there. If this position would cause the element to go out of the viewport, the browser would reposition it to fit as close tobottom center
as will fit within the viewport, but would remain visible in the screen. It might be more to the left of center if the popup button is on the top-right corner of the screen, for example.Option A is to have this be a part of the
anchor
property:Option B is to have this be a separate property with some relevant values:
This would allow for some offset
Viewport Offset
Another idea is to enable an offset from the viewport edge for the
optimizeVisibility
option:Option A, a part of the
anchor
property:Option B, separate property:
This would allow for some offset
Would love your thoughts!