Skip to content

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

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

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

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

flackr opened this issue Aug 7, 2024 · 44 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.

@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.

tabatkins added a commit that referenced this issue Jan 23, 2025
* [css-ui-4] Add 'interactivity' property, per #10711

* [css-ui-4] Sigh, inheritance *does* work on the flat tree, I'm dumb.

* [css-ui-4] Ensure 'interactivity' can make things inert, but can't *escape* inertness; defer more to the host language.
@mayank99
Copy link

mayank99 commented Mar 15, 2025

For anyone else following this issue, there has been some activity in w3ctag/design-reviews#1055.

I would recommend reading at least these four comments:

  1. @alice's original concern above: [css-ui] Support setting offscreen content inert #10711 (comment).
  2. @scottaohara's list of valid use-cases above: [css-ui] Support setting offscreen content inert #10711 (comment).
  3. @alice's top-layer idea potentially addressing those use-cases: [css-ui-4] Add 'interactivity' property, per #10711 #11178 (comment).
  4. @matatk's comment on the TAG review: CSS inert w3ctag/design-reviews#1055 (comment).

Also, I was surprised to see that interactivity is intended to ship in Chrome 135. Given all the pending discussions, I think it should be delayed.

@argyleink
Copy link
Contributor

https://silkhq.co - creator https://x.com/brunostasse
the following are notes from conversations with them:

When asked why they didnt use popover or dialog, the response was a set of use cases that CSS interactivity would be the right fit for.

Issues with inert:

  1. It's often too strong, similar to shadowDOM, where exceptions become difficult because the value of the feature is to not make exceptions
  2. Javascript required to toggle, or in complex cases, javascript to walk trees and conditionally apply (something css selectors would easily do)
  3. There's often needs for setting inert to a subtree and being able to create holes in it (what the author call islands of interactivity in Silk), or we may call "donut inert" with CSS interactivity

Use cases for consideration to the group:

  1. ParallaxPage - "the whole document is inert, but not the content of the ParallaxPage, and not the content of the top bar (which was present before opening the page). This is complicated to get with inert because you have to walk the whole tree to add it exactly where you need so the precise elements you need to remain interactive are not wrapped in it. Consider an inert-outside feature? Ideally you'd be able to set it to several elements, and they would be the only elements you can interact with on the page. It's better than having to set inert at the top level, because to do that declaratively you need a top level html element."
  2. Stack Management: “I also may want to open sheets on the page without making them front most, like adding cards in the back of a stack. With these API they would end up at the front of the stack. I don't yet handle this feature by I want in the future”
  3. A dialog being shown but you want to keep the primary nav bar interactive (i guess suggest using popover?)
  4. Integration with 3rd party libs: “These APIs also don't work well with third party overlay, like browser extensions; they can’t be accessed if they don't use the new primitives as well”.
  5. "I also have a use case where I need inert > interactivity > inert > interactivity. That's a bottom sheet which itself contains a page. It should be inert outside the bottom sheet, then inert inside of the content part of the bottom sheet, but not its top bar, and then interactive inside of the page."

So this is all even trickier when you stack pages, sheets, etc. A lot of scenarios are possible.

Having it in CSS would be very useful to be able to set it based on media/container queries and other selectors on first render.

Everything is better in CSS anyway because of this reason. HTML don't have queries and selectors, so it requires JS for everything.

<end of Bruno's comments />

Dialog that's been shown modally but a notification/toast comes in…. Inert causing people to do wierd stuff to make the UX work

We're seeing very slow adoption for Dialog because of both inert complexity of when it's the right choice, it's power, the lack of easy stacking of multiple items in the top layer and the lack of library adoption. The biggest issue tending to be inert, and folks feeling timid or not knowing you can use dialog non-modally, but also, confusion about why and when you need to orchestrate all this focus. Next biggest is that in your app, if you put 1 thing in the top layer, you tend to have to start putting everything that overlays in a top layer: aka, it doesnt have a good slow adoption story, it's you either put all things in there (tooltips that need to show on top of a modal dialog, multi-layering partial views that open other partial views, etc)

There's also the use case difference between inert and interactivity, where interactivity isnt a CSS replacement of inert, it offers subtly different results which are helpful to authors who are well intentioned and orchestrating lots of dynamic focus moments (like with Silk and many of it's demos).

For CSS overflow markers:
Being able to "un-inert" the interactivity is paramount so that the offscreen content (cards or whatever) is marked as not being interactive (this allows the keyboard to flyover a long list of interactive items), but the ::scroll-marker generated for it inherits the non-interactivity thus becoming a dot that can't be clicked or interacted with. The fix is to ensure restore interactivity for the markers 👍🏻 then, users can click or use the keyboard in the dots, which scroll content into view and when it's in view it's interactive. boom, it's a very healthy relationship, all relating to "scroll affordances" as provided by the markers which help aid content discovery and provide hints as to the size of the content in the scroller.

there's a lot of folks out there with very good intent on shipping meaningful keyboard and screen reader interactions who are struggling with the current tools.

tldr;

  • adoption from beautiful libraries is low because the current feature is both strong and rough to juggle
  • folks need an escape hatch so they can ensure interactive content is accessible during complex multi-moment overlays are happening
  • css interactivity provides the flexibility and adaptiveness that authors are looking for so they can provide meaningful focus and keyboard experiences
  • css markers are a great use case of when you have complex conditional interactivity desires and how a css driven interactivity feature (not necessarily a css inert feature) arent just valuable but required

@alice
Copy link

alice commented Mar 31, 2025

I need to step away from this for a bit; it's been exceptionally stressful trying to engage on this topic when there doesn't appear to be a genuine effort made to understand and engage with (not just rebut) the feedback others and I are giving on accessibility.

Some brief thoughts, however:

  • HTML inert was never meant to be a one size fits all solution.
  • However, it was designed carefully to try and mitigate the worst accessibility risks.
  • A one size fits all solution is most likely not a good idea; solutions more tailored to specific problems are going to be easier to reason about regarding trade-offs, easier to design in such a way that they match up with the desired visual appearance in each case, and less likely to come with the type of accessibility risks we're seeing here.
  • Anything which impacts the accessibility tree without impacting visual appearance needs to be very, very carefully approached, and that care has absolutely been and continues to be absent here.
  • This is doubly true in the context of CSS, which is a truly brilliant system which was specifically designed for changing the visual appearance of HTML content.
  • Yes, this is still true even when the property in questions impacts interactivity.
  • The name interactivity doesn't even make clear that it will affect the accessibility tree, just for starters.
  • Just because content isn't interactive doesn't mean it isn't critical, and an author might even deliberately make critical content non-interactive for similar reasons to why authors make content user-select: none.
  • Consider how this may be misused by authors who aren't "well intentioned" or who are even "well intentioned but in a hurry/ignorant/misguided" and/or lack accessibility testing resources.
  • Consider the unintended use cases as well as the intended ones. What might authors use this for "off-label" without fully understanding the implications?
  • Consider how this may be misused in AI-generated code.
  • A note in the CSS spec can and likely will be ignored by the vast majority of authors.
  • This is likewise true for the best written CSS Tricks or web.dev article.
  • Authors will learn primarily through trial and error, and their trial will absolutely not, in the majority of cases, include testing with assistive technology or, in all likelihood, the keyboard.
  • Actively pushing authors away from rather than towards carefully designed native options like <dialog> and popover seems like a regressive move, especially for accessibility.
  • Please, please, please slow down and listen to what others are saying about the accessibility risks.

(I'm copy-pasting this comment in a few places because this conversation has been so widely distributed. I apologise for the noise.)

@patrickhlauke
Copy link
Member

Nothing to add other than echoing @alice 's concerns here. There seems to be a lot of hurried movement on this, when it should be much more carefully considered for accessibility.

@bkardell
Copy link
Contributor

bkardell commented Apr 2, 2025

I would really like to echo to the call to consider the concerns raised by a large number of people now... I think we could schedule a special joint breakout session on this @astearns ?

I'd also like to link openui/open-ui#559 as I think that some of the things discussed there are applicable here too. In other words, It seems very probable to me that the more complex use cases (those which couldn't be met by just doing the thing everyone was much more comfortable with) are actually just "similar" in some ways, but probable not "the same" and require a lot more?

@scottaohara
Copy link
Member

scottaohara commented Apr 3, 2025

+1 to @alice's post.

Some responses to @flackr's comment.

First regarding the 3 points raised:

  1. Peaking UI remains a strong case for a version of this feature. (emphasis added because I continue to believe there are use cases that need to be solved, but not at the expense of the larger concerns being raised)
  2. I doubt the strength of this second use case. As I understand it you're talking about something like this HTML inert example. Often the reason for needing such UI is because the underlying content is temporarily blocked, or is in a loading state. Revealing that content would often require a user action, or for content to finish loading, and the DOM be modified. Using the HTML inert attribute would likely be the better call here since the DOM would have to be modified, if not entirely replaced, anyway. I'd be open to understanding this use case more, particularly if a compelling example could be provided to demonstrate why CSS would be the preferred option. But right now, I struggle to imagine a scenario where doing this with CSS (but also likely still needing JS) would be better for the developer.
  3. For the last point, I have little doubt in saying CSS would be the wrong choice, or if inert (css or html) is even needed or appropriate at all (e.g., background images which are already not in the a11y tree, or img elements which can already be set to presentational with an empty alt). Just taking the linked 'matrix' example at face value, if that was used for decorative purposes, then using aria-hidden=true or inert attributes would be far more logical. If it was meant to be conveyed as a demonstration, like it is on that page, then marking it up as a graphic (role=image w/ accName) would be the more appropriate choice. If someone is going to add text to their interface/page that is meant to be incidental - then they should be using markup to make that so. If they are using CSS to add the text, then there's already the alt text feature for CSS content.

Next, regarding:

If you have a paginated experience with many focusable elements, then for that experience you probably want your users to not have to navigate through all of the focusable items that precede it, or those that follow it, to navigate the page.

I can follow this rational for the carousel use case - not wanting to have a user have access to content that is obscured/off screen. That's where the idea of off-screen inert makes sense to me. But where this response lost me was specifically with "to navigate the page" - as this seems like it's opening up the use case for making visible focusable elements of the page inert, beyond the carousel use case.
While I believe the mention of "tabindex=-1 being a footgun" was in the context of simply using it and it alone to mark off-screen content as problematic (because yes, that content would still be available to people using screen readers) I've already had a couple of conversations with people who assumed interactivity could be used as a means to remove any focusable element from the tab order. And that's a problematic interpretation. tabindex=-1 or the disabled attribute can often be far more appropriate for scenarios where content can still be seen, but may not presently be interactive, or at least not meant to be interactive via keyboard (as other ways to achieve the same function may be present). This is a far more nuanced topic though, and I want to avoid a tangent, so I'll leave this here for now...

The part that really stands out to me as needing stronger guardrails and understanding for appropriate use is this comment:

Unlike properties like aria-label, inertness affects non-AT users as well, rendering the content non-interactive for all users. As such we think the risk is much less here than it would be with properties that only affect AT users.

I think this speaks to @alice's point that some of the concerns being raised aren't being fully appreciated, at least not consistently. For instance, this particular response doesn't acknowledge that CSS could be misused to make visible / unobscured content inert that isn't interactive - though in a previous codepen it was acknowledged that both editable content and important non-interactive content could be made inert. So, I realize I'm not saying anything here that is new information or incorrectly imply that this isn't a known pitfall. I'm commenting directly on that last statement because it is at odds with the previous demonstration of how this is not just an AT issue. Beyond that example where someone might find something amiss because interactive content can't be clicked/focused - an author could erroneously mark static content as inert and never realize the full impact of that - much in the way people have commonly misused aria-hidden=true and similarly unintentionally hid content that shouldn't have been marked as hidden. In these cases, only people using assistive technology are impacted, because those who can see can still read the content.

For some more context, aria-hidden=true used to be a lot more powerful - completely removing content from the a11y tree with no recourse for the user to mitigate unless they knew how to manipulate markup. Over the years, browsers have had to chipped away at this 'power' due to the constant misuse. As a result, the attribute is no longer allowed to be used or even function if specified on the html or body elements. If focus is found to enter an aria-hidden container, the browser might now undo the hidden state for all the content in that container... which wouldn't be possible with this feature to correct for author error. I mention all of this because it's not clear to me what mitigation for author error a browser could reasonably do, or if this has even been a topic of discussion up to this point. I would hate to see misuse that can't be corrected for - and for a feature like this to need to be whittled down to a safer version - scoped to specific use cases, but it can't be because it's been shipped and changing it could "break the web".

Finally, briefly touching on adam's comment:

Being able to "un-inert" the interactivity is paramount so that the offscreen content (cards or whatever) is marked as not being interactive (this allows the keyboard to flyover a long list of interactive items), but the ::scroll-marker generated for it inherits the non-interactivity thus becoming a dot that can't be clicked or interacted with.

To me this seems more like something the browser should be able to do automatically - rather than leaving it up to the author to have to know to do this. That really seems like an unnecessary requirement for authors, especially since the browser is already performing some magic in generating / slotting these markers, anyway...

That's all I can muster for now.... there are far more points to raise - and even going back and forth on individual use cases isn't really acknowledging all the other use cases none of us have even thought to talk about yet. There is potential to make something really useful here - at least for specific use cases where misuse can be prevented. I just don't want to see this become the aria-hidden of CSS. An incredibly powerful and well-meaning feature that has led to so many problems.

@flackr
Copy link
Contributor Author

flackr commented Apr 25, 2025

Unlike properties like aria-label, inertness affects non-AT users as well, rendering the content non-interactive for all users. As such we think the risk is much less here than it would be with properties that only affect AT users.

I think this speaks to @alice's point that some of the concerns being raised aren't being fully appreciated, at least not consistently. For instance, this particular response doesn't acknowledge that CSS could be misused to make visible / unobscured content inert that isn't interactive

I apologize, I never meant to imply that it was not possible to misuse, and as you have noted I have myself written examples of how the ability to inert (in the forms we have it and in the forms we may introduce it) can be misused in a way that could go overlooked. In this statement, I was only contrasting it with properties which have absolutely no effect for non AT users. In particular, making content inert means that it cannot be interacted with, the text cannot be selected or found by find in page, and the content can never be the target of any input events, meaning that it is more likely a developer or users who are not specifically using AT will catch these misuses. I fully acknowledge that it is possible to misuse in a way that could be overlooked by typical user flows.

In the interest of completeness, there are also many ways for developers to misuse css properties to hide content in ways that do not remove it from the AT tree resulting in confusing extra content (e.g. opacity: 0, transform: translateX(-100%) in a clipping container, etc).

(I'm copy-pasting this comment in a few places because this conversation has been so widely distributed. I apologise for the noise.)

Is this the best place to carry on this conversation? If so, shall we point the other locations to this issue?

I am happy to discuss and provide relevant context related to the many points you have raised in the hopes that it may further advance the conversation.

Being able to "un-inert" the interactivity is paramount so that the offscreen content (cards or whatever) is marked as not being interactive (this allows the keyboard to flyover a long list of interactive items), but the ::scroll-marker generated for it inherits the non-interactivity thus becoming a dot that can't be clicked or interacted with.

To me this seems more like something the browser should be able to do automatically - rather than leaving it up to the author to have to know to do this. That really seems like an unnecessary requirement for authors, especially since the browser is already performing some magic in generating / slotting these markers, anyway...

I completely agree, and we resolved on the fix for this in #11746 and have updated the chromium implementation accordingly.

@flackr
Copy link
Contributor Author

flackr commented Apr 25, 2025

The ability to escape inertness has been identified as a risk and confusing deviation from the capability of HTML inert. While there are use cases for this, we think that out of caution it would be safer to align with HTML inert for the currently specifiable inert value until we have time to carefully work through how best to address uninerting use cases. If we are agreed on this point, it seems to me that this should no longer be an inherited property. Adding to the agenda to resolve on this.

@flackr flackr added the Agenda+ label Apr 25, 2025
@jantimon
Copy link

jantimon commented May 6, 2025

it seems to me that this should no longer be an inherited property

My concern is that removing the inheritance increases the complexity - developers might implement error-prone workarounds that could actually worsen accessibility rather than improve it

Future "clever" css tricks might be:

html:has(.focus-trap) :where(*, *::before,*::after) {
  interactivity: inert;
}

.focus-trap *,
.focus-trap *::before,
.focus-trap *::after {
  interactivity: auto;
}

@benface
Copy link

benface commented May 6, 2025

@jantimon, I think the point is you wouldn't be able to have interactive donut holes like that. interactivity: inert would make all the descendants inert too (just like the inert property does in HTML), regardless of their interactivity value (hence why it doesn't need to be inherited anymore). In other words, it would work more like display: none (where descendants cannot escape the hiddenness) than visibility: hidden or pointer-events: none.

@jantimon
Copy link

jantimon commented May 6, 2025

@benface thank you that helped

I still believe this idea could have exactly the opposite effect of what's intended and lead to even worse workarounds.

The API won't change the fact that this exact requirement exists on very, very many websites.
That's why there are already many (often buggy) workarounds today that use javascript which set inert attributes

Devs who are asked to implement such a requirement might reach out to a workaround like this:

html:where(:has(.no-inert)) *:where(:not(:has(.no-inert))) {
  interactivity: inert;
}
.no-inert, .no-inert * {
  interactivity: auto;
}

@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: Interactivity does not inherit, and setting it on something that's inert does not change the intertness
The full IRC log of that discussion <dandclark> masonf: There is an HTML spec PR for this
<dandclark> ...It's connecting to CSS concept of interactivity. There have been changes. Part of what's in PR will change
<dandclark> ...it keeps existing behavior for modal dialogs. It allows interactivity keyword in CSS to cause intertness. It explains the existing inter attr in terms of that property
<dandclark> ...allows to you de-inert things.
<dandclark> ...Can exempt subtree to be un-intert. that's expected to change
<dandclark> flackr: We're proposing to discuss not de-inerting anymore. Have the interactivity prop be synonomous with the HTML prop
<dandclark> ...can't escape inertness aside from preexisting dialog semantics (which is internal magic)
<dandclark> flackr: It becomes non-inherited property.
<dandclark> ...The way you determine inertness is once you see inert at any point in tree, applies to all descendants, just like inert attribute
<dandclark> annevk: Why do we need interactivity property?
<dandclark> flackr: So it can be applied dynamically by CSS. Lots of cases where it's useful
<jarhar> dandclark: do we still have a11y folks involed in this conversation?
<jarhar> dandclark: theyre interested in this conversation, i hope theyre still involved
<dandclark> flackr: This has been ongoing discussion
<dandclark> ...you can see in various issues
<dandclark> ...change to interactivity is part of attempt, if we allign with HTML intert prop, it has the same implications as we already have for that
<dandclark> ...nice cleanup, it explains HTML prop like display:none explains hidden property
<dandclark> masonf: This change is a result of those convos
<dandclark> astearns: This seems like a necessary change, but not sure it's suffiient to address all concerns from a11y folks
<dandclark> flackr: Synonymouse with HTML inert
<emilio> q+
<dandclark> ...can argue it can be used more broadly now. But seems prescriptive to tell authors they can't do this with CSS when they can with HTML
<dandclark> astearns: Requires AT to update that it's not just HTML
<dandclark> flackr: This is just a browser thing
<dandclark> masonf: Right, should be exposed to AT in the same way
<astearns> ack emilio
<dandclark> emilio: As part of this work are you chaning HTML inert from being magic to be mapped to CSS prop
<dandclark> masonf: Answer is yes. There is still magic because dialogs get to de-inert things magically
<dandclark> annevk: Will CSS define all the inert logic? Moving that from HTML?
<dandclark> masonf: No, defined in both places
<dandclark> annevk: Hows' that make sense
<dandclark> masonf: HTML spec PR refers to both CSS and HTMl concept of inert
<dandclark> annevk: That' snot what you said before
<dandclark> masonf: You said the concept of ineert, which is defined in both places
<dandclark> masonf: Both mechanisms apply concept of inertnesss to tree
<dandclark> ntim: I think anne is referring to conecept of inertness, not the attribute. Why not move the whole def to CSS?
<dandclark> flackr: It's editorial
<dandclark> ...can define in CSS if that makes more sense
<dandclark> masonf: It's already defined in CSS, but yes let's get the language right, any of these are fine
<masonf> CSS concept: https://drafts.csswg.org/css-ui-4/#inert
<dandclark> annevk: I'm not sure it's editorial. If we move these concepts, we'll have to change a bunch of thigns
<dandclark> ...Then css has to be in charge of interactivity, whether nodes are interactive
<dandclark> masonf: I think it does, pasted link above^
<dandclark> annevk: Identically to what we have in HTML?
<dandclark> masonf: HTML links to that definition
<dandclark> masonf: The behaviors come from CSS
<dandclark> annevk: It's not just editorial. Are the behaviors identical?
<dandclark> masonf: My PR removes some of these defs and refers to CSS
<dandclark> annevk: But not removing the entire concept
<dandclark> annevk: Concept could live in CSS, if identical
<dandclark> masonf: I agree
<dandclark> astearns: Makes sense to ensure we are defining something identical. But editorial in that it's something we need to work through once we decide the design we've got is what we want to move forward with with.
<dandclark> ...whether we have interactivity prop is the more fundamental question, not sure we're there yet
<dandclark> ...Hope this change will address the a11y concerns but need to ensure that's the case
<dandclark> ...We don't yet have resolution to make interactivity not inherit. Can we resolve?
<dandclark> s/Synonymouse/synonymous
<dandclark> emilio: Can we resolve in this meeting?
<dandclark> astearns: Yes, it's joint meeting
<dandclark> annevk: Assumption is that the a11y people not in room agree with this
<dandclark> flackr: It's one of the things that have been identified, is a move in the right direction
<dandclark> ...remaining concern is whether you should be able to set inertness from CSS at all
<dandclark> annevk: Yes that seems separate
<dandclark> astearns: But very relevant
<dandclark> flackr: But you can, with visibility: hidden
<dandclark> Proposed resolution: Make interactivity not inherit.
<RRSAgent> I'm logging. Sorry, nothing found for 'link'
<RRSAgent> I'm logging. Sorry, nothing found for 'logs'
<dandclark> <wordsmithing resolution>
<RRSAgent> I have made the request to generate https://www.w3.org/2025/05/15-css-minutes.html annevk
<dandclark> Proposed resolution: Interactivity does not inherit, and setting it on something that's inert does not change the intertness
<masonf> +1
<flackr> +1
<dandclark> RESOLVED: Interactivity does not inherit, and setting it on something that's inert does not change the intertness
<ntim> s/intert/inert :)
<dandclark> astearns: I know this CSS prop is important to carousel set of proposals. What happens if there isn't interactivity property?
<dandclark> flackr: For a bunch of use cases they'll have to add prop via JS
<dandclark> vmpstr: Or they'll add visibility but that limits the effects you can have
<dandclark> flackr: Visually changes the things that are not current
<dandclark> ...When scrolling, you would see the new contents pop into visibility as it becomes active
<dandclark> ...In many use cases you can peek at next content
<dandclark> ...Interactivity prop supports this
<dandclark> astearns: Can't do this another way?
<dandclark> flackr: Right
<dandclark> astearns: Other questions or comments?
<dandclark> ...before we take it back to issue
<dandclark> masonf: I will update to incorporate the resolution, would like review after that
<dandclark> astearns: And you'll remove special casing for setting things uninert?
<dandclark> masonf: Right
<jarhar> https://github.com/whatwg/html/issues/8189#issuecomment-2877242732

@mayank99
Copy link

mayank99 commented May 15, 2025

Can someone clarify the practical impact of this resolution?

The most recent editor's draft (last updated April 14, 2025) already includes this note:

This property allows an author to force an element inert, but doesn’t allow making an element non-inert, just deferring inertness to the host language.

My understanding is: Previously, interactivity: auto could not undo HTML inertness. With this resolution, the same principle now applies to CSS as well, i.e. interactivity: auto can not undo CSS inertness (except on the same element).

If that is correct, then I think this is a good change!

@rejhgadellaa
Copy link

[...] setting it on something that's inert does not change the intertness

Just to verify, this means <dialog> will be the only way to have an interactive element inside an inert document?

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