w3c / csswg-drafts

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

[selectors] Add :role() pseudo-class #3596

Open tabatkins opened 5 years ago

tabatkins commented 5 years ago

In https://lists.w3.org/Archives/Public/www-style/2015Jan/0004.html (Oct 2014 Santa Clara f2f), we resolved to add a :role() pseudo-class, to match based on ARIA roles easily:

minutes excerpt
TabAtkins: jcraig suggested a :role pseudo
hober: There's a few problems. One is the impl RA roles on the
elements. When you have multiple roles on one element, you
get all of them.
hober: For styling you may want to style that as a switch or a
checkbox. Right now that's difficult in CSS.
hober: There's also the case of wanting to simply style all the
buttons on the page.
hober: You want to be able to say :role(button) and be done.

TabAtkins: That's convincing. Is there anything outside that?
hober: We can always add more.

glazou: You mentioned implied role. So some won't need an assigned
role. We'll need to refer to HTML.
hober: In CSS we say the host language has that.

dbaron: It's :: or : ?
TabAtkins: It's a functional class. It should be an ident.
glazou: Can you have multiple roles?
hober: Syntactically you can,
hober: But only one is active.
glazou: So if you have multiple roles on one element, it's
whitespace broken?
dino: So if you do :role...
hober: You can do role=button and role="super button". Or we
separate in the list itself.
glazou: So the role attr is multiple but the :role() pseudo is only
one?
hober: Yeah.

dauwhe: dpub is working on adding things for role attr.
TabAtkins: Do you know if it will be consistent with this?
dauwhe: They haven't said. I'll raise that with them.

TabAtkins: So I guess that's simple. Objections to adding :role()
to selectors?
TabAtkins: So :role(button) would target anything that has a
button according to aria rules.
hober: It wouldn't match button role = checkbox or something crazy

dbaron: So people are okay with agreeing CSS won't do future
things to influence what the aria role is.
hober: It should be defined by pointing over there [to markup layer].
fantasai: We need to have another language that has CSS syntax for
that kind of stuff. Our stuff should be about styling.
fantasai: People keep asking us to put things in CSS that belong
in the DOM, because they want to use CSS selectors and
cascading to attach it to the tree.
TabAtkins: If someone would like to implement cascading attr
selectors in a browser shrug
dbaron: Having CSS do this side makes sense, but we can't do both.
hober: Should we have a note in the spec saying "you may be
confused"?
glazou: When we had selectors we didn't have a note. I'm not sure
we need a note.
hober: Okay.

glazou: So no objections?

RESOLVED: add :role() to selectors

glazou: Who is going to write the prose?
TabAtkins: I will.

I volunteered to write the text, but clearly never did. ^_^

bkardell commented 5 years ago

I really like the idea of this and was thus going to take a stab at writing some proposed prose here, but .... from my recollection, and the minutes (both of which may be flawed), it feels like the 'key' things mentioned here really hinge on this being based off the computed role - like what is the actual role that this is playing. But, in discussing this with @alice, this might actually be pretty tricky because what the computed role is sometimes involves fairly complex checking and tree walking.

alice commented 5 years ago

I'd be interested to know what use cases @cookiecrook had in mind here.

I agree with @bkardell, it seems to be implied that this refers to computed ARIA-equivalent role (i.e. a <button> would match :role(button)), but that is not clear from the minutes.

Assuming that to be the case, implementing this could be quite complex.

cookiecrook commented 5 years ago

That is the case, but Alice is correct that implementation proved significantly more challenging than expected.

Style parsing needs to happen before layout and rendering. In WebKit (and Blink, maybe more) the accessibility tree is computed based on the render tree. Since accessibility can change the roles (or refuse to change the roles of malformed nodes), current implementations could result in one of the following:

  1. A circular dependency (neither style nor accessibility can proceed until the other is complete)

  2. CSS rendering continues but when accessibility loads, it could trigger new layout and repaints.

We left off that path by determining that a non-trivial amount of WebCore Accessibility would need to be extracted from the accessibility-specific codebase and refactored for use prior to layout.

It’s not impossible, but it’s quite a bit more than anyone was willing to commit to.

A WICG incubator may be a good path forward for this one. You’ll need implementor involvement and buy-in before the :role() selector can proceed.

cookiecrook commented 5 years ago

@bkardell wrote:

the computed role is sometimes involves fairly complex checking and tree walking.

As one example of this complexity, review AccessibilityTable:isDataTable() in the WebKit source.

In addition to hierarchical validation and well-formedness (<tables> do not get the table role unless they have a valid grid of rows and cells), this method checks for a variety of style-based heuristics such as borders and zebra-striped row colors. It's determining layout-vs-data table based on the style characteristics, which then determine the role, and would only then affect the cascade for a :role() selector.

SelenIT commented 5 years ago

I have a strong feeling that distinguishing data tables from layout table is a special, largely historical, exceptional case, that should be not generalized as a rule. Tables were used for layout when there were effectively no alternative. Tables are probably the only HTML elements misused this way because of their default styling. There never were such thing as "Layout lists" or something. The "HTML is meaning, CSS is presentation" mantra is one of the first things that modern web developers learn. Many web developers try hard to make their markup meaningful for non-visual output (e.g. wrapping navigation links into list items) while presenting it visually as design requires (e.g. as a horizontal flexbox "ribbon"). When browsers deduce from this that the author "didn't mean" a list there, it feels like a huge disappointment with the very idea of the semantic markup (at least, I felt so).

I admit that there definitely might be other special cases where styling distorts the initial meaning of elements for sighted users and ATs have to convey this distortion, but they should probably be investigated and specified individually. The general rule should be that CSS doesn't affect the implied meaning of the content unless there is an absolute and consensus-approved necessity to do so. Similarly to what we have already decided in #2355.

Crissov commented 5 years ago

So, :role() would be a bit like :lang() in that it can be inherited or inferred, while [role] or [aria-role] cannot. A pseudo-class seems appropriate then, otherwise I would have suggested special syntax as for IDs #foo and classes .bar, e. g. *@baz or %baz.

bkardell commented 5 years ago

@Crissov can you explain that comment a little more?

bkardell commented 5 years ago

@SelenIT - I think @alice or @cookiecrook can speak better to how unique that particular example is, but there's definitely additional relationships and complexity which I'm unsure even happens at the right stage right now to be considered in a selector. I believe some roles may actually rely on CSS application in order to determine their computed role, which would be problematic. I'm not suggesting that this isn't a thing that shouldn't be supported, and if we were designing all of the things fresh, this is a thing I would really want to keep in mind - I just wonder if we might not need to think about this a lot more and maybe work on some efforts to detangle - or maybe thinks about revise the ask somehow in a way that could be achievable but not just add confusion for developers about one more hard to understand kind of value?

Crissov commented 5 years ago

@bkardell At first, I wondered how :role(foo) would be any different from [role=foo], but then I realized that attribute selectors work on explicitly specified values while pseudo-classes can work on implicit values. Also, IDs and classes are not predefined by an external body while ARIA roles and BCP47 language codes are.

ExE-Boss commented 5 years ago

Also, adding completely new special syntax might not work so well with https://github.com/w3c/csswg-drafts/issues/3264.

cookiecrook commented 5 years ago

@SelenIT wrote:

I have a strong feeling that distinguishing data tables from layout table is a special, largely historical, exceptional case, that should be not generalized as a rule. [...] There never were such thing as "Layout lists" or something.

Here's the same concept for layout lists (a.k.a. "list-itis") versus semantic lists:
AccessibilityList::determineAccessibilityRole() in the WebKit source

"div-itis" is also a thing, though thankfully <div> doesn't get an important role by default. Other element types that my get this treatment at some point include <article>, <header>, <footer>, etc.

cookiecrook commented 5 years ago

@SelenIT

When browsers deduce from this that the author "didn't mean" a list there, it feels like a huge disappointment with the very idea of the semantic markup (at least, I felt so).

Not to diverge too far off topic, but some additional threads on that are here: https://twitter.com/pgrucza/status/1083835348671700992 https://twitter.com/cookiecrook/status/1084141791580905472

SelenIT commented 5 years ago

the same concept for layout lists (a.k.a. "list-itis")

@cookiecrook, thank you for these links. I completely agree with the Priority of Constituencies principle you cite. Hovewer, my point that there is no such thing as layout lists still stands. The term "layout lists" is a misnomer. There is a huge difference between (mis)using specific elements because of their styling and (mis)using them despite their styling, making extra effort to "overcome" it. I'd rather call them something like "unobvious lists" or "cryptic lists":)

Indeed, sometimes the "listitis" makes a page too verbose for screenreader users, and they definitely may feel some of the extra list-related info redundant and removing it can look helpful for them. I agree with this intent, but one premise of the issue 134187 seems wrong to me:

Chances are that they are just presentational lists using the elements for the sake of a styling hook.

How big are chances that someone uses a specific element not caring about its meaning and makes extra effort removing its styles, while there is much easier-to-use alternative (div)? There are probably more chances for the purely presentational (e.g. WYSIWYG-generated) markup that uses graphic markers just for decoration to pass the existing heuristics.

I'm pretty sure that the primary reason for overusing lists (instead of divs and other much easier to style elements) is intent to convey extra semantics (e.g. "this is a list of 5 horizontal navigation links" or "this is a 15 items portion of the catalog list ordered by price") that sighted users can usually deduce from the visual context (how the items are grouped together, which common decorations distinguish them from other elements on the page, etc.). And I'm not sure that hiding this intended meaning that authors did put into the markup from the non-visual users really serves the users' priority. Indeed, some heuristics to treat different type of lists differently could be useful, but styling is probably not the best criterion for this.

css-meeting-bot commented 2 years ago

The CSS Working Group just discussed :role() pseudo-class.

The full IRC log of that discussion <fantasai> Subtopic: :role() pseudo-class
<jcraig> scribe-
<jcraig> s/scribe-//
<fantasai> Rossen_: Can someone summarize this issue?
<fantasai> github: https://github.com/w3c/csswg-drafts/issues/3596
<fantasai> matatk: Is this a shortcut for the attribute selector? Seems to be syntactic sugar
<fantasai> fremy: There are some differences, handles roles that are implied as well
<TabAtkins> Yeah, handling implicit roles is the big point
<fantasai> PaulG: Map to computed role from Chrome's implementation
<fantasai> fremy: could do it yourself with correct attribute, but simplified way
<fantasai> heycam: is computed role only a function of role and tag name, or more things?
<fantasai> matatk: Landmarks, I maintain an extension to navigate, and where they are in teh document determines what they are
<fantasai> ... e.g. if header/footer are scoped to page you have page header/footer
<fantasai> ... but inside an article, not the same landmarks
<fantasai> ... not that simple, so I can understand why if browser does the matching it would be useful
<fantasai> PaulG: What's the status of it?
<fantasai> Rossen_: There's a group discussing this with ARIA
<fantasai> TabAtkins: Several years back we resolved to add this, to expose computed roles to selectors
<fantasai> ... several years after that, I raised this issue saying that I was supposed to draft it
<fantasai> ... still haven't written it
<fantasai> ... if any concerns about it, please file issues/comments
<fantasai> ... otherwise this is just something that needs to be written by me at some point, because I signed up for it
<fantasai> Rossen_: With this, we are out of time
<fantasai> Rossen_: thanks APA for joining us
<fantasai> Janina: Thanks for your hospitality
<fantasai> Rossen_: please do engage on the issues
<fantasai> ... we love to work with ou
<fantasai> ... if you find a liaison, would love to work with them
<fantasai> s/ou/you/
<fantasai> matatk: File issues is the theme for this week!
<fantasai> <br duration=10m>
andyearnshaw commented 1 year ago

I discovered this issue after thinking about how to write some generic code for a web component that will use an event handler to find the nearest ancestor with a specific role and then get some more information about it. It looks like there's a current limitation, where a custom element has role set via ElementInternals.role, which means you cannot rely on a CSS selector to find that custom element by its role. For example,

myCustomTable.addEventHandler('click', ({ target }) => {
  // This won't find an element whose role is set with ElementInternals.role
  const clickedCell = target.closest('td, [role="cell"]');

  if (clickedCell) {
    // There's a separate, but similar problem here that AOM should address
    const [x, y] = getColumnAndRowIndex(clickedCell);
    handleCellClick(x, y);
  }
});

Not only would :role() simplify the selector, it would cover this current limitation.

cookiecrook commented 1 year ago

the same concept for layout lists (a.k.a. "list-itis")

@cookiecrook, thank you for these links. I completely agree with the Priority of Constituencies principle you cite. Hovewer, my point that there is no such thing as layout lists still stands. The term "layout lists" is a misnomer.

Here's a more complete thread of the background on layout lists and why I would expect WebKit's behavior to remain.

Regardless, the lists example tangential to the point of this issue. There are other contextual role roles in ARIA and HTML-AAM. While I agree that it'd be possible to extract some or all of this logic from the accessibility runtime and insert it into the mainstream runtime, it's a non-trivial amount of work that, so far, no implementor I'm aware of has agreed to take on.

LeaVerou commented 6 months ago

To echo my comment from #10222, I’m not sure what the use cases are here. Is the idea that authors would switch their default styles from using the kinds of long selectors discussed in #2296 and would use :role(textbox) and :role(button) instead? If so, I’m unsure if that’s a good idea as it seems to mix style and behavior — in most web apps there are buttons that look like buttons, and buttons that don't look anything like buttons, especially given the lack of good ARIA roles to describe today’s UIs. E.g. even interactive visualizations where you hover over a e.g. a pie chart wedge or scatterplot circle to see more info about that data have to use role=button because there’s nothing better.

Crissov commented 6 months ago

The apparent need for additional roles in ARIA does not negate the usefulness of a role selector in CSS. If that’s an issue in practice it should be brought up in the proper place.


(The following is a draft comment from a while ago which I rediscovered just now and shall publish without any reevaluation:)

I’d like to point out that someone could create an external specification that assigned ARIA implicit default roles to elements in very different markup languages, e.g. ones without obvious element names like Markdown, thereby paving the path of adding direct CSS styling support to them.