Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[css-ui] Support setting offscreen content inert #10711

Open
flackr opened this issue Aug 7, 2024 · 30 comments
Open

[css-ui] Support setting offscreen content inert #10711

flackr opened this issue Aug 7, 2024 · 30 comments
Labels

Comments

@flackr
Copy link
Contributor

flackr commented Aug 7, 2024

Problem

Tab and carousel UI patterns that can be mostly created with pure HTML and CSS. #9745 is aiming to expand upon how rich of an experience can be declaratively built. The primary use cases explored here are scrolling paginated tabs or carousels. E.g.

The ARIA Authoring Practices Guide recommends that only the currently visible content is in the focus order, and has examples which achieve this either by:

  1. using display: none (example 1, 2) when they can (i.e. when the switch between slides is immediate), or
  2. by setting aria-hidden from script (example 3).

In many cases, display: none can't be used, e.g. in most of the above cases because the previous and next slide may be visible simultaneously. However, since the alternative is an HTML attribute, it requires developers to write script that listens to the appropriate events and set these states, which can be a tricky to correctly detect and is unfortunate to need for cases where the interaction is otherwise declarative (e.g. scrolling or anchor links).

Proposal

I believe there are a few ways we could approach this problem:

  1. Adding a CSS inertness property, e.g. interactivity: auto | inert which was previously deferred in [css-ui] Should inertness be exposed as CSS property? #7021 awaiting better use cases. This has the potential to help with animation related cases, e.g. [css-display] Interaction gotchas when delaying the effect of display: none #8389 where we currently try to infer this temporarily visible but inert state from the underlying style. With this property, developers would still need to have a way to trigger this style change as a result of whether something is currently visible which could be based on a view-timeline, e.g.
    @keyframes interactive-when-visible {
      0% { interactivity: auto; }
      100% { interactivity: auto; }
    }
    .page {
      interactivity: inert;
      animation: interactive-when-visible;
      animation-timeline: view();
    }
    Or by a ::snapped query as in [css-scroll-snap] Proposing :snapped: exposing private snapped item browser state for developers and designers #6985:
    .page {
      interactivity: inert;
      &::snapped {
        interactivity: auto;
      }
    }
  2. Adding a CSS property specifically for making offscreen content inert, e.g. overflow-interactivity: auto | inert. This would make content that does not intersect the optimal viewing region of the scrolling container inert as it would be if it were display: none.
  3. Adding an enumeration value to the inert attribute similar to hidden=until-found, e.g. inert=offscreen which could behave either like option 1 or 2 depending on which made more sense.
@flackr
Copy link
Contributor Author

flackr commented Aug 7, 2024

In my opinion, I don't think that this should be in HTML (option 3). Setting it via HTML requires setting it on every element even though it is a property of the way the elements are presented. Also, CSS can switch the way that content is presented based on media queries which would change whether content out of view should be considered inert or not. Between the two CSS options, I think that option 2 is simpler for this use case but feel that option 1 may generalize better to other use cases.

@flackr flackr added css-ui-4 Current Work Agenda+ labels Aug 7, 2024
@tabatkins
Copy link
Member

I agree that option 2 is the most author-friendly. I think it's compatible with also doing 1 in the future if we find that reasonable. We could either make option 2 use the same property we expect to use for option 1, but with a specialized keyword, or do a separate property and define the interaction (probably: it's inert if either property calls it inert).

I lean slightly towards the separate property, just because it groups the functionality slightly better with the associated functionality of overflow, and reads slightly better imo. (I can't come up with a good keyword that would real well in a general interactivity property.)

@bramus
Copy link
Contributor

bramus commented Aug 20, 2024

+1 on what Tab said there. Option 2 is a no-brainer for authors, while option 1 can be handy for authors who want fine control over things.

For example: adjusting the insets could be considered something exclusively for option 1. Although, that could also make the case for a overflow-interactivity-insets property 🤔

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-ui] Support setting offscreen content inert.

The full IRC log of that discussion <matthieud> flackr: many website designs when creating paginated stuff or when the site provide an alternative to a long scrolling document, the recommended practice is that content outside of the viewport is inert
<matthieud> flackr: you dont have the content in your accessibility tree
<matthieud> flackr: it can be done with display:none but not very good
<matthieud> flackr: you can do aria:hidden as html attribute so need a script as you progress animation
<matthieud> flackr: new simple way to say "content out of view is inert"
<matthieud> flackr: we could either assign this on the scroller (overflow) or on the element itself ?
<emilio> q+
<matthieud> astearns: the default value for overflow-interactivity is auto in option 2
<astearns> ack emilio
<astearns> zakim, open queue
<Zakim> ok, astearns, the speaker queue is open
<kizu> q+
<matthieud> emilio: Is overflow the only place we want to support this use-case ?
<matthieud> emilio: author might want this for stuff in the screen
<PaulG> q+
<matthieud> flackr: similar usecases to animate to/from content not the accessibility. Option 1 would allow that because its not tight to overflow
<ntim> q+
<matthieud> Option 1 has added complexity but you cant select offscreen content with a simple selector today, so for the scrolling usecase you would have to animate the interactivity property with a view timeline or something
<astearns> ack kizu
<matthieud> kizu: Option 2 is nice. option 1 is powerful but limited
<emilio> q+
<matthieud> kizu: always risk to break accessiblity with all options : if we apply this to an element but cant reach it without scrolling, accessiblity will be broken
<matthieud> kizu: because it's inert you would only be able to scroll to it, cant reach it in any other way
<matthieud> kizu: Option 2 is safer because tight to scrollable container
<astearns> s/tight/tied/
<astearns> ack PaulG
<matthieud> PaulG: Like kizu, in a listbox with item overflowed. Does the engine will give the correct number of items to the accesssiblity tree when some of them are inert ?
<matthieud> flackr: nice question. maybe inert is not the property we want to use then
<matthieud> PaulG: maybe inert is fine but not for this scenario. We need to clarify the exact use cases
<matthieud> flackr: we dont want to use this when user want to interact with this content
<TabAtkins> I'm feeling like this is indeed a "well don't do that" situation
<matthieud> flackr: it doesnt make sense to use this for overflowing tabs in a tab list for example
<matthieud> flackr: so maybe inert is not what we want
<astearns> ack ntim
<matthieud> ntim: controlling inert from CSS was originally objected against
<matthieud> ntim: inert is not only about presentation but also about content
<matthieud> ntim: because it applies aria-hidden
<emilio> q
<matthieud> flackr: display already does stuff on aria tree even if it is a css property
<astearns> ack emilio
<matthieud> emilio: for firefox tab bar, we want tab hidden but still remain in the accessibility tree. So we dont really want inert
<matthieud> does this only apply to scroller ? or also to overflow-path or clip ?
<emilio> s/overflow-path/clip-path/
<matthieud> kizu: for clip it should not work
<matthieud> kizu: for hidden not sure
<matthieud> flackr: for hidden many time people make it scrollable with other mechanism
<matthieud> emilio: we are not sure if we want actual inertness here
<matthieud> flackr: we can take it back to the issue
<matthieud> astearns: please comment on the issue

@astearns astearns removed the Agenda+ label Aug 21, 2024
@flackr
Copy link
Contributor Author

flackr commented Aug 21, 2024

@nt1m This is the previous resolution I am aware of where we decided to not have an inert property yet #7021 (comment). Let me know if there's another discussion we should also link into this issue.

From the final lines of the discussion that the main reason we didn't pursue it then was because we didn't have the specific strong use cases for which it was very useful / important:

Rossen: Does anyone object to waiting until better use cases or louder voices appear?
RESOLVED: Will not add an inertness property for now.

@nt1m
Copy link
Member

nt1m commented Aug 21, 2024

That was not the only discussion, there's a bunch of discussion on other PRs. I'm thinking of the multiple HTML PRs where inert tried to be added:

etc. etc. inert has a long history, so it would be good to check with web a11y experts before moving forward.

@flackr
Copy link
Contributor Author

flackr commented Aug 22, 2024

That was not the only discussion, there's a bunch of discussion on other PRs. I'm thinking of the multiple HTML PRs where inert tried to be added:

@nt1m Thanks for the context! I'm not sure I understand the root of your concern here. The linked issues are about spec'ing the HTML attribute. Are you saying that because we are moving towards defining inert in HTML it can't also be controlled by CSS? IMO having inertness in CSS does not preclude also having an attribute. E.g. the attribute can be explained by having a UA stylesheet rule:

[inert] {
  interactivity: inert;
}

Then the computed inert value is usually based on the attribute but can be overridden. Alternately it could be a !important rule to not allow overriding.

This is the only issue which makes mention of the possibility of it being controlled by CSS as far as I can see. In particular @othermaciej presented an argument against it being in CSS in WICG/inert#69 (comment) which I'll respond to here given the proposal here is not intended to replace the inert attribute but to extend it with CSS stylability.

Caveat: some personal opinions I haven't discussed with the team. I don't think inert would be better expressed in CSS. CSS is about presentation, not behavior. Stuff like user-select and -webkit-user-modify seems in retrospect kind of regrettable.

As a counter-point, display: none also inerts content. IMO, this sets a strong precedent that the presentation (style) of content does affect what should be visible in the accessibility tree. This is even used by the ARIA authoring carousel tutorials 1 and 2 (linked in the OP as well) as follows:

.carousel-item {
    display: none; /* "Styles" items inert by default */
}
item.active {
    display: block; /* The active item is interactive */
}

Also, the inability to escape inert from within a subtree seems like a feature not a bug. An inert CSS property would not be sufficient for implementing dialog either, both because of the ability to escape, and because dialog also includes novel stacking behavior.

This is not incompatible with a CSS inertness property. We have examples of both properties which can escape (e.g. pointer-events: none, visibility: hidden, and properties which can't escape display: none, contain: strict, touch-action: none). Typically properties which can't escape are not inherited, instead implying their state affects their entire subtree just as the inert attribute does. That being said, I could see there being an advantage to being able to escape inertness being able to explain and allow authoring experiences similar to dialog without needing to explicitly use dialog or other top layer APIs.

it would be good to check with web a11y experts before moving forward.

Happy to loop in a11y experts to the discussion. The intention is to make it easier for authors to meet the guidelines set out as best practices by the ARIA Authoring Practices Guide. Given that these guidelines already make use of display: none to inert inactive content it seems reasonable that authors should also be able to easily content in situations where it is not meant to be accessed currently - e.g. needs to be visible in order to animate in.

@flackr
Copy link
Contributor Author

flackr commented Aug 22, 2024

From #10711 (comment)

PaulG: Like kizu, in a listbox with item overflowed. Does the engine will give the correct number of items to the accesssiblity tree when some of them are inert ?

@AutoSponge I have since tested this and found that all of inert, aria-hidden and display: none have the same effect of reducing the item count. Given using one of these on inactive tabs / carousel slides is the recommended practice from the ARIA APG guidelines for the primary use cases this API is trying to address, I'm inclined to say this is working as intended and we should advise against using this in cases where the entire list should be announced.

@flackr
Copy link
Contributor Author

flackr commented Aug 22, 2024

From #10711 (comment)

emilio: Is overflow the only place we want to support this use-case ?
emilio: author might want this for stuff in the screen

@emilio I think that fundamentally there are two shapes this property could take represented by options 1 and 2. In the first case the author explicitly styles which things are inert, and in the latter they apply a style that tries to automate when things need to change states for them.

As @tabatkins mentioned they're not necessarily mutually exclusive, but option 2 is trying to handle the common easily detectable cases. If you have any thoughts for things we might be able to do to cover the other use cases you mentioned in an automated way i'd welcome improvements to how option 2 works, but the general question of whether something is visible seems non-trivial to compute.

If it's not automatically detectable then it would require a solution like option 1 where the author styles the content inert regardless of its location. If we don't also have an automated option then this adds an additional burden on developers creating scrolling experiences to ensure that they have some way of updating this as the user scrolls changing the current content.

@jcsteh
Copy link

jcsteh commented Aug 23, 2024

From an accessibility perspective, my concerns with this are exactly the same as they were for the inert HTML attribute. They are perhaps stronger concerns here because CSS has (at least historically) been primarily associated with presentation, not semantics, so the chances of someone doing this without considering semantics are higher.

The risk here is that someone will use this for some unintended semantic purpose where the content is actually semantically relevant but ends up being hidden from a11y APIs. This is particularly problematic for the CSS inertness property (proposed option 1), probably a bit less so for the other proposed options. The impact of this risk is very severe because this content would be entirely inaccessible to some users with absolutely no recourse.

For HTML, this was addressed by adding clear, firm, normative guidance about when it is inappropriate to use inert. If something like this is added to CSS, I think it is critical that similar normative guidance is included. I understand there may be reluctance to do this given that CSS is primarily associated with presentation, but since this has such a severe impact on semantics, I think omitting such guidance could be very harmful for accessibility.

@flackr
Copy link
Contributor Author

flackr commented Aug 23, 2024

Thanks for the context @jcsteh, this makes sense. I agree that we should at minimum have strong guidance on how to use this to avoid its misuse. Options based on 2 would nicely ensure that content that a11y APIs can see the same content that sighted users can. I'd be interested to determine to what extent we might be able to automatically infer the other use cases @emilio had in mind. E.g. we could also apply inertness on other common cues like opacity: 0 or visibility: hidden though either of these has challenges:

  • At what opacity is something considered no longer visible?
  • visibility: hidden can be overridden in a subtree so you'd have to ensure that visible content within is not inert.

It's worth noting that our resolution in #8389 technically allows making content inert via CSS (demo):

.inert {
  /* Immediately starts a transition to display: none */
  transition: display 10000000s allow-discrete;
  /* Since the underlying display value is none, this is treated as inert per resolution in #8389 */
  display: none;
  
  @starting-style {
    /* Starts visible to trigger the transition. */
    display: block;
  }
}

I think that we should try for an automatic mechanism to the extent we can detect visible content (option 2). I'm open to suggestions for how to recognize other cases where developers want to have displayed content that is not meant to be seen or interacted with.

@flackr
Copy link
Contributor Author

flackr commented Aug 26, 2024

From #10711 (comment)

If it's not automatically detectable then it would require a solution like option 1

@emilio can you comment as to whether there are other signals for detecting elements that are not visible on screen which could allow us to automatically handle the use case you had in mind? Do you think this Is something that we could upgrade the API with if we thought of ways to detect content not being visible similar to it being clipped by an overflow scroller?

@aleventhal
Copy link

From a high level I don't see anything harmful about having inertness available in CSS.

It's worth having a discussion on whether it can be undone in a subtree somehow. To me that is beneficial. I don't see any major downside that would be bigger than the benefit of allowing that.

@scottaohara
Copy link
Member

scottaohara commented Aug 26, 2024

is visibility: inert a possibility? does this need to be its own property? just curious. visibility: hidden already completely removes content from the a11y tree. but often inert content doesn't need to be 100% hidden (though per the guidance I helped add to the HTML spec, we would generally want some visual indicator that the content is not currently meant to be accessible). So a default UA style of some lower level opacity/transparency would probably be good (and then allow authors to override this as needed ).

i'd be warry of doing anything with opacity: 0 and inertness. i know there's plenty of instances of opacity: 0 in the wild which are being used for visually hidden content that is not meant to be hidden to AT. Making that content inert would likely break a lot of websites.

also agree with aaron that generally i think applying inertness with CSS could be handy. it'd make some UI a lot easier to build due to the lack of inert=false with the HTML attribute.

the only worry i have with that is inadvertently making content not inert when it really should have been. e.g., marking an element as not inert with CSS which makes sense for that component/in the normal document flow - but then a user invokes a modal dialog. Does that content become inert, stay not inert? Maybe if a modal dialog exists in the top layer, any document-level not-inert content becomes inert. But if someone needed a modal dialog AND a notification popover, well that popover is in the top layer now, and if it was marked as being not-inert, then could help solve stuff like whatwg/html#9936

@flackr
Copy link
Contributor Author

flackr commented Sep 4, 2024

is visibility: inert a possibility? does this need to be its own property? just curious. visibility: hidden already completely removes content from the a11y tree. but often inert content doesn't need to be 100% hidden

Yup, this is definitely a possible form for option 1!

(though per the guidance I helped at to the HTML spec, we would generally want some visual indicator that the content is not currently meant to be accessible). So a default UA style of some lower level opacity/transparency would probably be good (and then allow authors to override this as needed ).

This is a nice idea, were you thinking that it would actually use opacity, or change the color to have some transparency?

Using opacity is a bit tricky since it implicitly affects the way all descendants paint. E.g.

<style>
  section:not(.active), .inert {
    visibility: inert;
  }
</style>
<section>
  <p>This is some <i>inert</i> content</p>
  <div class="inert">
    <p>This content is also inert</p>
  </div>
</section>

If visibility implies / sets opacity: 0.5, does it also apply it to those elements inheriting visibility? If so, you'd end up with the <p> having an effective 25% opacity, and the inner <i> having 12.5% opacity. Even if we had a mechanism to only set it when you explicitly set visibility: inert it would probably be surprising that nested inert content is even more transparent. The other issue here is that if we allow making some subtree not inert you'd like it to have full opacity.

As such, I think changing the transparency on the color makes more sense, as it doesn't make its descendants even more transparent and can be easily undone in a visibility: visible subtree.

i'd be warry of doing anything with opacity: 0 and inertness. i know there's plenty of instances of opacity: 0 in the wild which are being used for visually hidden content that is not meant to be hidden to AT. Making that content inert would likely break a lot of websites.

+1 I agree. We should avoid this as a trigger.

the only worry i have with that is inadvertently making content not inert when it really should have been. e.g., marking an element as not inert with CSS which makes sense for that component/in the normal document flow - but then a user invokes a modal dialog. Does that content become inert, stay not inert? Maybe if a modal dialog exists in the top layer, any document-level not-inert content becomes inert. But if someone needed a modal dialog AND a notification popover, well that popover is in the top layer now, and if it was marked as being not-inert, then could help solve stuff like whatwg/html#9936

I think the computed inertness should probably take into account more than just this property. E.g. maybe you wouldn't be able to undo inertness when it had been set by the HTML mechanism or dialog.

@scottaohara
Copy link
Member

This is a nice idea, were you thinking that it would actually use opacity, or change the color to have some transparency?

i was just thinking in general - i wasn't trying to imply it should necessarily be opacity, and i think your rational is a good reason as to why that wouldn't be the best way forward. So long as any content of the inert container can be made to look dimmed in some way (text and graphics) then that sounds like a win to me. If only color transparency can be modified, then that makes me wonder if graphics would appear dimmed or not. maybe not the worst thing if they aren't / leave it up to the authors to do that themselves using whatever they see fit.

I think the computed inertness should probably take into account more than just this property.

fair. just trying to provide an example of where this could be helpful / where there is no way to un-inert such content with HTML alone.

@flackr
Copy link
Contributor Author

flackr commented Sep 9, 2024

From the discussions from a11y experts I'm hearing some good arguments for augmenting visibility. Proposal:

visibility: hidden | inert | visible;

This would:

  • inherit as per usual.
  • could be overridden in a subtree to make some subtree not inert.
  • ideally have a default UA style to make it visually evident that it was inert. I'm open to suggestions on how this could be achieved - naively thinking that we could have the computed inherited color gain some transparency from its non-inert ancestor - though I'm not sure if this could easily be undone by a subtree and it would have limitations such as not affecting graphics as @scottaohara called out.

@nt1m
Copy link
Member

nt1m commented Sep 9, 2024

I wonder how backwards compatible that is if we make the HTML attribute use that.

Existing code that uses visibility along with inert would change behavior potentially

@flackr
Copy link
Contributor Author

flackr commented Sep 9, 2024

I suspect the computed inertness would have to enforce inertness implied by the html attribute, so you could only uninert content made inert by visibility: inert.

@nt1m
Copy link
Member

nt1m commented Sep 9, 2024

Ideally you'd be able to define HTML inertness in terms of UA styles if we introduce something like this

aarongable pushed a commit to chromium/chromium that referenced this issue Sep 12, 2024
Experimental prototype based on the proposal in [1]

[1] w3c/csswg-drafts#10711 (comment)

Change-Id: Ifa7e3923b84cdf4c252d2fade18aaa2b0c3bbc9c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5850197
Commit-Queue: Rune Lillesveen <futhark@chromium.org>
Reviewed-by: Anders Hartvoll Ruud <andruud@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1354394}
@astearns astearns moved this to TPAC agenda items in CSSWG Agenda TPAC 2024 Sep 13, 2024
@flackr
Copy link
Contributor Author

flackr commented Sep 18, 2024

Ideally you'd be able to define HTML inertness in terms of UA styles if we introduce something like this

We could certainly try to define HTML inertness as a UA stylesheet rule:

[inert] {
  visibility: inert;
}

We would need to measure how often sites are specifically adding visibility: visible within inert subtrees today to get an idea how much existing content would change. One of the advantages of using a new property would be that we could do this without existing content changing.

We might still want an exception for the dialog case to be unable to remove inertness outside of the modal dialog, though I don't think this breaks specifying HTML inert in terms of CSS inertness.

@kizu
Copy link
Member

kizu commented Sep 18, 2024

We would need to measure how often sites are specifically adding visibility: visible within inert subtrees today to get an idea how much existing content would change.

I'm afraid there could be a lot: very often authors implement some toggles visibility by assigning both visibility: hidden and visibility: visible as two alternate states, without knowing how visibility actually works. I encountered many times in practice bugs about this, and wrote a post about it ~2 years ago: https://kizu.dev/restoring-visibility/

That said, the combination of this with the inert attribute could happen not that often, but this is still something I expect authors could stumble upon.

@alice
Copy link

alice commented Sep 18, 2024

I came across this issue more or less by chance, but nevertheless I have some thoughts, having been involved in the resurrection of the inert attribute.

I think (at least) two things have become conflated here that I'd like to argue should be kept separate:

  1. Should it be possible to make content inert using CSS properties?
  2. Should it be possible to escape inert? And/or how should inert-ness be inherited?

I do think there is probably a good argument to be made for being able to make content inert using CSS properties, and I think the example in the issue description is somewhat compelling. I'm not personally sold on the idea of being able to do things purely in CSS as a good in itself, having seen more that one well-intentioned attempt to implement things without javascript which resulted in an inaccessible experience. I do think, however, that making it more convenient to do the "right thing" makes it more likely that developers will... do that. I like the example in the issue description because it seems like the type of case where applying the attribute might be fragile if done in script, but is a couple of lines of CSS which should be easy to test and maintain. I think the "option 2" proposal seems to be the most convenient way to solve the specific problem laid out here, to that end.

I'm hesitant on the question of whether it should be possible to "un-inert" content. We went back and forth on this with the attribute as well, I think, and landed on the current behaviour partly for HTML boolean attribute reasons, but also partly because we didn't want to have authors accidentally or deliberately escaping inert and degrading the user experience.

I have a hunch that the main (and possibly only) use case for escaping inertness is to create modal UI. I think that if that is indeed the case, we should be talking about modal UI specifically (for example: does all modal UI belong in the top layer?), and I don't think that having a CSS property which can get into specificity battles (especially when the property in question doesn't necessarily have a visual impact, making it harder to perceive when it's applying) is the right approach.

On that note, I'm also not clear after reading through this issue why this is being prototyped as an extension to visbility. It seems like that has potential for unintended consequences as it interacts with visibility rules with different specificities, plus it seems semantically confusing given inertness isn't a visibility.


Aside: I'm sceptical of arguments along the lines of "CSS already affects interactivity/the accessibility tree, therefore it's invalid to argue this doesn't belong in CSS". CSS affects interactivity and the accessibility tree because it affects presentation. Content in a display: none subtree can't be interacted with because it's essentially not there for anyone: there's nothing there to be a click target, there's nothing to draw a focus ring a round, there's nothing to direct a screen magnifier to. The change to that content's interactivity is a result of the change to its appearance. There's a common misconception that the accessibility tree should theoretically be based purely on the DOM tree. In fact, the accessibility tree is intended to be as faithful a representation as possible of the visible experience, with exceptions as necessary to improve the user experience for AT users. This is because, firstly, AT users (including screen reader users) may well be able to at least partly see the visible experience; and, secondly, because the visible experience is the experience which will almost certainly have been given the most attention by the web page authors.

@flackr
Copy link
Contributor Author

flackr commented Sep 27, 2024

Thanks for the very well thought out response @alice!

I think (at least) two things have become conflated here that I'd like to argue should be kept separate:

  1. Should it be possible to make content inert using CSS properties?
  2. Should it be possible to escape inert? And/or how should inert-ness be inherited?

I do think there is probably a good argument to be made for being able to make content inert using CSS properties, and I think the example in the issue description is somewhat compelling. I'm not personally sold on the idea of being able to do things purely in CSS as a good in itself, having seen more that one well-intentioned attempt to implement things without javascript which resulted in an inaccessible experience. I do think, however, that making it more convenient to do the "right thing" makes it more likely that developers will... do that. I like the example in the issue description because it seems like the type of case where applying the attribute might be fragile if done in script, but is a couple of lines of CSS which should be easy to test and maintain. I think the "option 2" proposal seems to be the most convenient way to solve the specific problem laid out here, to that end.

Agreed! @emilio had concerns that while this solved the particular use case, it wasn't generic enough to help with situations where the content was not accessible for other reasons, e.g. I believe being obscured by a foreground tab was the case in their UI. There is something nice about how inerting content outside of the scrollport still allows it to be accessed by scrolling mechanisms, and for this specific use case it is ergonomically much simpler.

I'm hesitant on the question of whether it should be possible to "un-inert" content. We went back and forth on this with the attribute as well, I think, and landed on the current behaviour partly for HTML boolean attribute reasons, but also partly because we didn't want to have authors accidentally or deliberately escaping inert and degrading the user experience.

I have a hunch that the main (and possibly only) use case for escaping inertness is to create modal UI. I think that if that is indeed the case, we should be talking about modal UI specifically (for example: does all modal UI belong in the top layer?), and I don't think that having a CSS property which can get into specificity battles (especially when the property in question doesn't necessarily have a visual impact, making it harder to perceive when it's applying) is the right approach.

It doesn't need to be a specificity battle, I suspect even if we did allow authors to escape inert, we would only want to allow it to escape the author applied inertness and not extend to cases such as modal dialogs.

On that note, I'm also not clear after reading through this issue why this is being prototyped as an extension to visbility. It seems like that has potential for unintended consequences as it interacts with visibility rules with different specificities, plus it seems semantically confusing given inertness isn't a visibility.

This was pursuing @scottaohara's suggestion #10711 (comment) to see if this made sense. However, it does prevent us from explaining how the inert attribute works in any other way than computed magic, whereas if we use a new property we can easily explain it by a UA stylesheet

[inert] {
  interactivity: inert;
}

Aside: I'm sceptical of arguments along the lines of "CSS already affects interactivity/the accessibility tree, therefore it's invalid to argue this doesn't belong in CSS". CSS affects interactivity and the accessibility tree because it affects presentation. Content in a display: none subtree can't be interacted with because it's essentially not there for anyone: there's nothing there to be a click target, there's nothing to draw a focus ring a round, there's nothing to direct a screen magnifier to. The change to that content's interactivity is a result of the change to its appearance. There's a common misconception that the accessibility tree should theoretically be based purely on the DOM tree. In fact, the accessibility tree is intended to be as faithful a representation as possible of the visible experience, with exceptions as necessary to improve the user experience for AT users. This is because, firstly, AT users (including screen reader users) may well be able to at least partly see the visible experience; and, secondly, because the visible experience is the experience which will almost certainly have been given the most attention by the web page authors.

Right, I think I've heard the argument construed as only the DOM should affect the tree, so I drew the parallel to these other properties to show that there is at least precedent for CSS affecting it as well. I agree that this doesn't mean it necessarily should. However, as in the OP i'm trying to make it easier for authors to do the right thing in some of these interactive use cases without needing to resort to careful scripting.

Would it make sense for pointer-events: none; to affect the accessibility tree since this content cannot normally be interacted with, at least not directly? I'm not sure if there are use cases where you want to make interactive content that can't be interacted with / targeted by the mouse / touch - it seems like this would be bad practice.

@flackr
Copy link
Contributor Author

flackr commented Sep 27, 2024

I think the options are still fundamentally the same as in the OP. I think that having a CSS property that implies inertness would allow authors an easy way to ensure that the styles of content which is currently decorative / there for animations until activated by some means is nice.

Strawman proposal:

  • Go with option 1, interactivity: auto | inert (name to be bikeshed) as an explicit property can handle other cases where content is intentionally inaccessible (e.g. behind onscreen content / transformed away and meant to be brought into view via some other mechanism).
  • Optionally, to try to ensure that that the property is understood that it makes content inaccessible to @scottaohara's comment [css-ui] Support setting offscreen content inert #10711 (comment) we could have the inherited color be more translucent than the color inherited from, and/or imply hidden to hit tests, i.e. pointer-events: none;
  • To explain how this interacts with the inert property [css-ui] Support setting offscreen content inert #10711 (comment), add a UA stylesheet:
    [inert] { interactivity: inert; }
  • Allow escaping inert, explain modal dialog inertness being unescapable using !important as:
    :root:has(dialog:modal) { interactivity: inert !important; }
    dialog:modal { interactivity: auto !important; }

@scottaohara
Copy link
Member

This was pursuing @scottaohara's suggestion #10711 (comment) to see if this made sense. However, it does prevent us from explaining how the inert attribute works in any other way than computed magic, whereas if we use a new property we can easily explain it by a UA stylesheet

yeah i'm not at all wedded to that suggestion - it just seemed to make some sense to me... but I don't think it matters to expand on that at this point.

re: @alice's comment

I'm hesitant on the question of whether it should be possible to "un-inert" content. We went back and forth on this with the attribute as well, I think, and landed on the current behaviour partly for HTML boolean attribute reasons, but also partly because we didn't want to have authors accidentally or deliberately escaping inert and degrading the user experience.

fwiw, i am absolutely agree with the desire to not have authors willy-nilly escape inertness and degrading what should otherwise be straight forward modal experiences.

I am also totally fine with CSS not being the way to do that. However, there are some legitimate cases where being able to escape inertness (even inertness due to rendering a modal dialog) have been brought up, and it's been frustrating because the use cases can make it difficult, if not prevent, the use of the inert attribute or dialog element.

There are three use cases which I keep encountering / seeing discussion about:

  1. arguably the least 'troublesome' would be teaching/touring UI where the page is mostly dimmed except for the feature being highlighted and a popup/over that describes the feature. Generally the popup wouldn't be modal as someone should be able to see/review the feature that's being described - but the rest of the page needs to/should be inert, which is rather complicated to do with the attribute. There are other ways to do this, but they're often complicated to implement... I generally don't encounter teams willing to put in the effort, so the experience is often less than ideal.
  2. one thing that has been stopping some component libraries i'm aware of from embracing the dialog element for their modal dialogs is because it makes the whole page inert. Not that they don't (mostly) want this - but using it means that their solutions for global messaging / live regions fail because they're often placed at the bottom of the DOM... which becomes inert and thus the live regions fired due to activity in the modal dialog don't actually get exposed to the a11y tree. The ARIA notification API proposal could help some here, but not always...
  3. This use case overlaps with 2 a bit, but again related to modal dialogs that contain UI that invokes reusable component library popups (which some have started to try to convert to popovers). These can include popup notifications (similar to 2, but unique in that they might also contain functionality so simply announcing the content isn't sufficient), or other dynamically populated UI (listbox, menus, etc.) where often the UI is injected at the bottom of the DOM and was positioned with JS to where it needed to show up. Popover makes this a bit easier, but because the popover originates from the inert page, it too is inert.

i personally don't think this topic of being able to escape inertness is out of scope for a feature proposing to introduce inertness with CSS. I'm sorry if this comes across as conflating things, but I see this as an opportunity to resolve these use cases, or maybe get people to think about other more appropriate proposals to do so, if not part of this.

Thanks

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-ui] Support setting offscreen content inert, and agreed to the following:

  • RESOLVED: Accept Option 1 in flackr's latest comment
The full IRC log of that discussion <masonf> +1 thanks
<TabAtkins> flackr: we talked about this previously, there were some open questions and a arequest to talk to a11y folks
<TabAtkins> flackr: i've done both
<astearns> s/"this is what/"this is the *scope* of what/
<TabAtkins> flackr: certainly a controversial area, but i think a11y folks are largely in support of making it easier to match the expected a11y of these use-cases
<TabAtkins> flackr: and i've outline a way in which a property could explain the inert attribute, so we don't have complex interactions between the two
<TabAtkins> flackr: could we pursue the proposed option of adding a new property for this, and the UA stylesheet explaining inertness?
<TabAtkins> https://github.com//issues/10711#issuecomment-2378378364
<TabAtkins> flackr: Option 1, bikeshedding welcome
<emilio> q+
<TabAtkins> chrishtr: Is Scott's comment in line with this?
<TabAtkins> flackr: I believe so, yes, he has some additional comments about how/when you should be able to escape inertness.
<Rossen4> ack emilio
<TabAtkins> emilio: This also affects how browsers implement this
<TabAtkins> flackr: It mostly tracks how browsers implement, but the current proposal has the ability to escape
<TabAtkins> emilio: In Gecko, you can't - we implemented <dialog> stuff without the :has() (it doesn't work with shadow Dom)
<TabAtkins> emilio: we implement escaping the same way
<TabAtkins> emilio: the only reason authors can't escape inert now is because we don't expose the internal property that allows that
<TabAtkins> emilio: exposing it contradicts some of the discussions a while ago when this was being discussed. I'm personally okay with it, tho.
<TabAtkins> emilio: part of the reasoning to not expose to CSS was a lack of use-cases, but it seems there are some
<chrishtr> q?
<TabAtkins> Rossen4: so back to the original proposal, Option 1.
<TabAtkins> Rossen4: Objections?
<TabAtkins> emilio: to clarify, this is inherited?
<TabAtkins> flackr: yes
<TabAtkins> emilio: okay, instead of doing wonky pseudo-inheritance
<TabAtkins> RESOLVED: Accept Option 1 in flackr's latest comment

@tabatkins
Copy link
Member

tabatkins commented Nov 11, 2024

In #11178 I've drafted up the text for 'interactivity'. I ended up having to make it not, technically, an inherited property; if we want to make it so that the 'inert' attribute is explained in terms of the property, then it needs to "inherit" down the flat tree, not the DOM tree. So instead, the initial 'auto' value just matches the inertness of the flat-tree parent node; an explicit "normal" and "inert" explicitly turns inertness off or on for a given node. lol never mind, I completely forgot that inheritance already works on the flat tree. Back to being an ordinary inherited proeprty.

I also have a suggested UA stylesheet rule to move the 'inert' attribute behavior over to CSS; it applies inert !important;, so it wins over CSS declarations, which I think we agreed on. It needs to use @scope to get a lower boundary so elements that are "exempt" from inertness (like modal dialogs) can go back to normal.

(Ah, I just realized that those elements need to set a non-important "normal" so they'll turn off inertness; otherwise the auto behavior will still make them inert.) Done.

@emilio
Copy link
Collaborator

emilio commented Nov 11, 2024

@tabatkins I'm confused: inert the attribute works on the flat tree, and so does inheritance, so not sure why it can't be a regular inherited property?

@tabatkins
Copy link
Member

@emilio Yup, I just forgot how inheritance works.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Friday morning
Development

No branches or pull requests