Skip to content

[css-display] Interaction gotchas when delaying the effect of display: none #8389

Open
@jakearchibald

Description

@jakearchibald

TL;DR: This is a follow-on from #6429 (comment), which proposes making display animatable, to aid in creating "transition-out" animations.

This issue proposes:

  • Adding an inert property to CSS, and explaining the inert HTML attribute on top of that.
  • Making elements that are animating to display: none inert for the duration of the animation.

Let's say the JavaScript developer on a project creates a dialog/form, and when the form is submitted, the form is hidden via display: none, and the result of the form is used somehow in the app.

Then, at some later point, the CSS developer adds a transition which extends the interactive life of the element beyond what the JavaScript developer expected (the JavaScript developer and CSS developer may be the same person, but their mindset may be different when working with styles vs script).

This can be done already today, by overriding the default display: none on <dialog> elements (https://jsbin.com/xumitir/edit?html,css,js,output), but animating display: none, as proposed in #6429 (comment), creates an even more attractive, less-hacky way to do this.

By doing this, the CSS developer has created a significant change to the behaviour of the app. The user can now provide more than one submission to the form, since its lifetime in the app has been extended. This user action might be intentional (clicking the 'wrong' thing, then quickly clicking the right thing) or unintentional (double clicking).

Additionally, the element exists for longer in the accessibility tree, even though the intention is that it's 'gone'. This would result in unexpected behaviour for screen reader users.

These issues wasn't a possibility when the JavaScript developer created the form, so it's possible that these new interactions will be badly handled. The solution is to cater for interactions with the form beyond its previous lifecycle, or to prevent further interactions and AT visibility of the form using inert.

I think this is worth thinking about for two reasons:

  • It's difficult to catch bugs resulting from this in development. My experience is developers rarely correctly cater for the extended lifetime of interactive elements during transitions-away.
  • The issue is introduced by CSS, and the only way to fix it is in JS (pointer-events: none is an incomplete fix).

Potential solutions:

Education

We tell developers about this problem, and how to solve it in JavaScript. However, I have low confidence that we'd reach everyone, and even when it comes to folks we'd reach, would they remember to avoid these bugs?

Allow inert to be set in CSS

.hide {
  transition: opacity 200ms, display 200ms;
  display: none;
  opacity: 0;
  inert: yes;
}

The current HTML inert attribute could be explained by a UA style:

[inert] {
  inert: yes;
}

I know there was opposition to this in the past, since it relates to behaviour rather than style, but it feels like display: none and particularly transitions on display: none already have a significant impact on behaviour. Showing an element changes the behaviour of the page, and if that's done in CSS, it seems reasonable to be able to express modality via CSS.

Open question: Should it be possible for a child of an inert element to become un-inert? This is possible with pointer-events.

This means that the interactivity issue created by CSS can be solved with CSS. But, it requires the developer to remember to set it, so:

Make elements transitioning to display:none inert by default

.hide {
  transition: opacity 200ms, display 200ms;
  display: none;
  opacity: 0;
}

During the transition above, inert could behave as yes. This would avoid the situation described at the start of this post, where the CSS developer introduced a behaviour the JS developer hadn't catered for.

If the developer wants the element to be interactive during the transition, they can override this default:

.hide {
  transition: opacity 200ms, display 200ms;
  display: none;
  opacity: 0;
  inert: no;
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions