w3c / csswg-drafts

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

[css-display-4] Define how reading-flow interacts with focusable display: contents elements. #9230

Open emilio opened 1 year ago

emilio commented 1 year ago

https://github.com/w3c/csswg-drafts/issues/8589 / https://github.com/w3c/csswg-drafts/issues/7387#issuecomment-1640556638 propose new properties to alter the reading order of the items to follow the layout tree order, rather than the dom order.

However, that is in conflict with https://github.com/w3c/csswg-drafts/issues/2632 / https://github.com/mozilla/standards-positions/issues/772, in the sense that there doesn't seem to be a good order for display: contents elements that are focusable in a visually-order container.

We need to sort out how these two proposals interact. What is the tab order of a display: contents element inside an element with non-auto reading-order?

cc @rachelandrew @tabatkins @fantasai @dbaron

mfreed7 commented 5 months ago

I agree this is an issue. We (really @dizhang168) are in the process of trying to prototype an implementation of reading-order-items, and this case came up. For example:

<div style="display:flex; reading-order-items: flex-visual">
  <div style="order:2">Flex item
    <button>B</button>
    <button>C</button>
  </div>
  <div style="display:contents" tabindex=0> Problem here
    <div style="order:3">Flex item <button>D</button></div>
    <div style="order:1">Flex item <button>A</button></div>
  </div>
</div>

In this example, the sequential focus order should be A, B, C, D. There's no well defined "place" to put the display:contents div, since a) it isn't a flex item that can be ordered according to the flex visual order, and b) it can wrap flex items that aren't even contiguous. There's a similar (and slightly more complicated) case for <slot>s within a flex container like this.

I propose these display:contents elements within a reading-order-items container should simply be declared non-focusable entirely. Unless there's a compelling use case for doing that?

The case for <slot> gets more complicated, since a <slot> forms a focus navigation scope which must be traversed in its entirety before returning to the owning scope. We think we have a solution for that, maybe, but that's likely a good candidate for another issue. But it'd be simplified, here, by saying <slot> (which is display:contents by default) cannot itself be focusable within a reading-order-items container.

rachelandrew commented 5 months ago

I think that makes sense, if you have used display: contents I don't see why you would also want to include it in the order. I'd be interested if anyone can think up an example of needing to do so.

emilio commented 5 months ago

A fieldset with display: contents and the form controls reordered inside or so, perhaps?

mfreed7 commented 5 months ago

A fieldset with display: contents and the form controls reordered inside or so, perhaps?

That's a good use case generally, but I don't think (?) you'd want to be able to focus the fieldset itself in that example, would you?

dizhang168 commented 5 months ago

On this topic, here are a few more tricky cases where having display: contents on a flex item causes unclear reading order.

What should be the reading order if reading order items are defined inside a slot (has display: contents) and cross navigation scopes?

<!DOCTYPE html>
<meta charset="utf-8">
<div>
<template shadowrootmode="open" shadowrootdelegatesfocus>
<style>
.wrapper {
display: flex;
reading-order-items: flex-visual;
}
</style>
<div class=wrapper>
<button id="A" style="order: 2">Item A</button>
<slot></slot>
<button id="C" style="order: 4">Item C</button>
</div>
</template>
<button id="B1" style="order: 1">Slotted B1</button>
<button id="B2" style="order: 3">Slotted B2</button>
</div>

Which will render to: image Source order: A,B1,B2,C Visual order: B1,A,B2,C

Given the flattened tabindex-ordered focus navigation scope, step 2.2, we should visit all elements within a scope together (so B1,B2 together). However, that is visually the wrong order.

What should be the reading order if reading order items are defined inside a display: contents shadow root and cross navigation scopes?

<!DOCTYPE html>
<meta charset="utf-8">
<style>
 .wrapper {
   display: flex;
   reading-order-items: flex-visual;
 }
 </style>
<div class=wrapper>
 <div style="display: contents" id="root">
   <template shadowrootmode=open>
     <slot></slot>
   </template>
   <button id="A2" style="order: 2">A</button>
   <button id="B2" style="order: 1">B</button>
 </div>
 <button id="C" style="order: 3">C</button>
</div>

Which will render to image Source order: A,B,C Visual order: B,A,C

Here, we have a DIV that is:

A reading order item is defined using layout information. And in this case, this DIV is invisible to the layout object. Should the DIV qualify as a reading order item? My thinking is yes or else we wouldn't be able to visit its content.

dizhang168 commented 4 months ago

For more context on the points raised above about display: contents and slots, please refer to our HTML standards proposal. It has a suggested algorithm, visual examples and more details in the open questions about this specific problem. https://github.com/whatwg/html/issues/10407

dizhang168 commented 4 months ago

To summarize, the questions are:

  1. Should a display: contents (with tabindex=0) be considered a reading order item?
  2. Should a display: contents’ children be considered reading order items?
  3. HTML standard expect to traverse within focus scopes, where a focus scope owner can be a shadow host, a slot, a document, etc. This conflicts with reading order, where we are depending on a flattened tree traversal and display: contents/slots don’t matter.

Potential resolutions:

  1. Make display: contents elements not reading order focusable.
  2. Make display: contents children not reading order focusable (fallback to using source order).
  3. Tell users to avoid display: contents for reading order.
  4. Or other suggestions and considerations?
css-meeting-bot commented 4 months ago

The CSS Working Group just discussed [css-display-4] Define how reading-order / reading-order-items interact with focusable display: contents elements., and agreed to the following:

The full IRC log of that discussion <bramus> rachelandrew: issue around how our new reading-flow property interacts with focusable display: contents elements
<bramus> … got input from mason and di in the issue
<bramus> … question is from di at the bottom
<bramus> … should a display: contents with ?? be considered reading order items?
<bramus> … di also suggested that display: contents elements really arent focusable
<bramus> … can make it so that display: contents children are not reading order focusable
<bramus> … would love to hear thoughts
<bramus> dbaron: there are a bunch of complicated issues here
<bramus> … because on the one hand weve gotten feedback from a11y folks tha focusability and ?? should match each other
<bramus> … you shouldnt be able to do sth that takes an item out of fcous order but not the a11y tree
<bramus> … things like that
<astearns> s/??/reading order/
<bramus> … when you are saying that reading order should depend on box order it doesnt make sense to go through a thing that doenst generate boxes
<iank_> q+
<bramus> … easy way out is to say that if you are using one of the readingflow values that depend on box order that elements with display: contents are not part of that order, ie not focusable
<bramus> … not ideal from a11y POV i think
<bramus> … I have an almost finished project to make elements with display: contents focusable but hasnt happened yet
<bramus> … pulling that back would be a partial reverse of the change to make display: contents focusable
<bramus> … alt is to come up with some rule that says where it goes in the order
<bramus> … not hard to make that rule, might be hard to impl
<bramus> … doing the right thing for a11y vs doing a thing that is implementable/describable
<bramus> astearns: is your change that the element with display: contents is focusable or that its children are focusable?
<bramus> dbaron: the element
<astearns> ack iank_
<iank_> ```
<iank_> <div style="display: contents;">
<iank_> <div>1</div>
<iank_> <div style="order: 5;">2</div>
<iank_> </div>
<iank_> <div>3</div>
<iank_> ```
<bramus> iank_: there’s a case that i pasted here in irc
<bramus> … with the order prop and grid/flex reordering things you can pull items bc display: contents doestn have a box you can pull out of the display: contents and the iteration order doesnt become clear
<bramus> … in this case here, the order would be 1 3 2
<bramus> but display: contents is wrapping 1 and 2
<bramus> … so maybe we shouldnt consider display: contents
<bramus> … there might be other solutions
<astearns> ack fantasai
<bramus> fantasai: def an awkward situation. if author asks for it to be focusable then we should try to
<bramus> … would mean to figure out a place to put it in the order
<bramus> … before any other items it contains would make sense
<bramus> … even if they are split across multiple places
<florian> q+
<bramus> dbaron: to poke some holes into that
<bramus> … 2 edge cases
<bramus> … 1 of them is the item has no children at all and therefore ther eis no box at all
<bramus> … other thing is that child is also display: contents
<bramus> … no children at all is messy
<bramus> … other thing leads to recursion
<bramus> fantasai: no contents: if we were reordering all the items and ?? between prev and next siblings
<bramus> … if we reorder those then we could give up and shove it up the end
<bramus> … not sure what authors would expect
<bramus> … between the two makes sens
<astearns> ack florian
<bramus> … we might fix either attach to the prev or attach to the next as a sort of option so that at least when they are together it lands in the middle
<bkardell_> s/sens/sense
<bramus> florian: can i suggest to go the opposite route and say that display: contents does not apply to focusable elements?
<bramus> fantasai: interesting
<bramus> TabAtkins: that would break specs though … the TOC in it for example
<bramus> florian: but does it need to be focusable?
<bramus> TabAtkins: you can tab into the children spans
<bramus> fantasai: ????
<bramus> TabAtkins: if you prevent focusable elements from becoming display: contents then it would break ?????
<bramus> florian: but the a is
<bramus> TabAtkins: this is a focusable <a>
<bkardell_> q+
<bramus> … the fact that its used in a TOC for spec suggests that ???
<bramus> kbabbitt: is it actually focusable?
<astearns> s/kbabbitt/bkardell_/
<bramus> TabAtkins: it does not. what lforian said is to prevent focusable elements from becoming display: contents
<bramus> bkardell_: a is focusable if it has an href
<bramus> TabAtkins: it does, wouldnt use a otherwise
<bramus> florian: you mean that every entry in it is an a?
<bramus> TabAtkins: yes, but i am positioning in the grid the contents of it
<astearns> ack bkardell_
<bramus> florian: to keep pushing … tab’s case is an important point but its a subset
<bramus> … if we had ::contents the bit that needs to be focusable is that
<bramus> … you dont have element with a bunch of children that might or not be focusable
<bramus> … you want to layout the ::before and ::after
<bramus> … the part that is focusable is everything except those
<bramus> … seems a subcase of I have a focusable element with stuff underneath
<bramus> … seems that this case is less ? than the whole problem space
<bramus> TabAtkins: was using this as an example to counter your request
<bramus> florian: yes, but I think its a subcase
<emilio> I think this is a huge tangent, I don't think we should make display: contents not work like that
<bramus> TabAtkins: correct solution here is to use subgrid here. there are other solutions here
<emilio> We either do what we do now (display: contents makes stuff not focusable), or make display: contents focusable and deal with it
<bramus> astearns: given that we cant change other behaviors, what should we do here?
<bramus> florian: for this case: kind of has an obv answer.
<astearns> s/that/the likelihood that/
<bramus> … it is effectively everything except before and after that remains focusable
<bkardell_> q+ for miriam
<bkardell_> q+ miriam
<bkardell_> q-
<emilio> q+
<bramus> … which I think is different from situation where you have a bunch of child elements and then you cant place those
<bramus> rachelandrew: I feel like if in the situation where the author has asked to make it focusable then we have to honor that
<bramus> … the default propably is that its not focusable
<bramus> … its a visual hting we are doing with reading-flow
<bramus> … general use case gonna be that ???
<bramus> … if people asked to make the box focusable then we need to consider some of elika’s suggestions
<bramus> florian: or go back to my other suggestion. if you set tabindex on display: contents then you cant
<lwarlow> q+
<bramus> s/if you set tabindex on display: contents then you cant/if you set tabindex on then display: contents does not apply
<florian> q+
<astearns> ack miriam
<bramus> miriam: currently a11y experts have said us not to use display: contents bc browser bugs and regressions
<bramus> … not reliable to use display: contents on anything that needs semantics
<astearns> ack emilio
<bramus> … sara soueidan recently mentioned it again at css day
<bramus> emilio: we should stop discussion making display: contents not work on focusable things
<bramus> … i think it would be super confusing to do
<bramus> … can decied that display: contents elems are not focusable
<bramus> … not a big deal i think, but opinions
<astearns> q+
<bramus> … or can deal with reading order ??
<florian> q-
<bramus> … cant overfocus on one case specifically (e.g. tabs example)
<astearns> ack dbaron
<bramus> dbaron: rachel suggested to (IUC) sort of make setting tabindex be a stronger indication of focusability that would override some other things that make it non focusable
<bramus> … this scares me bc the rules are already very complicated
<bramus> … an overriding layer seems like a huge mess
<astearns> ack lwarlow
<bramus> lwarlow: i dont fully understand the problem
<bramus> … display: contents is used a lot with shadow dom
<bramus> … largely due to other issues with shadow root
<bramus> … suggestion of making the children of display: contents dont work with reading order feels strange
<bramus> … my intuition would be to ignore display: contents and treat it as if those children were where that display: contents element is
<bramus> … ??? even if source order doesnt match that
<bramus> … so making display: contents focusable here seems like wrong thing
<bramus> emilio: I thought idea was to make display: contents element not focusable / reachable by tab
<bramus> … but maybe I misunderstood
<bramus> dbaron: thats what i was thinking at least
<bramus> … agreeing with emilio here
<florian> q?
<bramus> emilio: so basically it would work but we wouldnt be able to ??? an element that would be ??? if you are reading visual order
<emilio> s/???/reach by tab/
<bramus> rachelandrew: i think that was the orig thinking. to not focus an element if you were doing that
<emilio> s/???/display: contents/
<florian> q?
<florian> q+
<bramus> … its whether that causes a problem here if we have unfocusable display: contents elems
<bramus> astearns: i think im confused
<bramus> … suggestion to do a copout but to have a principle that what we do with reading=flow and display: contents should be same as what we do with focusabilyt and display: contents
<astearns> ack astearns
<bramus> … not sure if that is actually desirable given the last few comments
<astearns> ack fantasai
<florian> q-
<bramus> fantasai: would be unexpected if lets say you have flexbox and use display: contents on some child and on some other item you set order: -1 and then you set reading-flow
<bramus> … even if you didnt do any reordering, the display: contents elem in the middle would disappear from the tab order
<bramus> … would be unexpected
<bramus> … and probably not notice dby many, so probably shouldnt do
<emilio> q+
<florian> q+
<bramus> … elems should remain focusable
<bramus> … best to put it before the first item that uses it
<bramus> … best place if it had no children attach to element before or after or both if ????
<bramus> … if youve to a working layout without reading order then it shouldnt break
<astearns> ack emilio
<bramus> emilio: slight counterpiont: if you make display: contents elem focusable. any visual feedback … you would already need to be careful with its styles, e.g. a link with an outline … youd have to style descendant or something
<bramus> … less concerned about authors accidentally removing it from tab order
<lwarlow> q+
<bramus> … its unfortunate but its a can of worms
<miriam> browser issues documented: https://adrianroselli.com/2022/07/its-mid-2022-and-browsers-mostly-safari-still-break-accessibility-via-display-properties.html
<bramus> … personal preference to make display: contents not focusable
<bramus> … but i get it
<astearns> ack florian
<miriam> and current state noted on caniuse: https://caniuse.com/css-display-contents
<bramus> florian: maybe thats just me, but i think we are talking in the abstract and maybe therefore cant find the right thing to do. need usecases and think on the basis of what people are actually doing with display: contents
<miriam> seems buttons are the primary remaining issue in most browsers
<bramus> … we are going in circles i thikn
<bramus> fantasai: if its focusabl ein the middle of the list wihtout reading order items and then applying it makes it no longer focusable … seems wrong
<bramus> florian: i agree in principle but we should know what people are doing with it
<bramus> … we know of tabs cases here but what everyone is doing here
<bramus> fantasai: ???
<emilio> q++
<emilio> q- +
<emilio> q+
<bramus> florian: agree. just confused by combinatin of statement by a11y people saying dont do it and us doing ???
<bramus> fantasai: (missed)
<fantasai> s/???/if I have a flexbox and it contains an item with 'display: contents' that's focusable and it is reachable now, and all I do is flip reading-flow on the flexbox, that *should not change the focusability of its children*/
<bramus> astearns: this is getting heated … emilio wanted to reply?
<astearns> ack emilio
<bramus> emilio: swithcing reading order wihtout display: contents can change to top order with shadow dom in various ways
<astearns> s/heated/more heated than it needs to be/
<bramus> … maybe that expectation is already broken? bc of how shadow dom tab scoping order works
<bramus> fantasai: there is a difference in changing the order making it not tabbable
<bramus> emilio: thats fair
<bramus> lwarlow: 100% agree with elika
<bramus> … cant change unrelated element and then suddenly make it no longer focusable
<florian> s/us doing ???/us figuring out what happens if you do it, without considering why people are doing it
<bramus> … changing tab order is what you expect
<bramus> … not focusable is not
<emilio> q-
<bramus> … not durable
<astearns> ackl lwarlow
<emilio> ack lwarlow
<bramus> … important to understand use cases, but tangent to this problem
<astearns> s/durable/doable/
<bramus> … you may not even know if you have a display: contents child
<bramus> … it should still be focusable
<bramus> … if you are using a web component from somewhere else, you have no control over it
<bramus> … i dont think we can make it suddenly not work
<bramus> … also "don’t use display: contents"
<TabAtkins> in retrospect it's kinda a fundamentally bad idea, tbf
<bramus> … reason for that is that its historically broken in browsers, not that its a bad idea
<florian> q+
<chrishtr> q+
<bramus> … cant disregard whole usecase because historical issues
<miriam> [nods]
<bramus> astearns: can maybe resolve on that reading flow should have no effect on focusability
<astearns> ack dbaron
<florian> q- later
<bramus> dbaron: regarding fantasai’s example: example 1st and 2nd time was slightly different
<bramus> …the 1st time it was setting order, 2nd time reading-flow
<fantasai> 1st example: flexbox containing e.g. 5 items, with 3rd item `display: contents` element, and last item with `order: -1`
<bramus> … what i was suggesting for if we need a condition for when these things might not be focusable, it would be only for use of reading-flow not order, rather than both
<fantasai> 2nd example: flexbox containing an item with `display: contents` and no use of reordering
<bramus> … there is a distinction between both
<florian> qq+
<bramus> … other thing: what luke already said: i think what we are trying to do here is fix the reasons why a11y folks are saying not to use this stuff
<florian> q-
<bramus> … bc people have use cases. only thing is that a11y folks say its currently broken
<bramus> chrishtr: concrete example from mason (2nd comment int he issue) display: contents elme with tabindex with 2 children
<bramus> … difficulty stems from conflict of values of order and tabindex of parent
<bramus> … not sure why this problem is specific to display: contents
<bramus> … wouldnt a parent with tabindex and order children cause problems even if parent was not display: contents
<bramus> lwarlow: order property woulnd taffect thme
<bramus> chrishtr: only ????
<bramus> lwarlow: thats my understanding
<bramus> dbaron: issue with masons thing is that ?? is reordering its grandchildren because it has display: contents
<bramus> chrishtr: could we resolve by causing display: contents to act like some kind of order affecting stacking content group (?)
<kizu> q+
<bramus> … could have a display: contents cause a flex item children to all have continous ordering
<astearns> ack chrishtr
<bramus> dbaron: thats probably not a compat problem I guess
<bramus> iank_: doesnt work for grid bc you can place grid items in any row/col
<dbaron> s/not a/a/
<bramus> chrishtr: do you have an exmaple?
<bramus> TabAtkins: notion of keeping them together as a group. in grid each item is individually placed
<bramus> chrishtr: but you can specify order on grid children, right?
<florian> q+
<bkardell_> s/exmaple/example
<bramus> … suggestion to reinterpret order for children of display: contents elements
<bramus> TabAtkins: nesting their order?
<bramus> chrishtr: yes
<bramus> iank_: would be surprising to authors
<bramus> … bc it wouldnt read in that order anymore
<bramus> astearns: i think we are going to have to wrap up
<astearns> ack florian
<bramus> florian: unless i misunderstood, chris has an interesting thing to focusalbe children of a display: contents elem
<bramus> … IUC thats not what your proposal adddresses
<bramus> … can be intersting, but doesnt solve this problem
<bramus> chrishtr: maybe I misunderstood mason’s example
<bramus> dbaron: I think its not that you have to go in and out, but its not clear where to put the parent in the tab order
<bramus> kizu: from a11y POV this case is violation. you cant have interactive elements nested inside other interactive ones
<bramus> … for when display: contents we should use focsable
<bramus> … maybe we can split focusable area into multiple ones?
<bramus> … if we have button with some interactiveelement inside, we split all the text parts around it into two ??? and then split
<florian> +1 to kizu
<bramus> … this way whatever we do, order would be logical from author POV
<bramus> … focus button, then text, then ???, then 2nd textnode
<astearns> ack kizu
<bramus> … when we consider all consecutive non interactive parts of display: contents as separate focusable areas we can mix with other interactive elements inside
<bramus> … with this solution wec an solve reading order and bigger issue with nested elements
<astearns> ack dbaron
<bramus> dbaron: my concern with that is that focus state is something that is in the DOM
<bramus> … given that focus is a thing associated with an element, its not clear how you make clear that an item appears 2 times int he tabbing order
<bramus> kizu: i think it would work, same as when you click
<bramus> … ???
<florian> q+
<astearns> zakim, close queue
<Zakim> ok, astearns, the speaker queue is closed
<bramus> … authors dont want to know which part you clicked, only that you clicked the element
<bramus> … order of things … focus on the text, then inner, then parent again
<bramus> … could be confusing for authors but preserves a11y
<dbaron> (I disagree, but I should probably let other people talk.)
<astearns> ack chrishtr
<kizu> I will comment in the issue
<bramus> chrishtr: 2 points: would be super helpful if you could write that down explicitly
<bramus> … and then walking through that in detail would be helpful when we come back to this issues
<bramus> … if this is an anti-pattern then we need a good thing for readers to get to the content eventually
<astearns> ack florian
<bramus> … would love to learn more too about why this is an anti-pattern
<bramus> florian: I like kizu’s suggestion
<bramus> … html spec distinguishes focusable element vs focusable area
<bkardell_> q+
<bramus> … the area can be an elemenent or part of an element
<bramus> … so there is already a notion of this in the HTML spec
<bramus> … should explore kizu’s idea
<bramus> bkardell_: want to warn about confalting interactive element with tabindex
<bramus> … should be careful about that
<bramus> astearns: so we should take it back to the issue?
<bramus> rachelandrew: so we all believe that ?? should be focusable?
<bramus> florian: maybe can resolve on regardless of what and how that reading-flow doesnt change that
<bramus> fantasai: thats what rachel is syaing
<fantasai> s/??/items with `display: contents`
<bkardell_> s/… should be careful about that/They aren't really interchangeable. There are complex interactive elements that do nest tab indexes and that's expected.
<bramus> florian: i think we are saying the same thing, but wanted to express that in a way we dont block romans thing
<bramus> bkardell_: can agree … and can also agree to make display: contents eventually focusable
<bramus> astearns: but thats a separate issue
<bramus> … shadow dom and at least a bunch of other things
<emilio> reading flow should not make elements not reachable in the tab order or something?
<bramus> … eg fragmentation, formatting context, …
<bramus> … would like to scope this to only effect of reading-flow
<bramus> chrishtr: did we prev resolve to make display: contents focusable?
<fantasai> PROPOSED: reading-flow does not affect whether an element with `display: contents` is focusable
<bramus> dbaron: dont remember off the top of my head
<lwarlow> +1
<bramus> astearns: we have proposed resolution
<dbaron> dbaron: ... which discussions were in CSS and which were in WHATWG
<bramus> … maybe that is too specific?
<bramus> … maybe “reading-flow does not affect whether an element is focusable”
<fantasai> PROPOSED: reading-flow does not affect whether an element is focusable
<bramus> florian: both work for me
<lwarlow> +1
<fantasai> +1
<bramus> astearns: objections?
<bramus> RESOLVED: reading-flow does not affect whether an element is focusable
<bramus> astearns: please keep commenting on the issue and put real world examples
<bramus> … will come back to this later
<fantasai> scribenick: fantasai
dbaron commented 4 months ago

To be clear, we didn't finish the discussion here, the resolution above is a partial conclusion that reduces the space of conclusions we could reach here.

kizu commented 4 months ago

In the meeting I said that I will comment in this issue expanding a bit more on my proposal and the nested interactive elements issues.

  1. If an element has display: contents, but is not focusable, then there are no issues, and its content should participate in the flow as usual, being affected by reading-flow etc.
  2. Otherwise, if an element has both display: contents and is focusable, but does not have any other focusable elements inside, this element's content becomes one focusable area. Example: https://codepen.io/kizu/pen/rNgYzVW — currently, only Chrome allows us to focus this link, Firefox and Safari both ignore it, which is bad.
  3. If an element that has both display: contents and is focusable has one or more other focusable elements inside, my proposal is to split the non-focusable areas (excluding whitespace text nodes) inside that element, making them distinct parts that participate in the tab order in the same way they participate in the reading-flow.

    By “Areas” I mean consecutive elements and text nodes. If there are no valid areas other than the nested focusable element, we first see if there is one with the whitespace and use it, otherwise we need to create an empty area at the beginning of that element and treat it as an absolutely positioned element in a static flow.

    Example of the current state for this: https://codepen.io/kizu/pen/gOJXxgy — inner element can be focused by all browsers, but the parent with display: contents is only accessible as a single area in Chrome, while Safari and Firefox ignore it.

The third case is the most complicated, but it is also a case which is already considered a bad practice: ideally, authors must not nest interactive/focusable elements inside each other. Some references for this:

Articles by @aardrian related to this:

A nested-interactive rule in axe related to this:

While this is a bad practice, we need to guarantee that the users would still be able to access the content in at least some way.

chrishtr commented 4 months ago

Thanks for the summary! I have a couple of questions.

  • Otherwise, if an element has both display: contents and is focusable, but does not have any other focusable elements inside, this element's content becomes one focusable area. Example: https://codepen.io/kizu/pen/rNgYzVW — currently, only Chrome allows us to focus this link, Firefox and Safari both ignore it, which is bad.

Note: this is only with the --experimental-web-platform-features flag turned on, which enables the DisplayContentsFocusable feature @dbaron is working on.

  • If an element that has both display: contents and is focusable has one or more other focusable elements inside, my proposal is to split the non-focusable areas (excluding whitespace text nodes) inside that element, making them distinct parts that participate in the tab order in the same way they participate in the reading-flow.

By "split" do you mean to find each consecutive subsequence of children and text nodes that are not focusable, and treat them as one focusable group? e.g. for the case of <div style="display:contents"><div>One</div><div tabindex=0>Two</div>Three</div> it'd have three items that participate in the tab order, which would be visually indicated by the bounding rectangle of "One", "Two", and "Three"?

Also, how should we determine the order of them? should all of these dynamically split items be focus-ordered as if they had the same tabindex as the display:contents parent?

By “Areas” I mean consecutive elements and text nodes. If there are no valid areas other than the nested focusable element, we first see if there is one with the whitespace and use it, otherwise we need to create an empty area at the beginning of that element and treat it as an absolutely positioned element in a static flow.

What do you mean by "with the whitespace"?

Also, why "treat it as an absolutely positioned element"?

Example of the current state for this: https://codepen.io/kizu/pen/gOJXxgy — inner element can be focused by all browsers, but the parent with display: contents is only accessible as a single area in Chrome, while Safari and Firefox ignore it.

(note: also only with the Chromium flag I mentioned above)

kizu commented 4 months ago

Thanks for the notes! Indeed, I tested in the Canary with the flag turned on.

By "split" do you mean to find each consecutive subsequence of children and text nodes that are not focusable, and treat them as one focusable group? e.g. for the case of <div style="display:contents"><div>One</div><div tabindex=0>Two</div>Three</div> it'd have three items that participate in the tab order, which would be visually indicated by the bounding rectangle of "One", "Two", and "Three"?

Yes, this is correct. It is questionable how those should be exposed to the accessibility tree (I don't know what is the best answer: should we announce those with all the element's content? Only the “area”? Something else?), but from a user's perspective those could look like separate entities, and a user can expect to tab through them separately (but that's subjective, and different users could expect different things; but I don't think we need to have a control over this, given we are covering a misuse case).

Also, how should we determine the order of them? should all of these dynamically split items be focus-ordered as if they had the same tabindex as the display:contents parent?

Yes, if there is a tabindex present on an element with display: contents, all its “areas” should inherit it, but the other focusable elements inside should not (as it works now with the regular nested interactive elements: the parent with tabindex is separate, the children are kept in the normal tabindex order). If there is not tabindex, then the tabbing order should follow the reading order (so, could also be controlled by reading-flow).

What do you mean by "with the whitespace"?

<a>
    <span tabindex="0"></span>
</a>

In the above code, there are two text nodes containing only whitespace: between <a> and <span and between </span> and </a>. I imagine that for a browser it would be easier to use one of those nodes as the focusable area.

Also, why "treat it as an absolutely positioned element"?

This is only for a case like <a><span tabindex="0"></span></a> — there are no text nodes between the tags, but, ideally, we'd need to have something that could represent the focus state, ideally with a focus ring over it. As it is not a real element, we need to somehow position it, and given the flow can be anything, the least intrusive way to treat it could be to use the same “placeholder” absolutely positioned elements have in their “static” position. But maybe there are other, better, ways to handle this.

dizhang168 commented 4 months ago

Hi @kizu! So, if I understand correctly, you are saying the behavior with feature DisplayContentsFocusable on in Chrome is what you expect.

If we look at the problem Mason shared:

<div style="display:flex; reading-order-items: flex-visual">
  <div style="display:contents" tabindex=0> Problem here
    <div style="order:3">Flex item <button>D</button></div>
    <div style="order:1">Flex item <button>A</button></div>
  </div>
</div>

Are you saying the order should be display: contents -> A -> D? Or should we be splitting it further into smaller focusable areas?

Yes, if there is a tabindex present on an element with display: contents, all its “areas” should inherit it, but the other focusable elements inside should not (as it works now with the regular nested interactive elements: the parent with tabindex is separate, the children are kept in the normal tabindex order). If there is not tabindex, then the tabbing order should follow the reading order (so, could also be controlled by reading-flow).

Could you give an example for this? Given a display contents DIV, you propose splitting it into multiple focusable areas and let them all have the same tabindex. Does it mean this DIV will get focused multiple times instead of just once during keyboard navigation? I feel like that might not be intuitive to the web users.

Also, would love your input on how this proposal would work with the changes I am proposing at https://github.com/whatwg/html/issues/10407. Thanks!

Side note, I have written and landed some tentative WPT tests for reading-flow here. Maybe this can help visualize different cases.

dizhang168 commented 3 months ago

I have done more research and thinking about this open question. We came up with two main options on how to handle it.

We also recommend visiting all display: contents elements after the sorted reading flow items.

We wrote out the HTML spec changes necessary and illustrated the approach with examples at https://github.com/whatwg/html/issues/10533.

@rachelandrew has also posted a blog post detailing the problem.

We recommend developers to give us feedback here or on the whatwg issue :)

css-meeting-bot commented 1 month ago

The CSS Working Group just discussed [css-display-4] Define how reading-flow interacts with focusable display: contents elements., and agreed to the following:

The full IRC log of that discussion <TabAtkins> Di: so i'm gonna focus on the proposal of how to implement css reading-flow
<TabAtkins> Di: I'm the Blink engineer working on this new property
<TabAtkins> Di: quick summary, the reading-flow property is in Display 4 draft
<TabAtkins> Di: This redefines the navigation order when the user presses Tab, and similar for a11y tree
<TabAtkins> Di: currently only works on display:grid and flex elements
<TabAtkins> Di: but with other proposals that touch on display orderring, like Masonry, it'll get bigger
<TabAtkins> Di: This is valuable because it helps authors choose the right reading order for their users, when it doesn't match the dom order
<Di> https://rachelandrew.github.io/reading-order-items-examples/
<TabAtkins> Di: rachel has a video showing how unintuitive the current dom-based order can be and how this property can fix
<TabAtkins> Di: I want to talk about the impl of the feature, and some of the edge cases, like display:content or abspos/fixpos
<TabAtkins> Di: the goal here is to get more feedback on the HTML PR
<Di> https://github.com/whatwg/html/pull/10613
<TabAtkins> Di: any questions to start? otherwise i'll go into details
<masonf> q?
<TabAtkins> ack zcorpan
<TabAtkins> Di: the current impl defines reading-flow relative ot eh "reading flow scope owner"
<TabAtkins> Di: it's either a container with a 'reading-flow' value, or a display:contents whose parent is a reading-flow container
<zcorpan> s/ot eh/to the/
<rachelandrew> we moved examples to https://chrome.dev/reading-flow-examples/ where there are a couple more, and there's a short video on the TPAC site https://www.w3.org/2024/09/TPAC/demo-css.html
<TabAtkins> Di: Within this, the order isn't normal dom order, it shoudl use the container's layout to sort the elements according to the reading-flow value
<TabAtkins> Di: Like it could be grid-rows or grid-columns
<TabAtkins> Di: some items are not sorted by the layout, like elements that are abspos
<TabAtkins> Di: in that case, they're visited after the ones that are sorted, in normal dom tree order
<TabAtkins> domfarolino: the ones that aren't aprticipating in reading flow, are they traversed in dom order, or still based on normal tab index from outside reading flow?
<TabAtkins> Di: tabindex takes priority over reading flow
<TabAtkins> Di: so we'll sort the elements and get a "next" element, so within a tabindex value we can cycle between elements with the correct sorting
<kizu> q+
<zcorpan> q+
<astearns> ack kizu
<TabAtkins> kizu: so when we deffine inheritancce for scope, when you focus an element inside the scope, can you escape? do you always first go thru all elements in the scope before moving outwards, or can you mix and match?
<TabAtkins> Di: no mixing, within a scope you visit all the elements first
<TabAtkins> kizu: I think that's okay, but we might need an extra value like reading-flow:contain, otherwise people will establish scopes just for the scoping behavior
<TabAtkins> TabAtkins: I think there's some confusion, you always visit all the focusable elements in a given element anyway.
<astearns> some discussion of scopes, tab index and other things not minutes
<TabAtkins> [will fill in later]
<TabAtkins> zcorpan: question on the general need for this property
<past> ack zcorpan
<TabAtkins> zcorpan: the preivous sense of the csswg is people should use the dom order for correct reaading order
<TabAtkins> zcorpan: what changed? do we have more layout mechanism now, different layouts on different devices, etc? just inconvenient to reorder the dom
<TabAtkins> rachelandrew: we've got tons of dev feedback on the preivous issues
<TabAtkins> rachelandrew: loads of usecases where devs ask for this
<TabAtkins> rachelandrew: simple is you have a layout with grid where the ideal layout in mobile vs layout presents things in a differnet visual order
<TabAtkins> rachelandrew: we give people the ability to rearrang ethings with grid, then basically say don't do it because it causes this problem
<TabAtkins> rachelandrew: I'll link in threads later
<lea> +1 to rachelandrew, this is a very common pain point
<TabAtkins> rachelandrew: But pretty mcuh every workshop i've done someone has said "i want to do this, but you said I can't"
<astearns> resolution to work on this: https://github.com/w3c/csswg-drafts/issues/7387#issuecomment-1690281298
<TabAtkins> Di: So the author issues is talking more about display:contents, it's all related tho for focus scope navigation
<zcorpan> q+
<TabAtkins> annevk: wonder why you decided tab index should win in the end?
<TabAtkins> TabAtkins: is that asked with the understanding about focus groups, which scope the tabindex behavior?
<TabAtkins> annevk: there's a scoping aspect, but there's also an element-by-element feature
<TabAtkins> annevk: we invented the css feature to win out, but then HTML wins
<rachelandrew> lots of cases in this issue https://github.com/w3c/csswg-drafts/issues/7387
<TabAtkins> masonf: our general feeling is using this feature in conjunction with tabindex would be a mistake, but we still have to define what happens
<TabAtkins> annevk: one thing you could imagine is tabindex just delegates to the css feature
<rachelandrew> also dense packing causes reordering, and the author can't control it, as will masonry.
<TabAtkins> annevk: then you could use CSS to further override it
<TabAtkins> annevk: so if you reorder the visual vs Dom, you can use CSS to fix that
<TabAtkins> annevk: it makes sense to me that CSS would win, so we could explain the HTML in terms of that
<masonf> tabatkins: An earlier draft of this feature had a feature to specify an integer to give an ordering, but we removed it because it's not a great idea anyway.
<masonf> tabatkins: also the tabindex already exists, even though it's bad, it works for this use case. This feature (reading-flow) does what you can't do - match layout predictably.
<bkardell_> q+
<masonf> tabatkins: Otherwise, you'd have to use JS. We don't like explicit tabindex so we didn't want to copy it into CSS. So we're left with defining how tabindex interacts with this feature.
<astearns> removing the index resolution and discussion: https://github.com/w3c/csswg-drafts/issues/8589#issuecomment-1721504153
<TabAtkins> annevk: I thought the CSS feature has a scoping mechanism, and the ability to say focus next
<masonf> tabatkins: you can choose a few options, but not arbitrarily.
<masonf> tabatkins: several examples where that happens.
<zcorpan> q?
<TabAtkins> annevk: I don't have an answer as to why tabindex shouldn't just be ignored
<TabAtkins> annevk: Once you start using this, shouldn't we just ignore tabindex?
<TabAtkins> TabAtkins: We just needed to give an answer to how they work together. If you feel strongly otherwise, we can have an issue
<TabAtkins> annevk: Yeah, makes the most sense to me to have it be ignored
<TabAtkins> domfarolino: what do you think is better - making tabindex secondary, or ignoring completely?
<TabAtkins> annevk: I think ignoring completely, based on what I've heard.
<masonf> q+
<TabAtkins> annevk: probably woudln't want things moving around based on tabindex
<jarhar> q?
<astearns> ack fantasai
<Zakim> fantasai, you wanted to react to zcorpan
<TabAtkins> fantasai: so tabindex is set on the individual items, while reading-flow is set on the container. tabindex has a higher specificity, in a way
<TabAtkins> fantasai: we might want equivalent functionality in CSS that operates on the individual items - there might be cases where reading-flow can't work automatically
<TabAtkins> fantasai: I'm guessing that's the logic behind the current behavior
<TabAtkins> fantasai: but I do think it needs a little more thought to how things work together, when it's not just simple content being reordered
<TabAtkins> fantasai: for example, a right-hand sidebar, versus an item around that sidebar, might want the sidebar read first
<TabAtkins> fantasai: so we have some mixed cases. I think tabindex is somewhat addressing that
<fantasai> s/an item/a collection of auto-positioned items/
<dbaron> q+
<astearns> ack bkardell_
<TabAtkins> bkardell_: I think Anne suggested that if we had a property in CSS equivalent to tabindex, then we could explain tabindex in HTML with the CSS mechanism. Is that right?
<tantek> wow bkardell_ brings up nav-index
<TabAtkins> annevk: It was a thought, yes. Not a complete proposal.
<TabAtkins> annevk: but Tab made a convincing point that tabindex is a bad API, not sure we should just copy it
<tantek> pretty sure we implemented nav-index in Tasman back in the day
<TabAtkins> bkardell_: I liked your idea about ignoring it, would you ignore all of it?
<TabAtkins> annevk: No, focus ability would be preserved, we'd just ignore the ordering. At some point we could introduce a property that more specifically lets you do that targeting.
<masonf> q?
<TabAtkins> annevk: But the mix of the two doesn't make a lot of sense to me right now.
<bkardell_> +1 , agree with what annevk just said
<TabAtkins> annevk: If you are using tabindex for one view, but then rearrange for another view and use reading-order, we'd still have a messed up order
<lea> q?
<TabAtkins> domfarolino: so then you'd have to stop using tabindex entirely if you wanted to use reading-flow
<kizu> +1 to ignoring tabindex inside a reading-flow scope
<TabAtkins> annevk: Yeah, seems reasonable
<TabAtkins> zcorpan: Wanted to ask about the a11y mapping
<past> ack zcorpan
<TabAtkins> Di: we have asked for feedback
<TabAtkins> Di: the reading-flow items that are sorted, we use that to present the items in the a11y tree
<TabAtkins> Di: normally the a11y tree follows by Dom order, so the unsorted items we keep in dom order
<lea> Inclined to also +1 to ignoring tabindex within reading-flow, the opposite seems very confusing, and also this provides a way to fix the issues with tabindex with a smooth upgrade path
<TabAtkins> zcorpan: So the plan is to spec that the a11y tree is reordered, good
<past> ack fantasai
<masonf> q-
<TabAtkins> dbaron: about the tabindex thing
<TabAtkins> dbaron: my understanding of this is - and maybe it's wrong way to think about it - is that when you're trying to find the next thing to focus, there's a process that's a tree traversal
<TabAtkins> dbaron: what reading-flow is doing, in my head, is it's changing the order you visit a set of siblings within that tree traversal
<TabAtkins> dbaron: but not really changing the whole tree traversal, just the visitation order of those siblings
<TabAtkins> (and their concepts)
<TabAtkins> s/cepts/tents/
<astearns> (was also going to say subgrid might be an exception)
<TabAtkins> dbaron: maybe subgrid has an exception
<TabAtkins> dbaron: maybe that impinges on your point about tabindex working, this changes just the visitation order of the siblings
<past> q?
<past> ack dbaron
<TabAtkins> annevk: I see what you're saying, if you use tabindex to change the visitation order and there's tabindexes inside of a part, it stays useful
<TabAtkins> annevk: so does the scoping happen at the parent level, or for each sibling?
<TabAtkins> masonf: the parent
<TabAtkins> annevk: so that does run into the problem. if two grid items each have a tabindex value, then they'll be followed numerically, rather than according to the reordered values
<TabAtkins> masonf: I see your point there, we might need more thought
<TabAtkins> TabAtkins: agreed
<TabAtkins> I propose we ignore tabindex ordering *on the reordered children*, and then scope the childrne's subtrees
<TabAtkins> domfarolino: If we don't honor tabindex for the siblings, would we honor it inside the subtree?
<TabAtkins> annevk: I guess so, it makes sense with what David was saying
<TabAtkins> Di: So are there any questions about making display:contents a focus scope owner
<TabAtkins> masonf: in CSS if you have a flex or grid item that's display:contents, and that display:contents has tabindex, that item should be focusable and still be in the focus order. so the question is where in the sequential focus does it come up?
<TabAtkins> masonf: two current proposals
<TabAtkins> masonf: one is put all the display:contents children last
<TabAtkins> masonf: Other that feels cleaner and we think has fewer a11y issue, is you make display:contents children of these reading-flow containers focus groups themselves
<TabAtkins> rachelandrew: We asked devs if anyone is doing this, and couldn't find an example yet
<astearns> discussion and resolution about reading order and display:contents interaction: https://github.com/w3c/csswg-drafts/issues/9230#issuecomment-2261469723
<TabAtkins> rachelandrew: I think it's an unusual case to solve, not something we're seeing everywhere
<TabAtkins> masonf: we also prefer option 2, because eit's better for a11y and easier to implement
<masonf> tabatkins: because display:contents, they don't have a layout, but it's also safe to hold the layout, that makes sense.
<rachelandrew> https://developer.chrome.com/blog/reading-flow-display-contents the request for feedback I've been sharing, which explains the issue
<TabAtkins> s/hold the layout/pull the layout from the parent, and apply it to the children/
<ntim> Making flex items is not terribly uncommon fwiw
<ntim> Making flex items display: contents*
<TabAtkins> TabAtkins: As if the display:contents element become a display:flex (or whatever) holding its children
<TabAtkins> panos: Di, are you unblocked?
<TabAtkins> Di: Yes. We ask for everyone to look at the HTML spec PR
<ntim> I use it to conditionally hide a set of flex items sometimes
<emilio> q+
<TabAtkins> masonf: Everything should be in the Html PR, modulo the new tabindex question
<TabAtkins> annevk: So the display:contents thing is being resolved in this new property? Or only comes up in the context of this property?
<TabAtkins> masonf: Only comes up in this context.
<TabAtkins> annevk: Okay, it does sound like of your two options, putting the display:contents at the end was weird
<TabAtkins> Di: And <slot> is display:contents, which is why we spend so much time thinking about this
<past> ack emilio
<TabAtkins> emilio: This is only an issue if the display:contents is focusable, yeah?
<TabAtkins> masonf: current proposal is display:contents children of these containers *always* makes them into reading order containers
<TabAtkins> emilio: Okay, and that prevents reordering across siblings
<TabAtkins> emilio: So for the purpose of focus, this sis only an issue if the display:contents element was focusable as well
<TabAtkins> masonf: Yes, the traversal algo would be a little more complicated, but that's it
<ntim> example of what i use `display: contents` flex children for: https://jsfiddle.net/dk1Lryhj/
<zcorpan> s/this sis/this is/
<TabAtkins> emilio: I think ideally, if you don't have a focusable display:contents element, you'd want the behavior of visiting children in the visual order
<TabAtkins> masonf: I think yes, except the a11y tree becomes harder in that case.
<TabAtkins> masonf: And I think the tab order should match the a11y order
<TabAtkins> TabAtkins: Okay, so display:contents scopes the ordering, even if their items are visually interwoven
<TabAtkins> emilio: that seems a little confusing to me as an author, you're saying use the visual order, but you don't get that
<TabAtkins> masonf: Yeah, all the possible solutions aren't obvious
<TabAtkins> emilio: display:contents that's focusable is indeed rare, but display:contents that isn't focusable seems a lot more common.
<TabAtkins> emilio: that's the main use-case of display:contents, to let the parent take up the children
<TabAtkins> masonf: If focus order was all we had to deal with, I'd agree
<TabAtkins> emilio: Yeah, I understand the a11y tree makes it hard.
<TabAtkins> rachelandrew: It seems that people are generally using display:contents in mostly simplistic ways at the moment
<TabAtkins> rachelandrew: whenever I ask for example they're just removing a wrapper from an element
<TabAtkins> emilio: right, but I think it would break even simple cases. A control with a label, in a display:contents container. If I visually lay them out so multiple labels are together...
<TabAtkins> masonf: slots are *already* focus scoped, actually, so that "breaks" today already
<TabAtkins> emilio: Hm, the way I'd want to use this feature might override that behavior...
<TabAtkins> masonf: Yeah, we're proposing to make display:contents act like how slots work today
<TabAtkins> [discussion of the grid use-case]
<TabAtkins> rachelandrew: We have tried to design some friction into this property anyway, so people don't just apply it willy-nilly.
<TabAtkins> emilio: so the main issue I guess is there's just no way to get the reordering use-case to work. maybe we're fine with that.
<TabAtkins> q?
<TabAtkins> emilio: So I think there are some realistic use-cases that would break under this behavior.
<fantasai> I think it would be useful to collect actual design use cases; the Google examples are quite simplistic and good for teaching but I think don't represent the complexity of what authors may need to do
<TabAtkins> emilio: two non-slots, forget the slot behavior
<TabAtkins> emilio: both display:contents, and use 'order' to put some elements of each at the top, you'd still get the weird order
<TabAtkins> masonf: It doesn't work in that it gives the wrong order, but at least it is focusable
<TabAtkins> annevk: So you couldn't find much cases where display:contents is focusable, but we thought it was important for display:contents to be focusable, how do those square
<TabAtkins> TabAtkins: Rachel has a lot of examples of *simple* display:contents use, just not complex ones that would run into this discussed issue
<TabAtkins> dbaron: I think there was a big discussion of whether display:contents should be in the a11y tree.
<TabAtkins> dbaron: there was a strong agreement that there should be, we all shipped it, *then* we had the trouble that the focus order didn't match the a11y order, and things were broken
<TabAtkins> lea: If authors need slots to be focusable, they'd also override display:contents, right?
<TabAtkins> annevk: I'm still confused that display:contents isn't more like display:none
<TabAtkins> TabAtkins: If you display:contents an <a>, the contents are still clickable. They need to be focusable too
<TabAtkins> annevk: Becuase links are done via Dom structure...
<TabAtkins> [more discussion about links being display:contents]
<TabAtkins> masonf: So this has been a good discussion. Dont' think anyone's come up with a better idea so far, but if anyone does...
<TabAtkins> annevk: Probably just doing what slots do today is fine, and if we need further overrides we can develop that.
<TabAtkins> annevk: Even if it comes up in practice for one person, we should probably wait a few...
<TabAtkins> lea: What if you call El.focus() on a display:contents element?
<TabAtkins> emilio: Under dbaron's proposed behavior, it does get focused.
<ntim> i feel like the discussion is getting off topic from the original issue
<TabAtkins> emilio: today it's not focusable
<TabAtkins> dbaron: But we want to change it
<TabAtkins> [point of order, no more breakouts within the room]
<fantasai> scribe+
<fantasai> TabAtkins: Sounds like conclusion is that [missed]
<fantasai> TabAtkins: although someone uncomfortable, nobody has a beter idea
<fantasai> s/[missed]/thing currently marked option 2 in PR/
<fantasai> TabAtkins: making `display: contents` work the same way as <slot>s do today
<TabAtkins> Di: So option 2 is make display:contents its own focus-scope owner, similar to <slot>
<TabAtkins> Di: What Dom is mentioning about putting display:contents last is a different part of the proposal
<TabAtkins> Di: And that other part is "everything not part of the layout just goes at the end, after all the visually-sorted options"
<TabAtkins> fantasai: So if I have a grid with a display:contents child, and *its* children are reordered by the parent grid, what happens
<TabAtkins> fantasai: so we have a flex with children A, B, C. B is display:contents with B1 and B2 children
<TabAtkins> fantasai: visual order is A B1 C B2
<TabAtkins> Di: So the focus order is currently A C B1 B2 - the display:contents is put at the end, as it's not visually sorted, and then its children are sorted visually
<TabAtkins> fantasai: okay new order A B1 B2 C
<TabAtkins> fantasai: But I've set reading-flow on this element
<TabAtkins> fantasai: As an author I'd expect reading-flow to not change the order of things
<TabAtkins> annevk: I'm also confused about thtis
<TabAtkins> masonf: two issues, one is whether display:contents forms a scope
<TabAtkins> annevk: Yeah, assume we do that to align with slot
<TabAtkins> masonf: Then we have a choice where to put the display:contents children
<TabAtkins> emilio: Put them where in the visual order the first sub-item shows up?
<TabAtkins> emilio: I think fantasai was hinting at this
<TabAtkins> emilio: when you're iterating the items, you can figure out "this item's layout parent isn't it's Dom parent, so it's display:contents"
<TabAtkins> emilio: so at that point you'd walk the display:contents subtree and do them in visual order
<TabAtkins> dbaron: so two options I think I heard
<TabAtkins> dbaron: one is when you hit the first Dom child of the display:contents
<TabAtkins> dbaron: another is when you hit the first *visual order* child of the display:contents
<TabAtkins> fantasai: the second one
<TabAtkins> emilio: I also think second, it allows more intuitive behavior when you reorder inside the display:contents
<TabAtkins> fantasai: I think it's important to make sure A B1 B2 C order stays as it is, you haven't moved *anything*
<TabAtkins> fantasai: Also would be good to have A B2 B1 C (with 'order') to work visually
<TabAtkins> fantasai: These are the most common by far cases of using display:contents
<TabAtkins> fantasai: the full re-ordering examples are much rarer
<TabAtkins> annevk: What if the visual order is C B2 B1 A, reversed?
<TabAtkins> fantasai: Yes, should still work visually. As long as the items are in contiguous visual order, it should still work
<TabAtkins> emilio: Say you flip the order in a display:contents. question is what tab order would you expect
<TabAtkins> emilio: I think ideal is what elika said, actually reorder them
<TabAtkins> emilio: I dunno how that interacts with the scope owner thing
<fantasai> s/full re-ordering examples/full re-ordering examples with interleaving/
<TabAtkins> emilio: Unsure if we can go back up to the parent and look at that reading order
<TabAtkins> masonf: Layout's already happened, you know the order.
<TabAtkins> masonf: So it sounds like people agree that display:contents is a scope owner, regardless
<TabAtkins> masonf: Then the question of what order relative to other things, which it sounds like we're coming toward
<TabAtkins> annevk: So if the visual order is B1 A C B2...
<TabAtkins> masonf: order would be B1 B2 A C in tabbing
<ntim> In https://jsfiddle.net/0x5yuLd2/1/, I would expect the order to be "first name, last name, credit card, cvv, expiration"
<TabAtkins> emeyer: I'm still not okay with the display:contents reordering, if visual order doesn't match even tho I asked for it, I think CSS is broken
<TabAtkins> masonf: Problem is the a11y tree is also "broken" in that case
<TabAtkins> chrishtr: We think the full-interleaving case is an uncommon example. It works fine if there isn't interleaving.
<TabAtkins> emeyer: Yeah, just giving the author-facing feedback
<TabAtkins> chrishtr: Okay so if it's a focus scope owner
<TabAtkins> chrishtr: What's the exact proposed ordering, to not put the display:contents at the end?
<TabAtkins> TabAtkins: You go thru the layout order, until you hit one that's in a different focus scope, then you recurse into that focus scope, then pop back out
<TabAtkins> annevk: The main reason it has to be a scope owner is that really the order is B B2 B1, not just B2 B1
<TabAtkins> chrishtr: Di, does that make sense to you, giving impl experience?
<TabAtkins> Di: Yeah, have a question since we don't actually see the B element in the visual order
<TabAtkins> emilio: You'd hit B1 visually, note that its parent is display:contents, then actually put B into the order, then B1, B2
<TabAtkins> annevk: [missed an example]
<TabAtkins> masonf: That makes the algorithm stateful, currently it's stateless
<TabAtkins> dbaron: It doesn't have to be stateful, but making it stateless is expensive, you have to crawl the Dom to see if we *would* have hit the element
<TabAtkins> fantasai: Here's an example of reordering'
<TabAtkins> fantasai: you have a number control, has plus and minus button
<TabAtkins> fantasai: So your control is some container, it's got a text input, and a plus and minus button.
<TabAtkins> fantasai: you want to lay it out with + on the left and - on the right. You use display:contents on the control wrapper
<TabAtkins> [I didn't understand the example actually, i'm confused]
<TabAtkins> fantasai: So the a11y tree should be able to see the "control" itself (as a wrapper) before we actually hit the + button
<TabAtkins> dbaron: So my question is when do we recurse into the display:contents
<TabAtkins> dbaron: Do we do it when we encounter the first visual child, or the first DOM child?
<TabAtkins> dbaron: In the second, if something else was interleaved, we'd do the interleaved first, *then* hit the first child of the display:contents and do the subtree
<TabAtkins> [everyone agrees that's bad, it should be the first visual child
<TabAtkins> ]
<TabAtkins> emilio: Is the "first visual child" thing different if you navigate backwards?
<TabAtkins> dbaron: If you care about first visual child when tabbing forward, you need to care about the last visual child when going back
<TabAtkins> masonf: agreed
<TabAtkins> annevk: Again we have the visual order of B2 A B1, the focus traversal would match but with the B wrapper, B B2 B1 A
<TabAtkins> (sorry, he said B B2 A B1)
<TabAtkins> masonf: No, that breaks the a11y tree. They're always siblings in the a11y tree, so it has to be B B2 B1 A
<TabAtkins> annevk: So B is a hard owner of its tabbing order due to the a11y tree
<TabAtkins> chrishtr: Rachel, any thoughts from a teaching perspective?
<TabAtkins> rachelandrew: I think it's weird whatever. But consistency with <slot> is useful
<TabAtkins> rachelandrew: I don't feel like there's a better solution.
<TabAtkins> rachelandrew: And I don't think the interleaving case is a common situation anyway.
<TabAtkins> Sanket: So there's focus scope owner, is it only slot and display:contents?
<TabAtkins> [no, there's several others, like dialog]
<TabAtkins> sanket: So those already behave this way?
<TabAtkins> chrishtr: For focus, yes.
<TabAtkins> annevk: The display:contents case is special because it's not actually displayed
<TabAtkins> emilio: Request, to make emeyer happy
<TabAtkins> emilio: The main thing that prevents us from doing splitting is making the a11y and focus order match.
<TabAtkins> emilio: Is it well-documented why they need to be the same? Is it better to break that for this case, or?
<TabAtkins> annevk: I was curious too, if that's really a hard limitation there's no future solution either.
<TabAtkins> emilio: Yeah, wondering if it's a hard blocker
<TabAtkins> masonf: We're not the experts, but we've been told it's needed
<TabAtkins> ???: Does tabindex rearrange the a11y tree?
<TabAtkins> chrishtr: No
<TabAtkins> dbaron: There's a difference between "here's a thing, and you can't get to it at all" and "here's a thing, and it's in a weird position". pretty big difference
<fantasai> TabAtkins: We're doing the whole scope owner thing because wanted to push to the end
<fantasai> TabAtkins: if we're adopting where it is visually, then might not need to
<fantasai> TabAtkins: B still needs to show up before its first visual child
<fantasai> emilio: Reason we needed it was so that it doesn't mismatch the a11y tree
<fantasai> TabAtkins: but you can currently use tabindex
<fantasai> emilio: Right, you can already mismatch
<fantasai> annevk: maybe don't need to match tree, but [missed]
<fantasai> TabAtkins: if you use A and tabindex on A and 2 children inside the A, and on something else
<fantasai> TabAtkins: your order can flip back and forth
<fantasai> TabAtkins: if you display:contents the A, don't know where to put it
<fantasai> TabAtkins: but if we define "it goes just before its first visual child" then we're back to where we were before display:contents
<fantasai> TabAtkins: with this answer to where we put it, i.e. right efore first visual child, we don't need to do scope owner
<fantasai> emilio: right, and we have precedent for that
<fantasai> ?: do we need scope owner for <slot> then still?
<fantasai> emilio: My understanding was to avoid conflicting with a11y tree, but can already diverge with tabindex so maybe we can make Eric happy
<astearns> s/?/Di/
<fantasai> mfreed: an exmaple without tabindex, you have a mismatch
<fantasai> emilio: is that a problem?
<fantasai> ...
<TabAtkins> TabAtkins: tabindex is a bad *design*, but I'm not sure if it's actually a bad thing *for a11y* here
<fantasai> emilio: if we need to make 'display: contents' focus scope owner for matching a11y, if that's a hard block can we document vry clearly why?
<TabAtkins> domfarolino: So next step, talk to a11y people to see if it's *okay* to have another case, like tabindex, of tab order mismatching a11y order?
<TabAtkins> emilio: Yes. If we get feedback that it's bad, we have consensus on scope owner + first visual item.
<TabAtkins> fantasai: So we can resolve on first visual, and figur e out scope later
<bkardell_> I just wanted to mention that it looked like the aria group was discussing some of these same things when we started in their group - it sounds like they had questions for us, and we have (if I understand) questions for them. We're in the same actual location, maybe we should get together and talk
<TabAtkins> fantasai: proposed resolution: display:contents focusable element occurs in the order immediately before its child that's first in visual order
<TabAtkins> dbaron: and when tabbing in reverse, it's still preceding it in the original order, so reverse-tabbing it's after
<ntim> emilio: needs tweaking for nested display: contents
<masonf> +1
<fantasai> RESOLVED: display:contents focusable element occurs immediately before its first child in visual order
<ntim> 🎉 🎉
<ntim> 🍾
<dbaron> (and probably an empty display contents goes at the end?)
<TabAtkins> proposed resolution: tabindex is ignored (for order purposes) on the items of a reading-flow container, but it *scoped* to those items if on descendants
<TabAtkins> proposed resolution not passed, we'll discuss in an issue
<Lionel_Wolberger> scribe+
css-meeting-bot commented 1 month ago

The CSS Working Group just discussed [css-display-4] Define how reading-flow interacts with focusable display: contents elements..

The full IRC log of that discussion <fantasai> s/Topic: [css-display-4] Define how reading-flow interacts with focusable display: contents elements.//
<fantasai> TabAtkins: [summarizing] Current spec proposes any 'display: contents' element doesn't participate in reading flow, appended to the end
<fantasai> ... and they also scope the children, which then end up at the end
<fantasai> ... but that's not great behavior
<fantasai> ... especially since no-op where DOM order and visual order match, now we have everything at the end
<matatk> q+ to ack the definition of display:contents
<fantasai> TabAtkins: new proposal is that 'display: contents' doesn't get moved to the end. Instead, children get ordered according to visual order
<fantasai> ... and 'display: contents' element itself gets placed immediately before its first child in visual order
<fantasai> TabAtkins: further question, which we wanted to ask you are, does it still need to scope its children?
<fantasai> ... when you hit 'display: contents' item, do you recurse and do all of its children first, or do you follow an interleaved order (if that is what visual order is)?
<Zakim> matatk, you wanted to ack the definition of display:contents
<fantasai> TabAtkins: argument for scoping is that a11y tree will match
<fantasai> ... all of the children will be contiguous
<fantasai> ... Argument for not scoping is that it matches visual order
<fantasai> ... and tabindex already jumps in and out of a given eleent, if that's how you wrote your HTML
<PaulG> q+
<fantasai> TabAtkins: so the question to you is, is the tabindex behavior horrible and not good to duplicate
<fantasai> ... or is it more important to match visual order, even if you jump in and out of tree
<fantasai> matatk: Thanks for explanation.
<zcorpan> (I found 0 pages with `<div role="table">` in httparchive sample_data (10k pages). So at least not common enough to show up in a 10k random subset of 12m pages.)
<TabAtkins> fantasai: To make i tmore concrete, say I have a tree with siblings A, B, C
<TabAtkins> fantasai: B has children B1 and B2
<TabAtkins> fantasai: in tree order I get A B B1 B2 C
<TabAtkins> fantasai: if I set display:contents on B
<TabAtkins> fantasai: I get the items as A B1 B2 C
<TabAtkins> fantasai: If I reorder them, I could visually reorder them as A B1 C B2
<TabAtkins> fantasai: Which interleaves them
<TabAtkins> fantasai: So, because B1 and B2 are under the B parent, in the a11y tree structure
<TabAtkins> fantasai: Should the reading order A B1 B2 C (keeping them contiguous)
<TabAtkins> fantasai: Or should it be A B1 C B2 (matching visual order)
<TabAtkins> fantasai: If B was display:contents but focusable, it would be A B B1 C B2
<TabAtkins> (in strict visual)
<TabAtkins> fantasai: Or we could cause the display:contents to strictly scope, giving A B B1 B2 C
<TabAtkins> fantasai: So do we force the containment, or match the visual order, when things are interleaved
<fantasai> matatk: You described previous change, and new change, what's happening now?
<fantasai> TabAtkins: All under discussion
<matatk> q?
<matatk> ack PaulG
<fantasai> PaulG: my instinct is that visual order should be strict
<fantasai> ... we tell devs not to use tabindex above zero
<fantasai> ... [too quiet]
<matatk> q?
<fantasai> ... if I had the choice between strict visual order or using tabindex to enforce the order, I woudl want strict visual order
<fantasai> ... don't want to use tabindex, since we coach devs not to use it
<matatk> q?
<fantasai> TabAtkins: dilemma wans't use tabindex or not. There's an existing behavior where tabindex jumps across tree boundaries.
<fantasai> ... question is, is that behavior acceptable here to match strict visual ordering?
<fantasai> PaulG: Not a disservice to enforce strict visual order
<fantasai> ... avoid people using tabindex for that purpose
<matatk> q?
<fantasai> matatk: My thought is, what would be really helpful is if you could flag APA with the result of that PR
<fantasai> ... that would be helpful
<fantasai> matatk: Some of the examples were relating to custom controls using templates and shadow DOM.
<fantasai> ... does it work no matter what the context?
<fantasai> TabAtkins: slightly different if using components, because <slot> is strict scoping container for tabindexing
<fantasai> ... all things in a <slot> are grouped
<fantasai> matatk: I think we lean towards an accessibility view on it; but would be helpful to track 'display: contents'