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

Make things focusable in CSS #25

Closed
frivoal opened this issue Feb 16, 2018 · 16 comments
Closed

Make things focusable in CSS #25

frivoal opened this issue Feb 16, 2018 · 16 comments
Labels
needs:feedback The editors would like feedback from more people before resolving needs:liaison Coordination with another WG/CG/etc needed to be able to close this issue. topic:spec type:enhancement Feature requests

Comments

@frivoal
Copy link
Collaborator

frivoal commented Feb 16, 2018

Other specs (most likely HTML) will probably find it convenient if we define a hook in the "Handling key presses" section to let them define what a particular element does when arrow keys are pressed and that element wants to respond (e.g. the <select> element changing which is the currently selected <option>).

EDIT: The discussion in this issue moved to a completely different, and more interesting topic. Repurposing the issue to talk about that.

@bradkemper
Copy link

bradkemper commented Mar 12, 2018

I’m not sure if this is where you want this comment. But what I’ve been trying to get to in some of my other comments, is a way to specify, in CSS, that an element can be tabbed to or arrowed to (previously imagined as tab-index:0 and arrow-index:0).

Maybe something like focusable: [tab | arrows | none].

I wasn’t clear from the prose whether spacial-navigation: active was supposed to make an element navigable by arrows, or if it was something that applied to an ancestor. But if I was creating a component, like say, something that acted like radio buttons, then I would need to say when something could be tabbed to, and when something could only be arrowed to. So, something like this, I guess:

div.radio-group { spatnav-container: create; }
span.radio-button { focusable: arrows; }
span.radio-button.checked,
span.radio-button:first-child:not(:has(+ .checked)) { focusable: tab; }

(That last line only works declaratively if :has() is usable on the Web. Otherwise, would have to use JavaScript to track when there are no “checked” classes on the buttons, and set a separate class to indicate that on the radio group parent).

Is there some other way to achieve this using the spec properties?

@bradkemper
Copy link

bradkemper commented Mar 12, 2018

Maybe something like focusable: [tab | arrows | none].

Or maybe focusable: [main | secondary | none], to account for keyboardless navigation.

@hugoholgersson
Copy link

@bradkemper it sounds like we had the same idea :) Did you see my comment?

@bradkemper
Copy link

@hugoholgersson I have now. Yes, seems pretty similar.

As someone who has recently been adding keyboard and AT usability to pop up menus, nav dropdown menus, light boxes, etc., my view is that being able to easily control WHICH elements are focusable or not (via CSS) is a more urgent problem than any of the rest.

@frivoal frivoal changed the title Define a hook so that elements can be specified to react to arrow keys Make things focusable in CSS Mar 20, 2018
@frivoal
Copy link
Collaborator Author

frivoal commented Mar 20, 2018

@bradkemper This is not at all what I planned to be doing with this issue, but I wasn't clear, and this is more important topic than the original one :D

I wasn’t clear from the prose whether spacial-navigation: active was supposed to make an element navigable by arrows, or if it was something that applied to an ancestor.

It was meant to be applied to ancestors, so that's a separate thing. (and it's probably going to be dropped or pushed to the next level anyway, see #35)

I’ve been trying to get to in some of my other comments, is a way to specify, in CSS, that an element can be tabbed to or arrowed to (previously imagined as tab-index:0 and arrow-index:0).

Maybe something like focusable: [tab | arrows | none].

This issue has come up before in the CSSWG. I think last time the rough conclusion was that although selectors may be a convenient way to set this up, there was no strong coupling between focusability and style, while there was strong coupling between focusability and semantics (i.e. HTML/DOM) and between focusability and attached behaviors (JS/DOM).

The fact that this isn't about styling isn't a blocker in my mind, but and selectors are a nice mechanism. But the fact that it doesn't seem to be strongly coupled with style does make me question whether it belongs in CSS.

I think it would be very interesting if we could restart that discussion (here or even better in the CSSWG) base on use cases that support:

  • why markup/DOM or a js API isn't the right place for that kind of switch
  • why we need to distinguish between tab focusing vs arrow focusing

Since you've been working on that sort of things, do you think you could write these down?

@hugoholgersson
Copy link

hugoholgersson commented Mar 20, 2018

Do we need to distinguish navigation methods? I doubt authors would like to disable one but not the other...

Perhaps focusable: auto | none is enough to begin with? That should be future-compatible with whatever (spatial) navigation method we come up with next.

@bradkemper
Copy link

@frivoal let me get back to you on that, when I have time to be more complete. Mostly because it would be sooooo much easier and probably more performant to use the CSS engine and CSS rules, rather than complicated fiddling with adding and removing and changing tabindex attributes every time a key is pressed or focus changes. I know I’m near the boundary line at the edge of what CSS is for, but so is the 'resize' property, and so are the other things being discussed. I want to move the line, if needed, to be able to use CSS in this hugely beneficial way.

@hugoholgersson for component-like things, I want to be able to do what native elements do with keyboard control. Which means that when you tab to a radio button, menu, etc., then you can use arrow keys to move focus within it, or tab to exit the component. So, that is two different levels of focusing.

@frivoal
Copy link
Collaborator Author

frivoal commented Mar 21, 2018

I agree there's a fuzzy border, and last time this was discussed in the csswg, I was the one pushing for it, so I'm sort of with you on that one. The questions I listed above are the ones that would help convincing me (and hopefully others) that we're on the correct side of the fuzzy border.

As for "2 levels of focusing" withing native elements, I'm still confused on this one (really, not pretending to be confused just to be polite while disagreeing): is that indeed a form of focusing that needs to respond to some keys but not others for usability's purpose, or is that something else than focusing ("selection"? that word is already used for text selection), somewhat more akin to changing the state of a control than changing which control has the focus? I don't have a good answer, nor a clear idea on how to get to an answer. Help figuring this out (possibly with copious amount of examples) much appreciated.

@bradkemper
Copy link

@frivoal I think it might be a distinction without a difference. The only interactivity difference I can see between changing focus between controls and changing focus (or whatever you’d call it) within a control, is what key you use to do it.

Pragmatically, when building a UI component, '.focus()', ':focus', and '.setAttribute("tab-index", "0|-1") are the tools I use now if I want to follow best keyboard practices for navigating controls like radio buttons, menus, tabs, trees, and the like, where the internal thing has to be focused before it can be changed. I’d have a hard time thinking of that as anything other than focus.

Please see this, if you haven’t already: https://www.w3.org/TR/2017/NOTE-wai-aria-practices-1.1-20171214/#kbd_general_within

@bradkemper
Copy link

That page also talks about aria-activedescendant, which maybe more in line with your alternative view of focus vs. “active” (as they call it there). In that method, the parent has the actual focus, and the descendant that is active gets the focus outline. But I consider that a much more awkward way of managing focus, compared to roving tabindex, especially considering things like radio buttons, which are typically siblings, not descendants of something with focus.

I also don’t know if aria-activedescendant has much support with browsers and/or screen readers, and so is probably not used much. Roving Tab-index is, and provides a good mental model for something like focusable: [main | secondary | none].

@bradkemper
Copy link

Brad’s Screed about Interactivity Being Part of CSS

So, I’d like to say that I am a big fan of separating content from presentation. But a certain amount of interactivity is part of the presentation that the Web designer has to consider when designing. We should embrace that, and not be too hesitant about adding features to CSS that make it easy to add even more interactive control to the Web.

When designing and creating a menu bar, for example, one has to design and create the different states its menus can be in. The easiest and most powerful way is declaratively, using CSS selectors and rules. So, for instance, this is easy:

.menubar > button:not(:hover) ~ .menu { display: none }

It could be argued that this is more about interactivity than presentation. The display: none is not really there to style anything. It, and the selector for this rule, exists entirely to make the menu interactive. In fact, I think it is likely that display:none is used more for interactive behavior than for anything that could be strictly described as stylistic. It is often used in conjunction with :hover and :focus, which are only about interactivity, or with class names added via JavaScript that are only there to show or hide something, not to style it.

But thank God. If these all only existed in JavaScript, and not CSS, life for authors would be far worse off.

Note that display: none also prevents focusing it or its descendants. That’s a side effect now, but an important one that is lacking in, say, opacity:0 or position: absolute; left:-100vw . I want better control of that as a primary effect, without having to hide the element, and without having to resort to JavaScript (other than maybe using JavaScript to add or remove a class, sometimes).

Note that we have a pointer-events property that can enable or disable the clickability of an element in CSS. Why not a property that can similarly enable or disable the focusability of an element, or set the level of focusability? Bring it on, I say.

These aren’t the only examples of CSS being used more for interactivity than for static styling of how it looks:

  • The resize property lets an element become resizable by the user, and there is not even any author control of what that resizing widget looks like or where it is placed. It is purely about enabling interactive behavior.
  • The will-change property is more about performance optimizations than about visual style.
  • overflow:auto|scroll|clip is primarily about enabling or disabling interactivity of user scrolling. It is much more about interacting with the content than of visually styling it.
  • user-select is another behavior-altering property that doesn’t actually change visual style. It enables and disables the ability to select text or other elements on the page. Conceptually, it isn’t so different from my proposed property to enable and disable the ability to focus an element on the page.
  • user-modify, while not on a standards track, is supported by Safari, Chrome, and Edge. It is similar to thecontenteditable html attribute, but somewhat easier to apply declaratively, because: selectors and the cascade. A read-write value does make an element focusable, but it also, you know, makes it writable. And it can’t be used to turn off focusability of things like anchors or text inputs.

Currently, supporting keyboard access by following ARIA recommendations for various component-like HTML constructions is not easy. It involves updating attributes, such as tabindex, on multiple elements at the same time, every time a key is pressed or focus is changed with that construction, based on event handlers that have to be added to those elements. These types of constant DOM updating can cause layout thrashing. It is also easy to sometimes end up with the wrong elements focusable/un-focusable, due to some tricky situations that the author’s code might not account for correctly, such as when the user clicks into another window and the blur event doesn’t have a relatedTarget, then the user clicks back in onto something else that takes the focus.

Also, when arrowing through a component-like thing, you want it to either stop when it gets to the beginning or end, or to wrap around to focus the last or first focusable part. So, a CSS focus-containment property that could be set on a parent or ancestor would make that a lot easier. This would be especially true if the user is using VoiceOver-keys or other means to advance the AT-focus to the next-previous element. In that case, there is no way to detect in JavaScript when the user has left the component, unless/until they advance to something that actually triggers a blur or focus event (using VoiceOver to advance to a paragraph that is non-focusable does not trigger any detectable events, AFAICT). But a focus-containment property could potentially contain that kind of pseudo-focusing too, replicating the way VoiceOver stops advancing when it gets to the last OPTION in a SELECT.

@frivoal
Copy link
Collaborator Author

frivoal commented Mar 28, 2018

I agree with all the above, and will happily repeat similar arguments to any CSSWG member who disagrees.

I still have some doubts that makes we wonder if making things focusable in CSS is the right thing to do or not:

pointer-events or display:none can hide/deactivate things from CSS for clicking / focusing purposes. I haven't though too much about it, but for the reasons you list above, I don't think I would have an issue with a property that can remove focusability from things that have it. However, that's not what you're proposing. You're proposing adding focusability from CSS to things that don't have it.

I am more skeptical about that because I believe that adding focusability alone is generally not useful, and that you typically need to also add some event handler to do something useful when the now focusable element is focused / activated. That will be done in JS, not in CSS. So that makes me think that making things focusable should also be in JS, to avoid things getting out of sync.

For me, it is a matter of separation of concerns in the sense of putting together the things that are tightly coupled together, not in the sense of separating presentation from style.

However, if there is a reasonable use case for making things focusable and then attaching no additional behavior at all via JS, then it seems OK to have it in CSS.

@frivoal frivoal added type:enhancement Feature requests topic:spec needs:feedback The editors would like feedback from more people before resolving needs:liaison Coordination with another WG/CG/etc needed to be able to close this issue. labels Apr 2, 2018
@frivoal
Copy link
Collaborator Author

frivoal commented Apr 5, 2018

@bradkemper Are you attending the Berlin F2F of the CSS-WG?

@bkardell
Copy link
Collaborator

bkardell commented Apr 5, 2018 via email

@frivoal
Copy link
Collaborator Author

frivoal commented Apr 5, 2018

@bkardell Sorry for the noise, I meant to ping @bradkemper since he raised this issue, but your names start by the same letter and I wasn't careful enough with autocomplete.

@frivoal
Copy link
Collaborator Author

frivoal commented Dec 3, 2018

Issue migrated to w3c/csswg-drafts#3379

@frivoal frivoal closed this as completed Dec 3, 2018
@WICG WICG locked and limited conversation to collaborators Dec 3, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
needs:feedback The editors would like feedback from more people before resolving needs:liaison Coordination with another WG/CG/etc needed to be able to close this issue. topic:spec type:enhancement Feature requests
Projects
None yet
Development

No branches or pull requests

4 participants