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-box] increase pointer target size independently of element layout #4708

Open
tylersticka opened this issue Jan 28, 2020 · 21 comments
Open
Labels
css-ui-4 Current Work

Comments

@tylersticka
Copy link

It's critically important that touch/click target sizes be adequate for an interface to be usable. But sometimes the visual needs of an interface element are out of step with its ideal pointer target size.

Some of the ways developers deal with this today:

  • Nesting additional elements so the interactive area can be defined separately from the visual appearance. This complicates the markup.
  • Using transparent borders and background-clip. This forces use of box-shadow in place of border and may also prevent border-radius from working in the expected way.
  • Absolute positioning pseudo elements larger than the parent element. This conflicts with overflow: hidden.

It would be cool if we could somehow extend the pointer box of an element without impacting its layout or visual appearance?

.button {
  pointer-box-offset: 0.5rem;
}

pointer-box-offset-opt

(I was encouraged to submit this issue after writing about the idea.)

@fantasai fantasai added the css-ui-4 Current Work label Jan 28, 2020
@fantasai
Copy link
Collaborator

This sounds like a straightforward solution to a reasonable problem! Copying terminology from border-image I'm gonna suggest outset rather than offset, though. :)

Side note: pointer-events still hasn't been added to the spec per #4438 pokes @frivoal

@smfr
Copy link
Contributor

smfr commented Feb 4, 2020

We'd need to define what happens boxes that are fragmented (split inlines etc), regarding whether the outset applies at the fragmentation edge. We'd also need to define its interaction with the various clipping mechanisms (overflow, clip, clip-path etc), whether touch-action regions are impacted, and whether the target region affects all interaction-based DOM events.

@fantasai
Copy link
Collaborator

fantasai commented Feb 4, 2020

@smfr Good points. Perhaps it should be a single value, like shape-margin? Then it can outset whatever the boundary line path is. Wrt fragmentation, I'd say you want to expand per fragment. I think most of the point is to impact touch? Probably should affect any coordinate-based DOM events, exactly as if the border area had been expanded--the current workarounds are effectively trying to do exactly that, just without affecting the painting area.

@bfgeek
Copy link

bfgeek commented Feb 5, 2020

One additional related thing we've seem some asks for previously is defining a "shape" for the touch area as well. E.g. somebody is creating a visual effect but wants to limit the hit-test region to a circle/ellipse/arbitrary-path.

(This additional request shouldn't block progress on a "margin" property, I'm bringing it up b/c I want to make sure we don't exclude this type of request in the future).

This extension point almost fits within the existing pointer-events property, e.g. extending by:
pointer-events: none | auto | <shape-box> || <basic-shape> | <image>
One possibility for this feature for this particular request would then be:
pointer-events-margin: <length>

Ian

@c-smile
Copy link

c-smile commented Feb 12, 2020

There is a known term in UI for that entity - hit testing. See: WM_NCHITTEST as an example.

So I think hit-margin would sound reasonably well for that purpose.

If that matters, in Sciter I've implemented this functionality using that name.

@upsuper
Copy link
Member

upsuper commented Feb 16, 2020

I like the idea, and it's indeed highly desired.

It might be worth considering that, though, how to handle such "margin" property with border-radius and clip-path. For example, if you have a circle element, would the hit area be a circle or a square (or a round-corner square)? If you have a complicated shape via clipping, how should it work? I'm not very sure about the answer here.

@c-smile
Copy link

c-smile commented Feb 16, 2020

if you have a circle element, would the hit area be a circle or a square (or a round-corner square)?

I would use standard margin production for that : up to four lengths to define rectangular hit-box.

We also can add extended form like these:

hit-margin: border 10px;
hit-margin: clip-path 10px;

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-box] increase pointer target size independently of element layout.

The full IRC log of that discussion <dael> Topic: [css-box] increase pointer target size independently of element layout
<dael> github: https://github.com//issues/4708
<dael> fantasai: Seemed reasonable proposal. Came from someone posting on twitter, I said file and issue, they did with nice diagrams. It seems to be a nice proposal nd solving a problem
<dael> fantasai: Seems simplier. Basically hit margin with a length and it expands outward from border edge of element
<dael> astearns: Expands the not quite defined hit area
<dael> fantasai: Yep
<dael> smfr: mobile browsers do area hit testing where if you tap browser looks around touchpoint. So there's built in hit test area expansion stuff. Don't know if have to define how that interacts
<dael> chris: Woul this replace or coeist
<dael> smfr: Not sure, I guess coexist
<dael> astearns: Define what mobile browser does in UA stylesheet.
<dael> astearns: Would be good to see if what we define would suffice for ua stylesheet. If not should fiddle
<dael> smfr: Good point. Also hit test can't leak outside iframes. Cross origin you can't allow it to got o the parent iframe
<dael> smfr: Also slightly concerned about clickjacking. You can do a link that covers document. Could do same with event hanlers but slightly nervious
<dael> astearns: Can't do same with slightly opque element on everything?
<dael> smfr: Yeah, that's not new
<dael> fantasai: Could limit size, can't have margin larger then something reasonable. Can already do the same thing as you mentioned
<dael> plinss: I haven't read it but does it define how to handle overlapping elements?
<dael> fantasai: aalreayd have to define. This increases border box fo hit testing w/o painting it
<dael> astearns: It does allow touch places to overlap where wouldn't notmally. Can do it with positioning but this is new overlap
<dael> smfr: Complicates impl b/c gneerally hit testing is painting in reverse. You hit test front to back. With this you extend elements to correct order in way that only effects hit testing. Leads tocomplications
<dael> plinss: Want to make sure it's defined even if treated as overlapping [missed]
<dael> astearns: Yeah, this would be cool to have. Need somebody to write a proposal. Who would that be?
<dael> astearns: And spec?
<dael> fantasai: CSS UI 4
<dael> astearns: Who are editors?
<dael> smfr: [missed]
<florian> I am an Editor of UI-4
<smfr> s/smfr/florian me/
<dael> tantek: This is very geometry related. Related to box model. And to hit testing which is undefined and may be worth spec on own.
<dael> tantek: Not similar to other cssui properties.
<dael> tantek: I don't think we should burden cssui 4 without florian saying he can help
<dael> florian: I'm not opposed to idea but not committed to idea.This is hard, hit testing is hard
<dael> tantek: And people who have tried to spec hit testing have run away
<dael> fantasai: I don't think this is too hard. I'll take the action to make pr
<dael> myles: Question: idea is inflate touch target so people can hit with fat finger. If that's try why isn't value a bool?
<dael> TabAtkins: Agree. You just want to make sure target is wide enough without ensuring whole element is wide enough. So make this target a fingerprint wide seems reasonable
<dael> tantek: Maybe 3rd state to shrink target area to avoid errant activation. UI elements that are damaging you want to reduce accidental compared to button they're near. Length may be overdesign, I agree
<dael> chris: Intended to cover case where there's a button but it's not a code button and you have text that is a link and you want if people click in general area. Is that use case being solved?
<dael> tantek: Should be solvable with eisting markup
<dael> astearns: Whole problem is solvable with markup now but as author states it's unfortunate to change makrup to get hit testing
<florian> s/this is hard, hit testing is hard/I don't think this is partcularly hard in itself, but hit testing in general is, so that depends on whether we open that can of worms/
<dael> tantek: I meant w'o adding more markup. Text link you can add explicit directions. I think we should distunguish common author errors and use cases we want to enable. Common author errors aren't fixed with a new feature
<dael> fantasai: I don't see how existing properties solve this w/o creating fake elements. Text link where you want to increase size of link without layout impact
<dael> tantek: But its' a text link inside something htat looks like a button and the answer to that is make it a button. I agree there are use cases for button with area around it like example in issue. That's legit.
<dael> tantek: I like it being higher level so UA can decide based on device. Don't need every webdev to solve what device with which resolution...I'd hate to put that burdon on webdev and UA can solve if there's touch-target: larger
<dael> myles: even on phsycial device can have larger resolution
<tantek> I'm suggesting a trinary
<tantek> per the shrinking use-case
<dael> astearns: We've had good discussion around length or bool. Let's engage issue poster on opinion between options and work from that?
<fantasai> +1 to astearns
<dael> tantek: I agree with sentiment
<dael> astearns: Okay, let's get back to Tyler. I'll ping

@c-smile
Copy link

c-smile commented Feb 19, 2020

florian: s/this is hard, hit testing is hard/I don't think this is partcularly hard in itself, but hit testing in

I don't think it is that hard.

It is just about replacing existing [pseudo-]code

if ( point is in el.border_box() )
  ...

by

if ( point is in el.hit_margin_box() ) // or path
  ...

Yes, there are issues with overlapping elements but that can be solved by authors using existing means:

button { 
    hit-margin:1em;
    margin:1em; // to avoid overlapping with siblings
 }

or

button { 
    hit-margin:1em;
    position:relative; // to move it in front of z-order
 }

@smfr
Copy link
Contributor

smfr commented Feb 19, 2020

One reason to have a flag, rather than a length, is that these hit-test margins need to scale with page zoom; you need relatively larger hit-test margins on a page with a small scale than one with a big scale (after the user zooms in). UAs don't want to re-evaluate style on zoom, so we don't want units that change with zoom.

@smfr
Copy link
Contributor

smfr commented Feb 19, 2020

hit testing is hard

I meant for implementors, not authors.

@astearns
Copy link
Member

@tylersticka could you look through the minutes above and weigh in with your thoughts about making this property more high-level (larger/normal/smaller instead of a particular size)?

@astearns astearns removed the Agenda+ label Feb 19, 2020
@plinss
Copy link
Member

plinss commented Feb 19, 2020

Gave this some more thought, we definitely need to carefully define how overlapping hit test areas work, and it’s more than standard overlapping element logic. My concern is when you have two adjacent elements and the extended hit test area of one covers another clickable element. If the user clicks inside an element, but also inside an extended hit test area of a sibling with higher z-order, the click should still go to the clicked element, not the sibling. Especially with dynamic layouts, it’ll be too easy for elements to slip under other element’s hit test areas and become unclickable in ways authors may not anticipate.

@tylersticka
Copy link
Author

Really quick, I'd just like to say "thanks" to everyone for giving this so much deep thought and discussion. Greatly appreciated.

@tylersticka could you look through the minutes above and weigh in with your thoughts about making this property more high-level (larger/normal/smaller instead of a particular size)?

I've re-read the transcript a few times, and I'll admit to feeling pretty skeptical.

Let's say you have a horizontal menu containing multiple buttons side by side with some space around and between…

Two buttons side by side, one labeled 'Button 1' and the other 'Button 2'

<div class="menu">
  <button>Button 1</button>
  <button>Button 2</button>          
</div>
.menu {
  display: grid;
  grid-auto-flow: column;
  grid-gap: 1em;
  padding: 1em;
}

Now let's say we want to extend their interactive area a bit because we want them to be easier to touch. To pull this off today, we might use a pseudo element that extends outward by half of the gap (CodePen):

.menu button {
  position: relative;
}

.menu button::after {
  content: "";
  position: absolute;
  top: -0.5em;  /* half of grid gap */
  bottom: -0.5em;
  left: -0.5em;
  right: -0.5em;
}

This extends the hit area for everyone, and mouse users get a more seamless experience when moving their cursor from one menu item to the next. Hooray!

Now in a world where I have hit-margin (or whatever we might call it) and I can specify an exact size, simplifying this CSS is very simple. I can instead write:

.menu button {
  hit-margin: 0.5em; /* half of grid gap */
}

Since I defined a grid-gap of 1em, I know that 0.5em is the most I can extend the hit area without overlap.

But I'm not sure how I would do that with keywords alone. How do larger or smaller relate to the white space choices I've defined in my CSS?

@c-smile
Copy link

c-smile commented Feb 19, 2020

For the note: you can try hit-margin live in https://sciter.com

<html>
    <head>
        <title>Test</title>
        <style>

.menu {
  flow: horizontal;
  border-spacing: 1em;
  padding: 1em;
  background: gold;
}

.menu > button { hit-margin:0.5em; }

        </style>
    </head>
    <body>

<div.menu>
  <button>Button 1</button>
  <button>Button 2</button>          
</div>

    </body>
</html>

Run usciter[.exe | .app] from GitHub https://github.com/c-smile/sciter-sdk

copy bin.win/x32/usciter.exe and sciter.dll to some folder and run executable
Pretty much the same for MacOS and Linux but in bin.lnx and bin.osx folders.

@coolaj86
Copy link

coolaj86 commented Apr 21, 2021

I have discovered a method that appears to work and, while not as elegant as the proposed solution, seems far more ergonomic and sensible than unstyling semantic elements to instead style children inside of them, or perhaps the other clipping method mentioned above.

label {
    /* the dimensions in which to increase the touch / click target */
    padding: 5px;
    /* make up for the combined lost width */
    width: calc(100% + 10px);
    /* un-offset the element back in its original visual position */
    position: relative;
    top -5px;
    left: -5px;
}
<label><button>Hello!</button></label>

I had this thought because I noticed that you can use <label> to increase the target size of a checkbox or radio button and I thought the rule may apply generally. It appears that it does!

I'm not sure what type of trickery may be necessary if things are bunched closely together, but this worked for my immediate use case.

I'm a complete CSS novice (backend dev), so I would be very interested if anyone has an innovation to add to this method which would be more appropriate while we wait for a better solution to make its way into the standards, and then browsers.

Update: Another, perhaps more robust solution using transform:

@cwadrupldijjit
Copy link

@coolaj86, I can see only one potential issue stylistically if you use the position: relative trick--it will still push things around it out, which might make things look awkward. I see that the codepen solution you proposed is a little better, but I would propose a slightly more elegant solution here (taking what you came up with and adjusting it slightly):

The difference is that you don't need to do any additional element wrapping in order to get that effect. The outline I added (of course) is only to show the clickable/tappable area, but you get the idea of how it would work. Should also work regardless of which element it's put onto.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-box] increase pointer target size independently of element layout.

The full IRC log of that discussion <dael> Topic: [css-box] increase pointer target size independently of element layout
<fantasai> github: https://github.com//issues/4708#issuecomment-588369114
<dael> fantasai: Posted a link to the comment with follow-up
<dael> fantasai: Last time had a question for the commentor about it being a length or larger/normal/smaller
<fantasai> https://github.com//issues/4708#issuecomment-588451067
<dael> fantasai: Commentor responded ^
<dael> fantasai: Example of 2 buttons side by side and explaining author would not be able to know distance. Not spec a length larger. If we made it up to UA maybe there would be overlap
<dael> fantasai: That was a concern by the poster. Related, plinss commented explaining what happens with 2 JS elements with extended hit area. Don't want to cover another element. Need more sophisticated logic then extending the hit area
<smfr> q+
<dael> fantasai: These points were brought up. Figured bring back to the group for discussion on how to move forward
<astearns> ack smfr
<dael> smfr: Question if we need this. Mobile browsers have something we call area hit testing. When you hit test you look in area around target that respond to events. One answer is UA should do it automatically somehow
<dael> florian: Tempted to agree b/c how big hit area needs to be is not something author can know. Depends on type of thing used to click, finger or stylus. Ratio between css pixels and layout. It's guesswork
<dael> florian: Probably UA is in better position
<dael> myles: Similar. If you pinch zoom finger to page changes. Anything that's fixed is not right tool
<dael> iank_: Trying to remember if we had this convo. We had people asking for this a while ago. might be on us to circle back with what they were after
<dael> astearns: Do you mean automatic for "this"
<dael> iank_: Not auto. A fixed length. I think chrishtr was more involved. I'm diging from my memory. But I don't think there's more we can do
<dael> florian: Do all browsers to area hit testing or is it apple specific?
<dael> smfr: Pretty sure it's mobile browsers. We do it on mobile WK. I think Android has
<astearns> ack fantasai
<fantasai> https://cloudfour.com/thinks/jagged-little-pill-issues-with-rounded-buttons/
<dael> iank_: I believe we have similar. Not area of expertise
<dael> fantasai: Illustration from issue ^ Someone writing about rounded corners on buttons reducing click area and they wanted it fixed. That's another consideration
<dael> fantasai: If we're seeing a lot of people doing this with hacks we should build in. If browsers can do it automatically and we don't need hacks that's idea
<dael> iank_: Potential for that. I have hear border radius reducing hit test. Argument for authors to opt out, particularly with large rounded corner. Unlikely there will be other elements
<dael> iank_: We likely should move on. Not sure how much more we can do on this today
<dael> plinss: I'm in favor of leaving to UA. Might be worth spec an algo to get interop
<dael> astearns: That would start with defining hit testing
<dael> florian: I believe there's an action on me for years ago to put something i spec. I don't think there's a good definition of it, so it's not in spec
<dael> astearns: iank_ if you can dig up the request that would be great to add to the issue

@astearns astearns removed the Agenda+ label May 5, 2021
@Malvoz
Copy link
Contributor

Malvoz commented May 6, 2021

In the CSS WG discussion (#4708 (comment)) @fantasai said:

If we're seeing a lot of people doing this with hacks we should build in.

I'd like to point out that Lighthouse has an audit that fails tap targets that are smaller than 48 by 48 in CSS pixels, they recommend using padding as one way to ensure accessible tap targets. Additionally WCAG 2.1 Success Criterion 2.5.5 Target Size requires targets to be at least 44 by 44 CSS pixels (with some exceptions). So I think this is a pretty common concern for developers with accessibility in mind.

@BillGoldstein
Copy link

FWIW, I'm pretty sure that Lighthouse actually checks for WCAG's 44 by 44 target size, even though the check's failure text says it checks for 48 by 48 (from earlier Material Design docs, IIRC).

@mayank99
Copy link

mayank99 commented Oct 10, 2024

I was thinking about this proposed CSS property after coming across openui/open-ui#1104. It would be useful in that context, because interactive elements nested inside a block link would likely need their hit targets to be enlarged.

Another idea I was thinking about was the possibility of specifying a "minimum hit target size". While it wouldn't provide the same level of granular control as hit-margin, I think it would be very valuable just for being an easy way of increasing baseline accessibility. Maybe this property could even be inheritable, which would make it easy to implement different "densities".

Example
input[type="checkbox"] {
  width: 16px;
  height: 16px;

  /* ensures the hit target size of checkbox is 24x24, even though visually it's 16x16 */
  hit-size: 24px;
}

html {
  &[data-density="compact"] {
    /* ensures the hit target size of all clickable elements is least 24x24 */
    hit-size: 24px;
  }
  &[data-density="comfortable"] {
    /* ensures the hit target size of all clickable elements is least 48x48 */
    hit-size: 48px;
  }
}

There could be two different properties for "hit target size" and "hit target margin" and maybe they could be combined into a shorthand? The shorthand could accept an auto value that tries to satisfy SC 2.5.8.

hit-target: auto; /* "auto" tries to meet AA, "larger" tries to meet AAA */

hit-target-size: 24px;
hit-target-margin: 4px;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
css-ui-4 Current Work
Projects
None yet
Development

No branches or pull requests