w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.44k stars 656 forks source link

Add hover/focus/long-press triggering delays to CSS #9236

Open mfreed7 opened 1 year ago

mfreed7 commented 1 year ago

Please see the Popover Hint and Hover explainer for more context:

https://open-ui.org/components/popover-hint.research.explainer/

We're working on an addition to the Popover feature that allows authors to easily and declaratively get hover-triggering of popovers. (And to make sure all input modalities are covered, "hover" includes keyboard focus and also touch screen long-press.) The idea for now is to use the popovertargetaction attribute, with a new value called interest (see this discussion for context on the name) that enables this new mode of triggering. When popovertargetaction=interest on a button that points (via popovertarget=foo) to a popover, that popover will be triggered when one of these things happens:

The key phrase above, and the point of this issue, is that the delay should be developer-configurable. Leaving this delay up to the UA leads to issues and missed use cases. For example, the built-in tooltip that shows up as a result of the title attribute has one major, common complaint: the UA-imposed delay is too long. Other, more creative use cases of this feature would also require a customizable hover-delay. For that reason, I'd like to propose that this delay is set in CSS, via a new property:

button[popovertargetaction=interest] {
  popover-show-delay: 0.5s;
}

There is another quite related, yet separate, set of behaviors that happens after the popover is shown. Typical "tooltip" use cases would also like the tooltip to be hidden after the tooltip stops being hovered for a period of time. To make this work, both the invoker (the button above) and the popover should be able to be hovered to maintain the popover in the open state. But once both of them have been de-hovered for a period of time, the popover can be closed. For this, I propose:

[popover] {
  popover-hide-delay: 1s;
}

Note that in the above proposal, the "show" delay is applied to the button that triggers the popover, while the "hide" delay is applied to the popover. That's because those elements are where the action takes place. However, one could make the case that it'd be nice to instead put both properties on one element, and the [popover] would seem to be the natural place to put it. In that case, the above properties could also be combined into a single two-valued property (credit @una for the idea):

[popover] {
  popover-delay: 0.5s 1s; /* first value = show delay, second value = hide delay */
}

Thoughts?

mfreed7 commented 1 year ago

See also these related discussions:

rthrejheytjyrtj545 commented 1 year ago

Can this work at the level of matching selectors by inventing functional forms for them like :focus(visible, 30ms) and adding arguments to forgiving selectors like :where(0 0 0, .3s / :not(:active))?

mfreed7 commented 1 year ago

Can this work at the level of matching selectors by inventing functional forms for them like :focus(visible, 30ms), :hover(3s) or adding arguments to forgiving selectors like :where(0 0 0, 300ms / :target, :active)?

I'd be worried about that approach, because then you'd need a CSS way to actually trigger the popover/behavior. I.e. you'd need :focus(visible,30ms) { trigger-popover-now: yes; }. So far (and as far as I can see it going), that really belongs in the HTML part of this feature, right? Also, I think the feature I've described doesn't have an equivalent pseudo state already. :focus gets the keyboard part, :hover gets the mouse hover part, nothing gets the long-press part, and (most importantly) nothing enforces that you need to use them all together or someone will be broken.

rthrejheytjyrtj545 commented 1 year ago

If authors want to control popovers regardless of the state provided by :popover-open and default styles, they can already do that, that is not a problem.

then you'd need a CSS way to actually trigger the popover

the display property defines an element’s display type

so far (and as far as I can see it going), that really belongs in the HTML part of this feature, right?

user agents are not required to present HTML documents in any particular way

the feature I've described doesn't have an equivalent pseudo state already

custom selector which is written as a pseudo-class with the given \, and represents a :is() selector using the provided \ as its argument

nothing gets the long-press part

:active pseudo-class applies while any generated box of any element (or pseudo-element) is being actively indicated by a pointing device (in the “down” state), e.g. between the time the user presses the primary mouse button and releases it, or while a finger is pressing on a touchscreen

tabatkins commented 1 year ago

Yeah, this isn't really doable via Selectors, it's triggering a different behavior that's not CSS controlled. CSS doesn't make something a popover, that's a quality of it imposed by the DOM APIs (or the UA itself in some cases). So that's not a viable approach.


Back to the OP, this seems reasonable.

I agree that it would make the most UX sense to set both the show and hide delays on the same element. I could see it being set on either the button or the popover, tho - as you say, both the popover and the invoker button need to be dehovered before the hide timer starts. Since you're setting the "interest" popover method on the button, and these are both effectively just applying some config to the "interest" method, I think it probably makes the most sense to put them both on the button, then?

One note is that we don't use CSS to configure/control non-CSS concepts much (at all?). Is it needed here, or should it be communicated in the DOM attribute? Why are the delays in CSS, but the indication that you want to use "interest" method is in the DOM? I presume the reason to put the delays into CSS is because they're unlikely to be different per-invoker, so you can reduce a lot of repetitive attribute values by making it a property, but would that similarly apply to the popover method?

(I think CSS should be used for non-CSS concepts a lot more, it's a rich and powerful language both in values and targeting, and authors are intimately familiar with it. I'm just wondering what the reasoning behind this particular slicing of responsibility is.)

rthrejheytjyrtj545 commented 1 year ago

Also #6719 can be useful in this case, with ::popup it will be possible to bind more properties to the popover associated with a particular button, including the suggested.

rthrejheytjyrtj545 commented 1 year ago

By the way, the name of the issue is a little confusing, it seems to describe the need for a general mechanism for this, the description only mentions the use case for opening or closing popovers.

mfreed7 commented 1 year ago

I agree that it would make the most UX sense to set both the show and hide delays on the same element. I could see it being set on either the button or the popover, tho - as you say, both the popover and the invoker button need to be dehovered before the hide timer starts. Since you're setting the "interest" popover method on the button, and these are both effectively just applying some config to the "interest" method, I think it probably makes the most sense to put them both on the button, then?

Interesting idea to put it on the button. I was initially thinking it made more sense to put them on the popover, since that's the thing that is showing and hiding. But I like the idea of adding both to the button; that also makes it possible to use the same popover invoked via different buttons that each have different delays. I'm not sure what the use case is, but it just feels more flexible which is good.

One note is that we don't use CSS to configure/control non-CSS concepts much (at all?). Is it needed here, or should it be communicated in the DOM attribute? Why are the delays in CSS, but the indication that you want to use "interest" method is in the DOM? I presume the reason to put the delays into CSS is because they're unlikely to be different per-invoker, so you can reduce a lot of repetitive attribute values by making it a property, but would that similarly apply to the popover method?

(I think CSS should be used for non-CSS concepts a lot more, it's a rich and powerful language both in values and targeting, and authors are intimately familiar with it. I'm just wondering what the reasoning behind this particular slicing of responsibility is.)

The reason I proposed using CSS for this is exactly what you said: it's just easier to do it there. I would bet that the overwelmingly-common thing is for all popover invokers on a page to use the same standard delays. So it's easier to do button[interesttarget] {interest-delay: 0.5s 0.5s;} once and not have to worry about adding attributes to all the buttons. The interesttarget attribute is in the DOM because (I think) it's somewhat semantic - it tells you these two elements are linked together via this connection. Also the a11y associations typically happen as a result of the DOM content and not as a result of anything from CSS.

rthrejheytjyrtj545 commented 1 year ago

I would bet that the overwelmingly-common thing is for all popover invokers on a page to use the same standard delays. So it's easier to do button[interesttarget] {interest-delay: 0.5s 0.5s;} once and not have to worry about adding attributes to all the buttons.

Another solution would be to make the proposed properties inheritable so that authors can set them directly to the root.

mfreed7 commented 9 months ago

Hello, I'd like to ping this issue as the result of a good discussion we just had in OpenUI related to the delays discussed on this issue:

https://github.com/openui/open-ui/issues/963#issuecomment-1856462744

There are a number of things discussed there, including the concept of a safe-area triangle. But related to this issue, a few interesting things were discussed. First, it does seem that folks like the idea of allowing CSS to control these delays, independently for the "show" and "hide" actions. In addition, we had a good discussion about specifying the delays themselves. As background, there are several issues with these delays:

Given the above constraints, the new idea is to specify the delays not as actual time values, but as "slow" or "fast", etc. So:

button[interesttarget] {
  interest-delay: [none|slow|normal|fast] [none|slow|normal|fast];
  /* interest-delay: interest-delay loseinterest-delay */
}

It would then be up to the UA to determine how to resolve "slow" into an actual delay value in seconds. The UA could also offer a user preference like "Minimal delays please" which would then reduce the delay value for all settings, or "I want more time" to increase them.

Thoughts? Suggestions?

annevk commented 1 month ago

Since we don't have a good handle on a cross-platform solution to "rich tooltips" WebKit doesn't think this is ready to move forward. See https://github.com/WebKit/standards-positions/issues/305#issuecomment-2231000262 for additional context.

mfreed7 commented 1 month ago

Since we don't have a good handle on a cross-platform solution to "rich tooltips" WebKit doesn't think this is ready to move forward. See WebKit/standards-positions#305 (comment) for additional context.

Thanks. See also my response. This issue is about solving one small piece of the tooltip puzzle. You've raised other issues, such as touchscreen, on the WebKit standards position. I hope you can help us with solutions to the issues you've raised! But since this issue is unrelated, perhaps we can still discuss it?

bramus commented 1 month ago

One thing that came up in this discussion on X (then still Twitter) was that a delay itself doesn’t always cut it.

Sometimes, you want the delay to only start counting from the moment the user has actively stopped over on the element instead of just a fly-by hover which just happens to be slow enough for the delay to expire.

/cc @simevidas

css-meeting-bot commented 1 month ago

The CSS Working Group just discussed Add hover/focus/long-press triggering delays to CSS.

The full IRC log of that discussion <keithamus> masonf: Quick intro. Recent comments makes me think we need to raise the issue generally on if tooltips are worth solving. This issue is around discussing ideas.
<masonf> - Explainer: https://open-ui.org/components/interest-invokers.explainer
<keithamus> ... related to interest target proposal
<keithamus> ... general story: other API called command/commandfor/invokers. Lets you invoke an element based on activating a button. This API is similar but instead of activating it invokes by merely showing interest; e.g. hovering mouse, focus keyboard, long press on touch, etc.
<keithamus> ... use case are tooltips, hovering menus, other cases where the user hasn't yet clicked
<keithamus> ... I don't think we want to debate the case just yet but we want to discuss the delays involved in this
<keithamus> ... tooltips are typically implemented with delays to avoid very noisy UI. That counts as showing interest. The fact the user, for e.g., has stopped the mouse there for a period of time indicates to the UA the user showing interest
<flackr> q+
<keithamus> ... why in CSS? The delays aren't necessarily semantic, but also are likely applied unilaterally on the page, so perhaps `*` or some other selector. Also prefers-* queries may influence that, e.g. reduced-motion.
<astearns> q+
<keithamus> ... some users may prefer longer delays, its also a developer specified period of time, some sites - e.g. games - might want shorter or longer time
<keithamus> ... there are two things, one is showing interest, the other is _losing_ interest, when you move away and want it to hide
<emilio> q+
<keithamus> ... where it currently stands is a single property shorthand with two delays, and values are generic, e.g. short/medium/long. This allows varying by OS or modality, e.g. short might be shorter for keyboard than mouse
<oriol> present+
<keithamus> ... so. Does this belong in CSS? Or should it be elsewhere? Does the approach make sense? Are there better ideas? Most interested in the last.
<astearns> ack flackr
<TabAtkins> I think this sounds reasonable and I'd like to explore it. Unsure if this is the exact shape, but this space seems useful to me.
<keithamus> flackr: as you were talking; one thing that I kept thinking of; should developers be customizing the delay at all? Original use case for delay is that hover shouldn't be instant. But if we don't allow for customizing we can align to platform delay lengths
<keithamus> ... hover menus aren't a good UX pattern... Is this something which needs to be customized or is this something which we can have as a UA value
<PaulG> q+
<keithamus> masonf: I believe there are different usecases eg menu vs tooltip, tooltip might have a longer delay because you want to make sure the user wants to see that thing whereas menus might be snappy
<keithamus> ... there is already `title` attribute which users complain is too long
<keithamus> flackr: we should change that if the common feedback is the delay is too long
<keithamus> masonf: I don't disagree
<kizu> q+
<keithamus> astearns: different timing for different affordances could be something in HTML. Different built-in timings for that.
<kbabbitt> q+
<keithamus> q+
<keithamus> astearns: Would we need a `never` or some other value that stays shown until you hover over the next one?
<keithamus> astearns: Other question; does this belong in CSS or HTML... maybe this is just a javascript feature? In JS you can determine MQ state and change things so it wouldn't necessarily be in CSS
<astearns> ack astearns
<TabAtkins> I can definitely say that debouncing correctly is much harder than one would think.
<TabAtkins> (I'm doing that in JS for Bikeshed.)
<astearns> ack emilio
<keithamus> masonf: the reason I don't think it should be in JS is it's tricky, debouncing gets interesting, keeping track of various timings. BTW losing interest can happen from both the button and the thing that invoked it, so it can get tricky in JS
<keithamus> emilio: this seems doable already in a sense. The same way people are adding entry/exit animations in dialog. Other than that I think the feature without a hardcoded duration makes sense. In theory UAs or something else should invoke this... ??? like invokers. I wanted to clarify that this seems doable with transition behavior discrete and existing
<keithamus> infra, but maybe that's wrong?
<keithamus> masonf: it's more tricky to do with entry/exit and some things are impossible like losing interest - you lose interest on the combination of losing interest on both button and invoker
<RRSAgent> I have made the request to generate https://www.w3.org/2024/08/14-css-minutes.html fantasai
<keithamus> emilio: the way I think with :hover and transition, keeps the interest, only if the thing you're popping up is inside of the dom of the anchor... it's a bit tricky and harder, but not impossible
<astearns> ack PaulG
<keithamus> masonf: you mention hover, that covers mouse users, but not other input users. Like popover, it sounds simple for one modality but gets complex in the details, thats my concern
<ydaniv> q+
<emilio> masonf: a counterpoint for that would be that you might be interested only in one kind of interest (like hover, but not keyboard focus perhaps?)
<emilio> But yeah the general thing seems worth exploring
<keithamus> PaulG: always a fan of progressive enhancement. I worry about lack of consensus on tooltip as a pattern, but just to clarify other patterns Ive seen or used, aside from tooltip... hover menus are a thing. Focus works the same way, focus/hover should do the same thing. Touch is the same as a click... my main area to push back on is timing as a token
<keithamus> as a specific time
<keithamus> ... a lot of people are concerned with specific times, especially wrt satisfying success criteria.
<keithamus> ... so I'd say go towards focus/hover pseudos as a way to separate those out rather than token/values. Touch would be separate
<keithamus> ... unless we add another pseudo but I don't think it would make a difference
<keithamus> ... everything else seems to be answered by the writeup but I'd like to see other use cases. What seems to far afield?
<astearns> ack kizu
<keithamus> kizu: authors need a way to provide custom duration, in my example let's say a design system already implements this - they already have different values, we have specific values for this. If we introduce this through CSS we'd probably want to match these. We will not have a different experience, users are used to a certain delay. In this case we'd
<keithamus> want to use a custom property in CSS and normalise for every use case. Kind of related to what PaulG says, we'd want some way to separate and where we'd want to apply this.
<keithamus> ... usually we dont want any delay with focus, immediate feedback. Reason for delay on hover is you can accidentally trigger, e.g. leave an area, return the cursor the tooltip wants to go away. With focus this isn't an issue. RIght now this can be implemented with transitions, but currently not possible with display transition. When transition to
<keithamus> none elements lose events, so you cannot have transition on display.
<keithamus> ... So I agree we need this property but it should be more author configurable
<keithamus> ... e.g. games might want immediate responses.
<astearns> ack kbabbitt
<keithamus> kbabbitt: I wanted to make the exact same point on games wanting instant response or 0s or something. AIUI the keywords were introduced to give a degree of control, that's an important use case. I wonder if we could do something similar to e.g. forced-colors where we want to force a UA setting to override what the author sets.
<fantasai> scribe+
<astearns> ack keithamus
<fantasai> keithamus: One use case I want to represent, where CSS feels appropriate
<fantasai> ... delay might want to be configurable based on presence of an active tooltip
<fantasai> ... e.g. if you currently are looking at a tooltip, and are in a mystery menu
<fantasai> ... you might want the delay to be shortened on subsequent things
<fantasai> ... that is trivially expressable in CSS right now, but much harder in other languages
<astearns> ack ydaniv
<fantasai> ydaniv: Agree with keith and roman. Anywhere we try to solve in keywords, it always failed.
<kizu> +1 to Keith, libs like Tippy have this as an option: https://atomiks.github.io/tippyjs/v6/addons/#singleton
<fantasai> ... for example in smooth scrolling, left up to UA, and we tried to migrate to it but it looks different in different browsers so got lots of backlash from users
<keithamus> ydaniv: Anywhere we try to solve values with keywords where the UA can chose, it always fails. For example in scrolling. Smooth scrolling is left up to the UA. It looks different, different speed in different browsers, tons of backlash with that
<keithamus> ydaniv: I think here it would be good to go with time values. CSS is a good place to put it. We have all the ergonomics. The right declarative place to put it.
<emilio> q+
<masonf> q?
<astearns> ack emilio
<PaulG> q+
<keithamus> emilio: I wanted to provide a counter point to the keyword. For more user-choice vs author-choice, e.g. scrollbar with has auto vs precise pixel value, otherwise you cannot allow users who need more delay to have more delay. So I disagree on the need for precise time.
<keithamus> astearns: one reason we dont have pixel values for scrollbars is because some OSes don't support changing that, that's not the case for these kind of delays
<keithamus> ... if there we platform specific delays that were widely used and people relied on, then I could see your point.
<keithamus> ... I don't think this is OS specific.
<keithamus> emilio: I agree it's not OS specific. It's more about - as a user... I guess you could override with a user stylesheet, but it loses the intent of making it short or long
<keithamus> masonf: I had the same concerns but user agents could have a setting like "double all the delays" or clamp them to a range. As long as the UA can override those specified by the developer, as long as there's a mechanism.
<dholbert> q+
<keithamus> astearns: I'd definitely support allowing UAs to override, but I don't think we should build it around UA preferences.
<astearns> ack PaulG
<flackr> q+
<astearns> ack dholbert
<keithamus> PaulG: multiplicative idea for UA setting would be great. WCAG 221 is 10x, so allowing user 10x time to do a task. If this were part of that this would allow people to spend a lot less code on a feature. Great progresssive enhancement and accuracy across user experiences
<keithamus> dholbert: specifying exact time; the idea of letting UAs add multipliers... I worry a little that with specifying exact time, developers would coordinate animations with delays which would look cool but would break with UA adjustments.
<keithamus> ... it might not work in practice.
<astearns> ack flackr
<masonf> q+
<keithamus> flackr: I wanted to make an argument against complete customisation. Couldn't UAs have a sensible tooltip delay that makes sense. I've heard interesting ideas of how that could work such as subsequent tooltips being instant - this could be something the UA could do in general. The argument for this is that the UA could provide a consistent
<keithamus> experience across sites and the OS.
<astearns> ack masonf
<keithamus> ... this is why scrolling in general isn't customizable. Users aren't surprised that sites don't change scroll
<keithamus> masonf: Is the point that we shouldn't allow customisation, or specific numbers?
<kizu> q+
<keithamus> flackr: unless we have strong reason to believe that UA delays don't work we should have UA determined.
<kizu> q- will comment in the issue
<kizu> q- to comment in the issue
<keithamus> masonf: appreciate the feedback. I think I heard open questions; specific delays might be better than named values. Different delays based on modality, hover vs touch. Focus delay should be zero, but I think there should be a non-zero focus delay for folks tabbing in the document.
<keithamus> ... should there be a pseudo class for first tooltip open, etc... I'd love to have more feedback on the issue. Thanks for the discussion
<keithamus> astearns: Is this going to form controls task force, or just tooltip discussion?
<keithamus> masonf: I opened this issue about a year ago, but it's clear I need to bring the tooltip issue to the task force as there are wider questions. I don't know if this rises to that level.
mfreed7 commented 1 month ago

Thanks for the great discussion and ideas. I heard these general viewpoints (none were unanimous):

Further ideas and discussion is welcome!

kizu commented 1 month ago

Comments promised in the call:

@flackr: I wanted to make an argument against complete customisation. […] The argument for this is that the UA could provide a consistent experience across sites and the OS.

I think the web platform is rich enough to have vastly different types of apps and sites in it, where it might not be possible to normalize them to a specific set of values. Some apps might want to have snappier values, others — more relaxed. A work tool like a monitoring app will likely need a different set of values compared to something like a casual blog or a promo page. short and long could mean different things in the context of the corresponding design systems, and a pre-defined list of UA-only values couldn't cover all the use cases (but might be useful as the default consistent list).

@mfreed7: It's still possible for UAs to override this for users, e.g. via a "make delays 10x longer" setting.

@dholbert: I worry a little that with specifying exact time, developers would coordinate animations with delays which would look cool but would break with UA adjustments.

I like an idea of a global 10x longer setting. For cases where we'd need to synchronize things, we could introduce something similar to forced-color-adjust property, but for these delays/transitions.

flackr commented 1 month ago

My argument for not customizing this is that it empowers the UA to provide all of these good behaviors to all popover hints rather than requiring each developer to think about them, e.g.:

I also feel like the use cases for instant reveal are fundamentally different than a "short" delay, and may be best represented by either a different named concept, e.g. hover.

Some apps might want to have snappier values, others — more relaxed.

I worry that this sort of customization may not actually be providing a better user experience.

There were some questions during the call about touch - I think that just like click, contextmenu, :hover, and other "mouse-centric" properties where we already have a way to trigger with touch, we would do the same for this capability. My proposal which aligns with android behavior would be to show it after a short delay of pressing down - long enough to not be considered a click.

kbabbitt commented 1 month ago

Re: customizing delays vs not -- why not both? Provide at least an auto value that leaves it up to the UA to align to preferences, perhaps also short / long / etc. for variances where the author wants some variance but doesn't care about specific values, and also accept <time> for authors who have specific values in their design language - with the provision that UAs can still override those specific values using a forced colors like mechanism.

kizu commented 1 month ago

Clear allowance to align with user / OS preferences,

A predefined list of keywords would be enough for most cases, while a custom duration will be an escape hatch for those cases where things are important for the authors. “Simple thing easy, complex — possible”.

Can be based on a time after stopping movement

I don't think this contradicts a user-defined value. This could be a default behavior, with a potential additional option to opt-out of it (but I don't think it is necessary).

Can eliminate or significantly reduce the delay for opening the n'th hint after a first one is open

The problem: there are cases where we'd like to have independent groups of tooltips. Two toolbars on two different sections would want to “share” one delay across items inside them, but not across sections.

I worry that this sort of customization may not actually be providing a better user experience.

Relying solely on the OS/UA behavior will mean there will be no room for innovation, and as soon as someone will want to do something unusual and modify the experience a bit, they will have to opt out of the default behavior completely, rather than use an escape hatch. Which will lead to a much worse experience and potential footguns while trying to re-implement it with other means.

flackr commented 1 month ago

Relying solely on the OS/UA behavior will mean there will be no room for innovation, and as soon as someone will want to do something unusual and modify the experience a bit, they will have to opt out of the default behavior completely, rather than use an escape hatch. Which will lead to a much worse experience and potential footguns while trying to re-implement it with other means.

So to be clear, I'm not saying that we shouldn't also allow some customizations, but I am concerned that if we try to design a bunch of strictly specified individual features we may make it harder for the UA to innovate while still honoring the developer specified values. My proposal is more that we determine what properties a common solution can have, and then add customizations as needed to meet the use cases (with clear examples) that are fundamentally different.

flackr commented 1 month ago

I built a demo to show what's possible based on an immediate state change (e.g. :hover) using transitions on a custom property with style queries on that property: https://codepen.io/flackr/pen/gONXNdV