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

:focus-visible's "hidden focus" artifact can result in user UI confusion on Mac #257

Open
cookiecrook opened this issue May 18, 2021 · 13 comments

Comments

@cookiecrook
Copy link

cookiecrook commented May 18, 2021

One example I have not seen discussed is the default Space Bar behavior when an activatable element is focused.

  • When no element is focused, pressing Space Bar in Safari will cause the page to scroll downward.
  • When a <button> is tab-focused or script-focused, a visible focus ring is displayed and Space Bar in Safari will activate the button.
  • Space Bar activation is consistent with platform interaction conventions on the Mac. Similarly Windows users expect Enter to be the primary activation key press.
  • [Update for clarity] When a native <button> is clicked, it does not receive keyboard focus from the click. The resulting state matches the user expectation that the button is not focused, it shows no focus outline , and therefore Space Bar will scroll the page.
  • [Update for clarity] However, when a custom button <div tabindex="0" role="button"> is click-focused, if the button remains focused but the focus ring is hidden, there is a user interface disconnect as to what Space Bar will do. Does it activate the button again (it will), or scroll down (as a user familiar with the Mac conventions would expect, since no focus ring is visible)?
  • This seems to be a critical interaction problem that is not addressed by :focus-visible.
  • The :focus-visible implementations for custom buttons in Chrome on Mac and Mozilla on Mac may now be out of alignment with this common Mac UI convention.

Similarly up/down arrow keys scroll the page by default, but modify certain controls (an slider, for example) when the control gets keyboard focused. The same is not true when these controls are modified with the mouse, as keyboard focus never moves to the control.

From a related thread:

For authors who want a control that participates in the tab focus cycle, but without drawing a focus ring on tap or click, [a better solution may be] to give them a way to make elements keyboard-focusable but not mouse-focusable. I don’t think there’s any support in the web platform for that, although the opposite is possible with tabindex="-1".

@robdodson
Copy link
Collaborator

robdodson commented May 18, 2021

The :focus-visible implementations in Chrome on Mac and Mozilla on Mac may now be out of alignment with this common Mac UI convention.

I think Chrome has had the behavior where it would focus the button on click, but hide the focus ring since before we started working on :focus-visible. I'm not sure what the thinking was behind that original decision, but I have heard at least one person argue in favor of it because they think that a user may mouse click on a button and then want to click it again using their keyboard, which would be possible on Chrome but not on Safari (I don't think?) because Safari doesn't put focus on the button when you mouse click it.

But if it's standard across all of macOS that buttons don't receive focus when they're mouse clicked, then maybe it's worth adopting that same approach in the browser. I can definitely understand the user argument that "buttons work this way on my computer except when I use this particular browser" and that being annoying for them.

Similarly up/down arrow keys scroll the page by default, but modify certain controls (an slider, for example) when the control gets keyboard focused. The same is not true when these controls are modified with the mouse, as keyboard focus never moves to the control.

Do you feel like the macOS/Safari behavior is correct here? For instance, if I click to drag a slider—but perhaps my mouse dexterity isn't perfect—in Chrome I can press the arrow keys to dial it up or down by a few units, and I'll see a focus ring as I do this. But in Safari I would need to use my keyboard to navigate back to the slider (from wherever focus is). If I tried to press the keyboard after dragging it, it would scroll the page.

@cookiecrook
Copy link
Author

cookiecrook commented May 18, 2021

Do you feel like the macOS/Safari behavior is correct here? For instance, if I click to drag a slider—but perhaps my mouse dexterity isn't perfect—in Chrome I can press the arrow keys to dial it up or down by a few units, and I'll see a focus ring as I do this. But in Safari I would need to use my keyboard to navigate back to the slider (from wherever focus is). If I tried to press the keyboard after dragging it, it would scroll the page.

I acknowledge there are benefits to either approach, but rather than discuss the value judgement of which is more "correct," I'd like to focus on the general Mac platform conventions and user expectations that:

  • keyboard focus remains visible
  • mouse click only moves keyboard focus when the element clicked accepts some form of character input (e.g. character value in <input> or typeahead in some other controls like menus and selects)
  • when there is an element with visible keyboard focus, certain keys (spacebar, arrows, etc) are sent to that responder
  • when there is NOT an element with visible focus, the user understanding is that the larger view is the key responder. For example, the Safari viewport scrolls with arrow keys or spacebar.

@bkardell
Copy link
Collaborator

bkardell commented May 18, 2021

when there is NOT an element with visible focus, the user understanding is that the larger view is the key responder. For example, the Safari viewport scrolls with arrow keys or spacebar.

I think this is the critical one, and the real rub here stems primarily from the fact that div buttons already work inherently different from standard apple-philosophy buttons, but also have no way of working just like windows-philosophy buttons either. Combine this with the fact that there isn't a focus model that describes this hybrid thing either. That is, as @cookiecrook mentioned above, tabIndex values are more windows-like -- there is no way to say "this isn't a mac button, but I want to it work like that in terms of only being keyboard focusable". We've been disussing aspects of this for years, even here the discussions began way way before #42 (comment)

I am (still) pro us making it possible to be clear about this because there is quite obviously no "right" default that works for all cases of what a focusable div might intend to be - it really depends. That said, here are my (personal, representing no one specifically) thoughts:

  • it seemed then (and seems now) like a better solution for that will take some real time given how complex and how much baggage there is around focus.
  • For now, tabindex=0 divs are inherently not mac-button like today and that probably can't change. This seems to lead to a 'worst of both worlds' situation: Since authors can't not show the indicator on those, they just disable the ring for everyone, all the time. We have to be careful that we don't provide a solution that yields the same.
  • The easiest answer here is to say 'focus-visible matches those for keyboard, but not for mouse' but not put it into the UA sheet for mac. This would mean that focus visible doesn't strictly do what it says on the tin so far, but honestly, I think everyone could adjust to that fairly readily I think.
  • Alternatively, a maybe half-baked idea would be to provide an optional argument to the pseudo about which matching behavior it should use and the UA sheet could use that? Or some other easy "mostly" signal that doesn't require changing what actually gets focus?

@robdodson
Copy link
Collaborator

robdodson commented May 18, 2021

The easiest answer here is to say 'focus-visible matches those for keyboard, but not for mouse' but not put it into the UA sheet for mac. This would mean that focus visible doesn't strictly do what it says on the tin so far, but honestly, I think everyone could adjust to that fairly readily I think.

If I understand correctly, this would mean devs would need to do the following in Safari, correct?

div[tabindex]:focus {
  outline: 4px dashed orange; // strong keyboard focus indicator
}

div[tabindex]:focus:not(:focus-visible) {
  outline: none; // hide focus on mouse click
}

@robdodson robdodson reopened this May 18, 2021
@cookiecrook
Copy link
Author

cookiecrook commented May 18, 2021

@bkardell wrote:

tabIndex values are more windows-like

It's no secret that :focus-visible was designed to make it easier for web devs to avoid hiding focus on everything (the main anti-pattern) and instead hide focus only on mouse click (better than hiding all focus, but still problematic as described above)… Many web devs implemented this secondary pattern (using ~mousefocus vs ~keyfocus classnames) because they thought it was the only way.

I wonder if the design of :focus-visible would have been different if the workaround developer pattern had been [pseudocode] on click, (prevent default focus and activation) then (trigger activation behavior)

If that workaround had arisen, would we instead be talking about a new CSS property (maybe user-pointer-focus: none; similar to user-select) rather than a pseudo class (:focus-visible)? Like user-select a user or AT could always override the author-defined user-pointer-focus behavior.

@robdodson
Copy link
Collaborator

If that workaround had arisen, would we instead be talking about a new CSS property (maybe user-pointer-focus: none; similar to user-select) rather than a pseudo class (:focus-visible)? Like user-select a user or AT could always override the author-defined user-pointer-focus behavior.

Would that also be possible with the pseudo class argument that Brian mentioned?

:focus-visible(pointer-focus) {
  // a style to be used if the element received focus from a pointing device
}

Another thing I'm curious about... The original intent of this issue was to point out that Chrome and Firefox's hiding of the focus ring on <button> may break user expectations around what the space bar will do. It seems like the suggestion is that Chrome and Firefox should behave like Safari on macOS and not move focus to <button> when it's mouse clicked because:

mouse click only moves keyboard focus when the element clicked accepts some form of character input (e.g. character value in or typeahead in some other controls like menus and selects)

I totally get why this makes sense, and would not be opposed to changing the behavior in Chrome if other folks on the Chrome team are supportive of it. But I'm a bit confused why this bullet would apply to <button> and not <div tabindex="0">? It seems like a div with a tabindex (and no contenteditable) is akin to a <button> or a <input type=slider>. @cookiecrook would you agree that the div also should not receive focus on mouse click? Is the issue that changing that behavior is just a big can of worms? I understand if that's the case but I wanted to make sure I'm not missing something.

@cookiecrook
Copy link
Author

cookiecrook commented May 19, 2021

maybe user-pointer-focus: none; similar to user-select

Would that also be possible with the pseudo class argument that Brian mentioned?

:focus-visible(pointer-focus) {
  // a style to be used if the element received focus from a pointing device
}

No. My [Disclaimer: unvetted, brainstorm] suggestion of user-pointer-focus: none; (bikeshed name/idea) is that it could prevent mainstream mouse-triggered focus, in the same way user-select: none; prevents mainstream text selection, but still allows it for AT use.

The goal would be to give authors a way to specify that <div role="button" tabindex="0"> behaves like a native <button> does on Mac, where pointer click triggers activation, but doesn't cause the button to acquire keyboard focus.

As you mentioned later, this behavior could also extend to the user agent stylesheets for Firefox and Chrome on Mac, so that they could match the Mac behavior convention. Web authors could also use user-pointer-focus: none; to bypass the need for the "outline: 0" anti-pattern on Windows browsers if they wanted.

@cookiecrook would you agree that the div also should not receive focus on mouse click?

Yes. In order to match the Mac UI convention, a mouse-click on <div role="button" tabindex="0"> should activate it but not focus it, but I don't think the web platform has a method to achieve this yet, other than scripting.

In the case of <div tabindex="0">, leave it up to the author to decide. Potentially throw a console warning for the role ambiguity.

@emilio
Copy link

emilio commented May 19, 2021

We intentionally moved away from the Mac convention in here, fwiw: https://bugzilla.mozilla.org/show_bug.cgi?id=1614658#c15

@robdodson
Copy link
Collaborator

robdodson commented May 19, 2021

Thank you for sharing that thread @emilio, it's a really great discussion!

The gov.uk example in that thread makes a good argument for browsers to move focus to controls that don't receive text input, while also deciding internally to not draw a focus ring.

The reason this seems useful is twofold:

  • It allows the browser to closely match platform conventions—on macOS the browser can choose to not draw a ring on a clicked radio, but on Windows it would draw a ring.
  • With the addition of :focus-visible, it gives developers fine grained control over the experience.

So in the gov.uk case, where they want Windows-like behavior (even on macOS) they could say:

input[type=radio]:focus {
  outline: 2px solid orange; /* All radios get a custom outline, regardless of input device */
}

But if another developer prefers using the macOS behavior on all platforms they could do:

input[type=radio]:focus-visible {
  outline: 2px solid orange; /* Radios only get a custom outline when navigated via keyboard */
}

** Edit **

Bit of a forehead slap moment when I remembered to scroll up and reread James' initial points that doing this also can create user confusion around how the spacebar and arrow keys work. Tricky...

@bkardell
Copy link
Collaborator

I wonder if the design of :focus-visible would have been different if the workaround developer pattern had been [pseudocode] on click, (prevent default focus and activation) then (trigger activation behavior)

If the inputs were different, the outputs might have been different. The web's facilities for dealing with 'focus' are imo kind of a load bearing pile of ages old problematic things that need major investments in improving. Yes, there are lots of things worth exploring. Some don't even require changes to specs. Chrome's simultaneous introduction of a 'Quick Focus Highlight' mode is, I think a great example of an innovation that neatly seems to help a whole lot of things: it is always on top (kind of more like things provided by VO or whatever), it has a dual (consistent) ring which helps it be visible anywhere and it's non-distracting in significant ways without all this baggage.

It isn't possible today to express the thing that mac buttons do. Should it be? Probably yes? Is a solution to that fundamentally necessary to provide before we can resolve on a useful focus-visible - I don't think so. If for no other reason: the current state of things does exist and mountains of content exist today that will be restyled for years to come in pretty much current form. That means, I think, we have to answer what to do with div tabindex=0 in terms of focus-visible. I mean, realistically I think we shouldn't speculate on whether people would use such a thing if it existed.

As I see it, some pragamtic options are:

a) :focus-visible matches that on click on mac and not elsewhere.
b) :focus-visible doesn't match on mac either, but mac doesn't use this in their UA sheet -- we have a little bit of explaining to do, but with 1 more or less line of code, authors can cope easily.
c) We introduce an optional mode for matching, like :focus-visible(platform) which the UA (and authors) can use as well as :focus-visible - the div case matches in one, but not the other.
d) are there others?

It is hard for me to resolve this even in my head tbh. a tabindex=0 div doesn't seem to have a clear parallel.. It is itself is today, even on mac, more windows-like, so it's hard for me to even compare. Since that is all that exists the net result of too many sites just broadly disabling it seems bad/worse than edge cases. My biggest worry really is that a) leaves enough holes (despite our best hopes, divs with tabindexes abound) as to wind up in the same spot.

@robdodson
Copy link
Collaborator

robdodson commented May 20, 2021

My biggest worry really is that a) leaves enough holes (despite our best hopes, divs with tabindexes abound) as to wind up in the same spot.

Yeah this is my concern as well... Ultimately I want to give devs good flexibility to differentiate between mouse and keyboard focus without needing to resort to weird javascript hacks and/or having them nuke focus altogether.

c) We introduce an optional mode for matching, like :focus-visible(platform) which the UA (and authors) can use as well as :focus-visible - the div case matches in one, but not the other.

This is an interesting idea. While I like that option-B gives folks flexibility to differentiate between mouse and keyboard focus, I'm worried that it may lead to webkit bug reports as people will see the default focus ring and assume :focus-visible should match.

I guess you could also do option b while you work out how option c would actually work? 🤷‍♂️

@cookiecrook
Copy link
Author

cookiecrook commented May 21, 2021

Bit of a forehead slap moment when I remembered to scroll up and reread James' initial points that doing this also can create user confusion around how the spacebar and arrow keys work. Tricky...

I think that's the key point that I'm hearing from others inside Apple. We want interoperability, but this (both getting focus on click, and then hiding it) is fundamentally different from the platform experience UI expectation on Mac.

Emilio's link states that Firefox on Mac chose to do this in order to 1) Match Windows/Linux, and 2) Match Chrome on Mac, which itself doesn't match the Mac convention. Now Safari is the only browser on Mac that behaves like most Mac users expect...

@cookiecrook
Copy link
Author

cookiecrook commented May 21, 2021

FWIW, Chrome's settings have other platform-specific focus exceptions in them... Such as:

chrome://settings/appearance "Pressing Tab on a webpage highlights links, as well as form fields" (On means "work more like Safari")

chrome://settings/accessibility "Navigate pages with a text cursor" (On means "work more like Firefox and Windows")

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

No branches or pull requests

4 participants