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] Allow anchoring to pointer #8639

Open
jakearchibald opened this issue Mar 24, 2023 · 9 comments
Open

[css-anchor] Allow anchoring to pointer #8639

jakearchibald opened this issue Mar 24, 2023 · 9 comments

Comments

@jakearchibald
Copy link
Contributor

Right now, if you want to drag an element on the web, you need to listen for pointermove events and update the position of the element. This means the operation is bound by the event loop, and can easily jank.

It feels like anchoring could solve this, by anchoring to a particular pointer. Then, the element can be moved to a layer in the compositor, and its position can be updated without blocking on the event loop.

@tabatkins
Copy link
Member

The syntax allows this. Named anchors require dashed idents, so we can add non-dashed idents to refer to special anchors like this - anchor(pointer top), etc.

The layout model should allow it too - pointer position is outside of layout entirely, so in theory it's pipeable into this system without issue.

Impl is potentially a different story, since we'd want to make sure it was accurate each frame (rather than lagging a frame behind). @xiaochengh will have to speak to that, for Chrome's impl at least.

@xiaochengh
Copy link
Contributor

I assume this pointer anchor's containing block is the ICB, which means only fixed positioned elements can use it.

Performance-wise it means we need a relayout on every pointer move. But maybe in most cases it won't be a big problem, since I assume in most cases the size of the element doesn't depend on pointer location -- in which case we can avoid reflowing the descendants of the element. But still this all seems to be main thread work, and I don't see a possibility of further optimization with compositor.

Btw I assume anchor-size(pointer ...) is either 0 or always fall back?

@tabatkins
Copy link
Member

I assume this pointer anchor's containing block is the ICB, which means only fixed positioned elements can use it.

Hm, I suppose so. I suppose the CB doesn't actually matter, tho? Maybe we can add a case to the valid-anchor algo that allows for these "no CB at all" cases to be used anywhere?

Btw I assume anchor-size(pointer ...) is either 0 or always fall back?

I'd probably just not allow it in the anchor-size() grammar at all. It'd just be confusing, since either it'd always be 0x0 or it'd always be invalid for sizing and cause fallback.

@SebastianZ
Copy link
Contributor

For what it's worth, anchoring to the pointer was also suggested by me in #8315 (comment).

Sebastian

@kizu
Copy link
Member

kizu commented Mar 26, 2023

There is one important aspect that I think should be mentioned: if we're going to add an ability to attach something to the cursor, I think it would be very important to also be able to attach something to the document.activeElement, use the currently focused element as the fallback for the pointer, or something else.

This would be kinda possible by assigning the anchor-name dynamically to the element with the :focus or :focus-visible (though, this method would currently lack transitions), but I think we need to think if we would want to have something that could easily incorporate both methods?

If we could come up with something that could allow developers not to forget about the keyboard users when assigning things to the cursor — it would be great! Otherwise, they would need to handle this by themselves somehow, but I'm not yet sure how this would look code-wise. Probably something like using the focus-visible as default (using the center of this element, or something else? Or, as the cursor does not have dimensions (Edit: @SebastianZ's idea to be able to use the actual cursor's size as the dimensions; though we'd need to then have different queries for the cursor itself, and for the point that it points towards), maybe the sides used with the pointer could determine the position for the active element fallback?), then falling back to the pointer — basically this example — https://codepen.io/kizu/pen/PodVKxG — but where instead of the fallback element we'd have the pointer.

If we could somehow combine this into one easy to use thing in CSS, I think it could potentially prevent a number of developer mistakes. We could also still provide an ability to target only the pointer or active element, but the most simple case, imho, should target both.

I would also want to provide some other possible use-cases for pointer and/or active-element anchoring:

  • A tooltip following the cursor (existing js implementation of tooltips often has this, for example — https://atomiks.github.io/tippyjs/#follow-cursor).

    Screen.Recording.2023-03-26.at.12.11.08.mov

    (alt: A video showing the different ways the tooltips stick to the cursor in the tippy.js implementation)

  • CSS-only implementation for more forgiving dropdown menu's hover areas. CSS-Tricks article about this:
    An image showing a UI with a triangle starting from a cursor over a menu item and going to the left side of the dropdown menu to the right
    Not sure if pointer positioning would be the only thing required to achieve this (we would probably need something to actually calculate the angle etc), but it would make things much easier, as we could use the pointer's position for one side of our connecting triangle, and the left side of a popover as the other side.

  • A hover/focus state that follows the pointer/focus. There are probably hundreds of examples of this, where people are implementing something like this by either adding js that assigns a local x and y coordinates for a button to show a shiny gradient, like in this example by @LeaVerouhttps://codepen.io/leaverou/pen/qBEYGeq —  though this would require us to use the anchor values not just for the inset properties or dimensions, but for things like background-position (see [css-anchor-position-1] Using anchor offsets/dimensions for properties apart from inset/sizes #8586).

@bramus
Copy link
Contributor

bramus commented Mar 26, 2023

# I would also want to provide some other possible use-cases for pointer and/or active-element anchoring

Also see #6733 where I explored a similar thing to expose the pointer’s coordinates on the hovered element through a new :hover pseudo.

@jakearchibald
Copy link
Contributor Author

Let's keep this thread to cases where an element tracks the pointer. The ideas where a tooltip follows the pointer, or takes one axis from a pointer and another from an element are fun ideas!

@kizu
Copy link
Member

kizu commented Mar 27, 2023

Re-created this example with buttons on the CodePen with anchor positioning: https://codepen.io/kizu/pen/vYzbqOW

Instead of the pointer I'm using an element with relative position, and only use JS to modify its coordinates to “ponyfill” the absence of the actual pointer attachment. The codepen could be probably forked if someone wants to experiment further with the pointer anchoring :)

@kizu
Copy link
Member

kizu commented Mar 27, 2023

In this example I also did add the handling of the :focus-visible — and if you'd remove the .button:focus-visible parts that override the pointer target variables, you'd see how it can be very easy to ”break” the display of the tooltip with keyboard navigation. That's what I meant by wanting to incorporate something built-in to make this kind of issue less likely — while developers could do it the way I did — they would need to explicitly handle this, and it would be really cool if we could provide a way to use the pointer position from the box without compromising the keyboard users.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants