Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[css-anchor-position-?] Add a ::tether pseudo-element #9271

Open
xiaochengh opened this issue Aug 30, 2023 · 3 comments
Open

[css-anchor-position-?] Add a ::tether pseudo-element #9271

xiaochengh opened this issue Aug 30, 2023 · 3 comments

Comments

@xiaochengh
Copy link
Contributor

(This is a sub-topic of #9117)

The Anchor Positioning Exploration proposal has a ::tether pseudo-element that represents the "connection" area between the anchor and the anchored element. The advantages include:

So I'm proposing adding this pseudo element to the spec. However, as this can become a very complicated topic and there are many details uncertain, I think this may better go into Level 2 of CSS Anchor Positioning.

We can also use this as an all-in-one issue about ::tether, before reaching anything resolvable.

(Rough) Proposal

Add a ::tether pseudo-element to CSS Anchor Positioning Level 2:

  • ::tether's originating element must be an absolutely positioned element with a valid default anchor. Otherwise it has no effect
  • ::tether is a tree-abiding pseudo-element that creates an absolutely-positioned box, which is inserted as a sibling after its originating element in the box tree1
  • ::tether allows all properties and declarations as long as they don't break the previous bullet
  • ::tether can be nested in a @try block (like @try { ::tether { ... } }), so that the declarations apply only if the @try block is applied2

Notes:
1 This allows ::tether to use its originating element as well as the originating element's anchor as anchor elements
2 This allows e.g. setting different arrow directions for different fallback positions, which is essentially a fallback position query as we mentioned earlier

Discussions

One thing I'm particularly unsure about is how should ::tether interact with automatic position fallbacks, or any other short syntax for simple position fallbacks.

The original proposal uses position-area-based UA stylesheet to set different borders for different position areas. However, we currently don't have position-area-based fallback syntax, so this doesn't easily apply. Also I've heard some thoughts that this might not satisfy all use cases (e.g., if the tether diagonally connects the two elements).

For automatic position fallbacks that auto-flips styles, we may consider auto-flip ::tether style in a similar manner. The drawback is that it doesn't work with transform, which seems to be a common pattern to draw an arrow.

@tabatkins
Copy link
Member

Yeah, I'm strongly for making this a level 2 feature. It looks super useful, but I think there's a lot of open questions for it, and I don't think we want to slow down the rest of the spec resolving it. It should be the #1 feature for the next level, tho.

For example, automatic positioning of the tether, based on the relative position of the anchor and the abspos. For "smart" positioning we might want to, say, take border-radius into account when possible, etc.

Or for another, how the border of the abspos interacts with the tether. As proposed in the grid-based exploration, you can somewhat fake this by overlapping the tether over the abspos's border, but of course that makes a number of assumptions that might not be true. It would be nice to figure out a "proper" answer to this, even if it's limited to a ::tether special-case rather than a generic mechanism.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-anchor-position-?] Add a ::tether pseudo-element, and agreed to the following:

  • RESOLVED: mark ::tether as at risk and leave note in the draft
The full IRC log of that discussion <bramus> TabAtkins: we had an issue about a way to style an arrow in response to abspos relative to anchor. this was more explicty in apple’s proposal with ::tether
<bramus> … this is a great idea.
<bramus> … having a border around the whole box + arrow seems like a need
<bramus> … but also very difficult
<bramus> … proposal to move to level 2
<bramus> … apple’s proposal had good <missed>
<bramus> … to be clear it’s the styling, not the position
<bramus> … this might block us now, so like to push it furhter down the future
<bramus> astearns: are you talking about deferrint he styling or the ::tether allogehter?
<bramus> TabAtkins: the ::tether alltogehter. styling is essential and i think we need to get right
<florian> q+
<astearns> ack fantasai
<bramus> fantasai: curious to hear you expand a bit about styling that needs to be worked out
<astearns> for tooltips the tether (whether you can style it or not) seems pretty important
<bramus> TabAtkins: simple case: abspos is a solid bg with no border.tether is a triangle with same color. that is easy.
<bramus> … you might need to to a little bit of neg margin
<bramus> … hard part is a border or border-radius. getting tether to integrate with those and having border flow with it and not visibly be underneath it is hard to solve
<bramus> … and people want to do that based on existing example
<bramus> … also see examples outside of the web
<fremy> q+
<bramus> … i want to make sure we can handle that or recognize that we cant
<florian> q- later
<bramus> … border is the one that really bothers me. e.g non-linear border around anchor en tether
<bramus> fantasai: you can hack with drop shadows
<bramus> TabAtkins: a little bit
<bramus> fantasai: but i would like to do better
<bramus> … you can get pretty far with drop shadow, but do undrstand concern
<bramus> TabAtkins: potentially
<bramus> … needs more time to bake, and dont want to delete rest of the spec
<florian> q- later
<fantasai> s/delete/hold up/
<astearns> ack fremy
<kizu> q+
<bramus> fremy: similar question. i have impression that implementin tether itself is not a lot of work and will solve a lot of cases
<bramus> … maybe needs some trickery, but most cases it would solve the problem
<bramus> … you *want* a tether
<bramus> … do you really believe we need to defer, tab?
<bramus> … or do you believe it is too much effort?
<bramus> TabAtkins: if one feature takes a lot more work than rest of spec … don’t like to add things that will delay baking time
<bramus> … there are rendering concerns. As much as possible i would like tether to do right thing for authors and not give them a bad result to be angry about
<bramus> … we need a resonable rendering result with the styles in the UA. common cases should work out of the box
<bramus> …if we put it in L2 and do find it easy to solve, happy to pull it back into L1
<astearns> ack florian
<bramus> florian: I think agree with tab that this has extra complexity that will take time
<bramus> … but i don’t think we are at that point to go to CR yet, so seems premature to push it back now
<bramus> … even if incomplete, we should work together with the rest
<bramus> … as we evolve the spec, we should keep working with it
<fantasai> s/rest/rest, to ensure it all integrates together properly
<fantasai> +100 florian
<bramus> … my recommendatoin would be to keep it in for now with the understanding that impls might not start there and do the rest first, and spec wise it is not unlikely that we would evntually push it to L2
<astearns> we have a process for at-risk things
<bramus> kizu: other concerns outsid eof border issues
<bramus> … how to position it in more edge cases
<bramus> … is ok when position on TRBL
<bramus> … but on corners it is much more cmoplicated
<florian> s/we should keep working with it/we should keep working with it together with the rest, to make sure that the model stays coherent/
<bramus> … e.g. what if element is completely over other element? where to draw the tether and how to show it (pointing to left or right)
<bramus> … also depends on how we do fallback and conditional styling
<bramus> … tether with conditions maybe?
<bramus> … would be happy with basic implementation in L1 to be able to play with it
<astearns> q?
<bramus> … but lot of small issues –its a complicated topic
<astearns> ack kizu
<bramus> fantasai: agree with florian on keeping it in L1 that it helps us think about how it works with rest of styling model, e.g. fallback model
<TabAtkins> q+
<bramus> … how would that work with tether.
<astearns> ack TabAtkins
<bramus> … dont want to defer to L2, even if florian says it might end up there
<bramus> TabAtkins: I realize I am hypocretical at this as I dont like 2 levels of ED. Fine to not put it in L2, but want to mark it as risk in L1 saying that it is *super experimental*
<florian> seems fine to me
<bramus> proposed resolution: mark ::tether as at risk and leave not in the draft
<bramus> astearns: proposed resolution: mark ::tether as at risk and leave not in the draft
<florian> s/not in/note in/
<bramus> RESOLVED: mark ::tether as at risk and leave note in the draft

@kizu
Copy link
Member

kizu commented Sep 15, 2023

I wanted to add some examples of what I meant by complicated ::tether cases.

Here is the exploration that I did that I would use to show them: https://codepen.io/kizu/pen/zYMmVJd (at first, I wanted to write an article about it and my findings in it, but couldn't come up with a cohesive text, so I would contribute my thoughts on the related issues instead).

They take a bunch of vertical space, so putting them inside details A screenshot of a popover positioned tightly above the anchor, without a space for a tether element.

What if there is no space between the anchor and the abspos? Would we need to add an explicit min-height in this case to the ::tether, and require it to align with the bottom of the abspos still?


Screen.Recording.2023-09-15.at.21.22.23.mov

The corner-case can be the most complicated, probably: if we want to have an arrow, then we would need to have a way to also have a certain min-width, stop before the border-radius ends, and then also somehow determine its position for the corner case: should it be on the block or inline side? How the ::tether would know about which side it is in, given that in all cases that could be start / start?


A screenshot of a popover positioned exactly at the center of a popover.

When we position the popover at the center of an anchor — should it have a ::tether? Where?


A screenshot of a popover positioned far from the anchor, making the tether element span the length from the abspos to the anchor.

How should the default styles be defined for cases like this? Something like an aspect-ratio?


A screenshot of a popover positioned over a very tiny dot of an anchor, making the tether very thin and high.

If the anchor is very small, should the tether follow its size, or should it have that min-width in this case and be centered? Or should it be very small?


In the 2 previous cases, I can see designs where we could want to have the size of the :tether exactly as on the screenshots, like for the “connecting line” style of tethering, where it must go from one element to another. So maybe we'd need to have some control over how the ::tether is aligned in its “box”, making it so the actual tether area is actually akin to the grid cell, with the element itself being able to either stretch, or be aligned in some way (with some auto alignment to the closest side of the abspos maybe?)


As a sidenote, speaking of the idea mentioned by @tabatkins about the border going over the tether — is there somewhere an issue about this?

I can see that effect a bit separately from the ::tether itself, where we'd want to be able to “merge” (in vector editor terms) multiple rectangles into one shape, allowing the background to seamlessly go through multiple elements, and decorations like borders and shadows following the edge in some way. Probably similar to how Safari handles the default outline in the case of elements going beyond their parents? See https://codepen.io/kizu/pen/QWzMZZG (though the border-radius looks weird in it — I guess it is not a trivial thing)

A screenshot of a focus outline from Safari showing how it goes around the element that is absolutely positioned on the bottom of a block.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Friday Afternoon
Development

No branches or pull requests

4 participants