WICG / spatial-navigation

Directional focus navigation with arrow keys
https://drafts.csswg.org/css-nav-1/
Other
216 stars 38 forks source link

Make things focusable in CSS #25

Closed frivoal closed 5 years ago

frivoal commented 6 years ago

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 commented 6 years ago

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 commented 6 years ago

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

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

hugoholgersson commented 6 years ago

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

bradkemper commented 6 years ago

@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 commented 6 years ago

@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 https://github.com/WICG/spatial-navigation/issues/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:

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

hugoholgersson commented 6 years ago

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 commented 6 years ago

@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 commented 6 years ago

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 commented 6 years ago

@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 commented 6 years ago

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 commented 6 years ago

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:

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 commented 6 years ago

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 commented 6 years ago

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

bkardell commented 6 years ago

I don't think i am, but i can call in

On Thu, Apr 5, 2018, 3:18 AM Florian Rivoal notifications@github.com wrote:

@bkardell https://github.com/bkardell Are you attending the Berlin F2F of the CSS-WG?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/WICG/spatial-navigation/issues/25#issuecomment-378842735, or mute the thread https://github.com/notifications/unsubscribe-auth/AA1IZa-RFvvmICkDZRd3Ux27L1k9FZRwks5tlcU0gaJpZM4SH73N .

frivoal commented 6 years ago

@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 commented 5 years ago

Issue migrated to w3c/csswg-drafts#3379