w3c / csswg-drafts

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

[css-animations-2, css-transitions-2] Entry and exit animations for top-layer elements #8189

Closed chrishtr closed 1 year ago

chrishtr commented 1 year ago

Animating an element into and out of the top layer provides context to the user for a more useful and pleasant interaction. Currently, developers have no way to do so in a way that preserves top-layer status during the animation, and as a result, demos like this one won’t work in cases where exiting the top layer causes a visible change of positioning or z-index. Let's fix that.

TL;DR of proposal

Introduce a new CSS property called top-layer that can be targeted by web developers in their CSS transitions and animations.

This CSS property is not generally available to web developers and will always be set with an !important UA style sheet rule. It’s defined as a CSS property for the purpose of a layered definition that fits within existing animations APIs and concepts, and as a result is easy for developers to use with existing animation APIs.

Example: a <dialog> remaining in the top layer during a 200ms opacity animation during close. The part marked as "New!" is the only addition needed for the developer to delay top-layer removal until the end of the animation.

@keyframes open {
  from { opacity: 0; }
  /* Ending at opacity: 1 is implicit, per existing CSS animations spec */
}
dialog:closed {
  opacity: 1; /* UA default */
  animation: open 200ms;
  transition: top-layer 200ms; /* New! */
}
@keyframes close {
  from { display: block; }
 /* Starting from opacity 1 is implicit, per existing CSS animations spec */ 
  to { opacity: 0; }
}
dialog {
  animation: close 200ms;
}

(full demo except for top-layer here)

Details

Use case

This feature enables support for animation when entering or leaving the top layer. Such animations often wish to preserve top-layer rendering during the course of an “exit” or "entry" animation. Without this feature, it is impossible to perform such an animation.

Top-layer APIs: <dialog>, fullscreen, and popover.

Note: The demo in the TL;DR uses CSS animations, but a CSS transition would additionally require this issue to be resolved to be usable for entry transition animations. We also need to support animating display:none for top layer animations that need it, such as <dialog> (tracked here).

Background on the top layer

The top layer is defined here. It is currently accessed only via the Fullscreen API (here) and the <dialog> element’s showModal method (here). When opening a fullscreen element, the fullscreen spec says “add it to its node document’s top layer”. When closing fullscreen, it says “remove it from its node document’s top layer”.

When calling showModal, the <dialog> spec says “add subject [the dialog element] to subject's node document's top layer”. When closing a dialog, it says “If subject is in its Document's top layer, then remove it”. If an element is already in the top layer, re-adding it to the top layer moves it to the top of the top layer.

Proposed Definition of the top-layer CSS property

The top-layer CSS property determines whether an element is in the top layer. It has two values:

top-layer: browser; /* element is in the top layer */
top-layer: none; /* element is not in the top layer */

When an element is “added to the top layer” (see previous section), it is placed in the ordered set of top-layer elements, but the rendering effect of the top layer (putting it in the top-layer stacking context and obeying the rendering order of the ordered set) only applies when top-layer is set.

The element is only removed from the ordered set once top-layer’s computed style has evaluated to none (at the end of the transition, if any). However, the “moved to the top of the top layer” behavior still occurs if the element is “added to the top layer” while animating out (see previous section).

The following UA style rules are added:

dialog {
 top-layer: none !important;
}

dialog:modal:open {
  top-layer: browser !important;
}

:fullscreen {
  top-layer: browser !important;
}

Why shouldn't developers be able to change top-layer outside of transitions?

It’s important to restrict direct developer access because the top layer is a UA-managed resource. Not giving developers direct access guarantees that the UA is able to show top layer content on top of other content, and control eviction from the top layer when needed. This point has been discussed in #6965. If in the future a "developer" top layer is added below the browser one, we could potentially add a third value to top-layer.

andruud commented 1 year ago

I thought the concept of "UA-private except for transitions" seemed odd at first, but I suppose it could be expressed as adding a UA rule (before the other rules):

* {
  top-layer: initial !important;
}
chrishtr commented 1 year ago

I thought the concept of "UA-private except for transitions" seemed odd at first, but I suppose it could be expressed as adding a UA rule (before the other rules):

Good idea! I think this should work, because transitions are at the highest priority of the cascade. It would also avoid introducing a new "UA private" concept, which is a plus.

chrishtr commented 1 year ago

Good idea! I think this should work, because transitions are at the highest priority of the cascade. It would also avoid introducing a new "UA private" concept, which is a plus.

I went ahead and edited the original proposal to remove "UA private" and replace with !important UA style sheet rules. I tested in Chromium and found that transition animations work as expected.

tabatkins commented 1 year ago

...huh. This seems like an incredibly clever hack. I'm not opposed to it!

khushalsagar commented 1 year ago

When an element is “added to the top layer” (see previous section), it is placed in the ordered set of top-layer elements, but the rendering effect of the top layer (putting it in the top-layer stacking context and obeying the rendering order of the ordered set) only applies when top-layer is set.

I'm unclear on the exact effect of adding this element to the the ordered set but not changing its rendering order. There is a set of rules defined here, the change in rendering order (by updating the element's parent stacking context) is part of it. But isn't all of this deferred by the transition property which delays updating the top-layer value?

LeaVerou commented 1 year ago

I thought the concept of "UA-private except for transitions" seemed odd at first, but I suppose it could be expressed as adding a UA rule (before the other rules):

Good idea! I think this should work, because transitions are at the highest priority of the cascade. It would also avoid introducing a new "UA private" concept, which is a plus.

What prevents developers from applying an animation like:

@keyframes foo {
    from, to { top-layer: browser }
}

.foo {
    animation: foo 1s infinite paused both; /* actually any of these keywords by itself works too */
}

to put elements in the top-layer?

emilio commented 1 year ago

@LeaVerou that'd be in the animations, not transition origin.

LeaVerou commented 1 year ago

@emilio Then transition: 999999999s top-layer to make it last forever after a given trigger 🤷🏽‍♀️

My point is that this is a clever hack, but a hack nevertheless, and can be worked around to at least some degree.

css-meeting-bot commented 1 year ago

The CSS Working Group just discussed Entry and Exit Animations for top-layer elements.

The full IRC log of that discussion <fantasai> Topic: Entry and Exit Animations for top-layer elements
<fantasai> github: https://github.com/w3c/csswg-drafts/issues/8189
<fantasai> flackr: When certain elements go in/out of top layer
<fantasai> flackr: if devs want to have an naimation on the, they need the element to remain in the top layer for duration of the animation
<fantasai> flackr: so proposal is that we allow specifying top layer in the transition properties
<fantasai> flackr: but that it's otherwise not a developer-stylable property
<fantasai> flackr: essentially, you can specify transition: top-layer
<fantasai> flackr: and give it a duratoin
<fantasai> flackr: and this is the duration during which the element stays in the top layer
<Rossen_> q?
<ntim> q+
<Rossen_> ack ntim
<fantasai> ntim: I've always been against the top-layer CSS property concept
<fantasai> ntim: The concept should really stay abstracted away from the developer
<fantasai> ntim: even just introducing this property is a bad first step, I think
<lea> q?
<lea> q+
<emilio> q+
<fantasai> lea: I wanted to as ntim why he thinks this concept should be abstracted away from the developer
<fantasai> lea: there's a lot of reasons it should controllable in CSS
<Rossen_> ack lea
<fantasai> lea: we keep seeing use cases that could be solved if could be controlled in CSS
<fantasai> ntim: If you allow controlling top layer with CSS, you end up with same issues as z-index
<fantasai> ntim: the appeal of top layer right now is that it's controlled by order of JS API calls
<lea> q?
<flackr> q+
<fantasai> ntim: but once you start allowing random elements to put top-layer, then what order is actually used in the end?
<fantasai> lea: I think that depends on how we design the feature
<fantasai> lea: maybe it's a property that just the UA controls
<fantasai> lea: though I hope to avoid that
<fantasai> ntim: I think it needs a real design
<fantasai> ntim: just exposing this concept...
<chrishtr> Note that the proposal is not incompatible with ntim's concern. I agree with his concern.
<fantasai> lea: yes, absolutely, does need design work to do it properly to not have problems of z-index
<fantasai> lea: total +1 to that
<lea> q?
<Rossen_> ack emilio
<fantasai> emilio: I don't think I have a strong feeling wrt top layer property
<fantasai> emilio: but basically the use case seems to be transitioning modal dialogs and so on when opening and closing
<fantasai> emilio: and I assume other elements in the top layer
<fantasai> emilio: to me that seems like a use case that non-modal dialogs also need
<fantasai> emilio: there are dialogs that may not be in the top layer
<fantasai> emilio: so feels to me that this is a clever hack to avoid having closing/closed state on the dialog and fullscreen things
<fantasai> emilio: not sure if that's been considered
<fantasai> emilio: so why is this property better
<fantasai> emilio: why not say that it goes from open to non-open, have an intermediate state, and define that intermediat state transition as when all its transitions have finished
<Rossen_> ack flackr
<fantasai> flackr: Wrt tim's concern about exposing top-layer to the user, we have these stackign questions
<fantasai> flackr: this proposal nicely avoids, because things remain in their current stacking position
<fantasai> flackr: so we don't have to change any of that or figure out those definitions yet
<fantasai> flackr: I don't understand what non-modal dialogs have a problem, they can continue to apply their desired z-index
<fantasai> emilio: but you still have the issue of if you want a close animation on a dialog, you need to do it manuall
<Rossen_> q?
<fantasai> flackr: dialog element, which is top-layer?
<fantasai> emilio: dialog may or may not be top layer depending on show vs showModal
<masonf> If the dialog isn't modal, it isn't in the top layer, and you don't need this.
<fantasai> flackr: It would maintain its top layer state during transition, but still have to define the animation
<chrishtr> q+
<fantasai> emilio: idea is you can do opacity or transform or whatever to hide the dialog, right?
<fantasai> emilio: right now that's not easy to do with non-modal dialogs either
<fantasai> emilio: why not have ...
<fantasai> emilio: Firefox has all its panels as well, we have animations when you use menus
<fantasai> emilio: and those are just web elements
<fantasai> emilio: internally we have 5 states
<fantasai> emilio: open, opening, closing, closed
<fantasai> emilio: we ahve intermediate states so that the front end can actually use transitions for this stuff
<fantasai> emilio: my question is, why is this specific to top-layer and not to elements that pop in and out
<fantasai> flackr: you can't reasonably establish entry animations is resolved by setting inital styles
<fantasai> flackr: with that, should be possible to do on non-modal dialogs
<fantasai> flackr: top-layer is the only thing they don't have access to
<fantasai> flackr: the model is consistent with other things taht have a state change trigger an animation
<fantasai> flackr: state changes immediately, even though animation continues to run
<masonf> non-modal dialogs need the ability to animate to/from display:none, but that's a separate issue.
<fantasai> emilio: when non-modal dialog closes, you want to ?? animation to displaY:none
<fantasai> emilio: you transitoin display, which we resolved to do but don't yet do
<fantasai> emilio: so your proposeal would be to animation display directly and also transition opacity
<fantasai> flackr: I have proof of concept for Chrome
<lea> q?
<fantasai> emilio: so this proposal is to explicitly allow z-order to remain while transitioning
<lea> q+
<fantasai> emilio: like transitioning display
<fantasai> emilio: on one hand, I thin it would be less weird to have these intermediate states
<fantasai> emilio: when you open dialog, you transition to opening state
<fantasai> emilio: when you update style and don't have transitions running you're open
<fantasai> emilio: etc.
<fantasai> emilio: when no pending ransitions transition to closed
<fantasai> emilio: only targetted to dialogs/popovers/etc. but I think that's the main use case
<fantasai> emilio: I think that would be slightly less weird for authors
<fantasai> emilio: rather than transitioning display ...
<fantasai> emilio: having magic property seems weird
<fantasai> emilio: I guess this proposal weird, but I think maybe having intermediate pseudo-classes could be more elegant and usable for authors
<fantasai> flackr: I think this is more consistent with other state changes for the Web
<Rossen_> ack fantasai
<fantasai> fantasai: why not have things just stay in the top layer until their transitions are done automatically?
<fantasai> ntim: That seems to make sense
<fantasai> chrishtr: Having a transitioning state and this automatically detect what they're happening and preserve top layer during UA was thoroughly explored during popover design
<fantasai> chrishtr: and prototyped in Chromium
<fantasai> chrishtr: was specific to popover and dialog, and why not have a generic mechanism in animations
<fantasai> chrishtr: this is what lead to these proposals for display:none animations and specifying top-layer duration
<fantasai> chrishtr: without specifying UA magic to detect length of animations
<Rossen_> ack chrishtr
<ntim> q+
<fantasai> chrishtr: discussed at length in popover API proposal
<Rossen_> ack lea
<fantasai> lea: firstly, it seems weird to have a property that only works in transitions
<fantasai> lea: if devs want to put things in the top layer, what prevents them from adding an animation that puts them in the top layer?
<fantasai> emilio: ....
<fantasai> lea: so only available in transitions?
<fantasai> lea: what prevents having a transition that lasts 999999s?
<fantasai> emilio: you'd need to call modal
<fantasai> lea: trying to prevent devs by adding only to transitions, it's a hack and can be worked around
<fantasai> emilio: I agree
<Rossen_> q?
<fantasai> emilio: internally, how we implement top layer
<fantasai> emilio: I'm not sure how I feel about this
<flackr> q+
<fantasai> [missed]
<fantasai> Rossen_: let's end this topic right here
<fantasai> Rossen_: we coered quite a bit, but this doesn't seem ready for resolution
<fantasai> Rossen_: was well articulated and proposed, and good path forward for addressing some of the TAG review comments
<fantasai> Rossen_: shoudl take conversation back to GH, and should bring it back when it's more developed
<flackr> q-
flackr commented 1 year ago

@emilio Then transition: 999999999s top-layer to make it last forever after a given trigger 🤷🏽‍♀️

My point is that this is a clever hack, but a hack nevertheless, and can be worked around to at least some degree.

The browser is still in control of what is in the top layer and its order, which isn't true if exposed as a generic css property. While your example is a hint to the browser that once in the top layer the element should remain in the top layer basically forever, the browser is allowed to still evict it in certain circumstances and can also guarantee that new content shows above the old content (e.g. a new fullscreen element or top layer dialog will go above).

khushalsagar commented 1 year ago

@emilio @LeaVerou I think that problem is gonna stay no matter what solution we take if we acknowledge the use-case. We want developers to be able to keep elements in top layer for the duration of an animation, the length of which should be in developer's control. Whether that happens via :open/:closed pseudo-classes or transition: top-layer, the author is going to be able to keep elements in top layer indefinitely. We could carve out a special duration cap for transitions involving top-layer to address this if needed.

nt1m commented 1 year ago

@chrishtr mentioned that was objection around appending things to top layer during the transition. I believe the objection was more around the :top-layer pseudo and the interactions around it regarding transition (e.g. :top-layer would be matching even when the popup isn't open). Now that the pseudo-class is named :open/:closed, I think this approach can potentially be revisited. (Although feel free to correct me if I'm missing something)

cc @fantasai who brought this up during the call.

nt1m commented 1 year ago

Also, I'd like to re-iterate my objection to exposing the name "top layer" explicitly to the web platform.

These are the reasons why:

If we want to consider exposing top layer to random elements, I think that's a discussion that needs to happen independently, with a proper discussion around naming, before exposing it to the language.

chrishtr commented 1 year ago

Also, I'd like to re-iterate my objection to exposing the name "top layer" explicitly to the web platform.

I think another name would be fine. Any ideas? I'll think on it also...

I think this approach can potentially be revisited

@nt1m I'm not sure which approach you're suggesting could be revisited. Could you clarify?

nt1m commented 1 year ago

I'm not sure which approach you're suggesting could be revisited. Could you clarify?

The one where we append the element in the top layer when the transition starts, and keeping it in the top layer as long as the transition is still running. I originally objected the :top-layer pseudo-class interacting with that bit (since it would be misleading), but now that it's :open/:closed there's a bit more flexibility around this.

nt1m commented 1 year ago

Also, looking at the demo in the first comment, it seems like the issue isn't the top layer itself, but rather the individual adjustments the top layer makes. E.g. this CSS works perfectly:


@keyframes show {
  0% { 
    opacity: 0; 
  }
}

dialog[open] {
  animation: show 400ms;
  visibility: visible;
  /* UA-default opacity: 1; */
}

@keyframes close {
  0% {
    visibility: visible;
  }
  100% {
    /* Necessary to repeat display: block unless
       interpolation behavior is visibility-like
       preferring non-none value. */
    visibility: visible;
    opacity: 0; }
}

dialog {
  --duration: 400ms;
  animation: close 400ms;
  visibility: hidden;

  /* The UA applies the following while dialog is :modal,
     we need to preserve it during the animation. */
  display: block;
  position: fixed;
  inset-block-start: 0px;
  inset-block-end: 0px;
  max-width: calc((100% - 6px) - 2em);
  max-height: calc((100% - 6px) - 2em);
}

so it seems to me this is more about allowing the display CSS property to animate?

Also, if this is about having to repeat all the properties that the top layer sets, then don't we have the same issue with any HTML feature that sets UA styling? It seems to me than this is more a problem tied to display than top layer.

khushalsagar commented 1 year ago

@nt1m it's not just the UA styles applied in top layer, which developers can replicate. It's also the change in stacking which allows the dialog to paint on top of all other content.

jods4 commented 1 year ago

Is this new take on top-layer animation even less friendly than the previous popover one when it comes to non-time based animations?

In previous spec, it was hacky but possible to control the animation from JS by using "proxy" native animations that one could pause and complete. If I understand correctly, this new proposal is founded on a CSS transition and that, is impossible to control from JS.

Can someone write a basic example of a physics-based animations (e.g. springs) for a top-layer element removal?

nt1m commented 1 year ago

Very disappointing feedback here was not taking in account before sending an "Intent to Ship": https://groups.google.com/a/chromium.org/g/blink-dev/c/nx2P-B8Rhx4/m/QbE3n68fAgAJ

chrishtr commented 1 year ago

Very disappointing feedback here was not taking in account before sending an "Intent to Ship": https://groups.google.com/a/chromium.org/g/blink-dev/c/nx2P-B8Rhx4/m/QbE3n68fAgAJ

It is not an intent to ship, it's an intent to prototype. We are building a complete prototype in order to make sure we understand all of the implementation touch points of top layer before coming back to the CSSWG for further discussion.

nt1m commented 1 year ago

Very disappointing feedback here was not taking in account before sending an "Intent to Ship": groups.google.com/a/chromium.org/g/blink-dev/c/nx2P-B8Rhx4/m/QbE3n68fAgAJ

It is not an intent to ship, it's an intent to prototype. We are building a complete prototype in order to make sure we understand all of the implementation touch points of top layer before coming back to the CSSWG for further discussion.

Ah right, sorry, must have been confused since I saw this coming from https://twitter.com/intenttoship .

chrishtr commented 1 year ago

Ah right, sorry, must have been confused since I saw this coming from https://twitter.com/intenttoship .

No worries. I agree the intenttoship twitter name is a bit confusing.

flackr commented 1 year ago

In previous spec, it was hacky but possible to control the animation from JS by using "proxy" native animations that one could pause and complete. If I understand correctly, this new proposal is founded on a CSS transition and that, is impossible to control from JS.

The getAnimations() API returns all running CSS animations, CSS transitions and web animations allowing them to be modified or controlled from JS. This would let you pause and complete the transition in order to run a JS-based animation.

Can someone write a basic example of a physics-based animations (e.g. springs) for a top-layer element removal?

Something like this (uses a transition of visibility so that it works in regular browsers but with this proposal the same would work for the top layer transition): https://output.jsbin.com/qoyevow

jods4 commented 1 year ago

@flackr thanks!

Good thinking, grabbing the CSS transition with getAnimations. 💡 The code is clunky, but at least it works (any non-keyframe-based animations with native web animations is clunky, so nothing unusual there -- I'm hopeful the platform will make some progress on this front in the future).

Your proof of concept works, but for somewhat more "real" code I'd tweak it a bit: Listening to transitionstart is a good idea but then you should just look for transitions that target visibility (which you know is the key piece here) rather than using evt.propertyName. In a real application, the dialog might well start other transitions for other states so that would not be reliable.

flackr commented 1 year ago

Just to put the sample code in the issue here, it would look something like this for top-layer:

dialog.addEventListener('transitionstart', (evt) => {
  if (evt.propertyName != 'top-layer')
    return;
  let transition = evt.target.getAnimations().filter((anim) => anim.transitionProperty == evt.propertyName)[0];
  transition.pause();
  runCustomPhysicsJSAnimation().then(() => { transition.finish(); });
});

You could also roughly (extra work to ignore already running animations not included here) polyfill the previous way this worked by using getAnimations({subtree: true}) to find all animations within the dialog and adjusting the transition duration to match the end time of the last animation, e.g.

dialog.addEventListener('transitionstart', (evt) => {
  if (evt.propertyName != 'top-layer')
    return;
  let transition = evt.target.getAnimations().filter(
      (anim) => anim.transitionProperty == evt.propertyName)[0];
  let maxDuration = evt.target.getAnimations({subtree: true}).map(
      anim => anim.effect.getComputedTiming().endTime).reduce(
          (maxDuration, duration) => Math.max(duration, maxDuration), 0);
  transition.effect.updateTiming({duration: maxDuration});
});
lilles commented 1 year ago

Here is what I wrote up about spec changes for CSS and HTML that would support transitions of top layer elements with a top-layer property. It matches the implementation we have behind a flag in Blink.

TL;DR Outline spec changes needed to introduce the top layer concept in CSS with a top-layer property as well as specifying how ordering of top layer candidate elements can be provided by the host languages like HTML.

Background

Proposed Changes

CSS Specification

HTML Specification

Fullscreen Specification

nt1m commented 1 year ago

Again, can we come up with a different name than top layer?

SebastianZ commented 1 year ago

Also the values should get better names than none and browser, in my opinion.

Sebastian

chrishtr commented 1 year ago

How about overlay?

overlay: top: in the top layer overlay: normal: in normal z-index flow

Fullscreen, popover and dialog can all be thought of as UI overlays.

nt1m commented 1 year ago

overlay is a lot better, will think more on my side and come back with more suggestions if I find any.

nt1m commented 1 year ago

I think overlay: auto and overlay: none would be more accurate than top/normal since top won't work on all elements (but only on top layer ones).

nt1m commented 1 year ago

Potentially overlay-behavior: auto makes more sense than overlay: auto.

This new property is essentially about disabling top layer layout/rendering behaviors during transitions, so I think including -behavior in there makes sense.

nt1m commented 1 year ago

Fwiw, I think top layer is a very bad name here because this property really is about the rendering behaviors that top layer has, rather than the top layer elements list itself. You can have an element in the top layer list, while having those top layer rendering behaviors turned off during transitions using that property.

So overlay-behavior: auto/none seems to express this better IMO.

nt1m commented 1 year ago

@chrishtr I'm trying the top-layer property in Chrome Canary, and I'm not sure how it works exactly, but my example doesn't seem to work: https://jsfiddle.net/n1p67m0L/

lilles commented 1 year ago

@chrishtr I'm trying the top-layer property in Chrome Canary, and I'm not sure how it works exactly, but my example doesn't seem to work: https://jsfiddle.net/n1p67m0L/

chrishtr commented 1 year ago

A complete working demo is here that you can use on Chrome Canary. Command-line to test:

chrome --user-data-dir=/tmp/foo --enable-blink-features=CSSDisplayAnimation,CSSTransitionDiscrete,CSSTopLayerForTransitions https://codepen.io/chrishtr1/pen/eYLyGgq

This demonstrates a dialog that is normally below a green overlay, but when it is in the top layer it is on top. It also demonstrates animation of discrete properties generally, display (to prevent disappearing), and top-layer (to stay on top of the green overlay).

When closing the dialog, it transition-animates opacity, display and top-layer with potentially different durations for each.

chrishtr commented 1 year ago

I propose that we move forward with a new overlay-behavior CSS property specified according to the rules described here (except with change of property name of course) and with syntax like this:

overlay-behavior: auto | none

There is the following UA rule:

* {
  overlay-behavior: none !important;
}

Note: the only way to override such a UA rule is with transition: overlay-behavior.

nt1m commented 1 year ago

@chrishtr Just wondering, instead of creating a new property, has syncing with display been considered? Mainly putting this out there since it has been done for inert: https://github.com/w3c/csswg-drafts/issues/8389

chrishtr commented 1 year ago

@chrishtr Just wondering, instead of creating a new property, has syncing with display been considered? Mainly putting this out there since it has been done for inert: #8389

Interesting idea. I think it would work in cases where top layer elements animate to display:none, but not cases where they don't. e.g. a developer could add dialog { display:block } or [popover] { display:block } to their style sheet. In that situation, it's unclear when to remove the element from the top layer when dismissing the dialog or popover, without the UA having to try to guess or detect when animations are happening on dismiss.

fantasai commented 1 year ago

Note: the only way to override such a UA rule is with transition: overlay-behavior.

To be clear, that can't override the UA rule. You can't override a UA !important rule, only the UA can override it, so if the UA doesn't apply an overlay-behavior: auto !important rule to an element it will stay as none. But the author can control the transition between none and auto with such a rule.

From an initial read, I think the proposal makes sense. I think using the term “overlay” is a great improvement over “top-layer”. :) I'm a little uncertain about -behavior as the suffix, it doesn't seem to be behavioral, more like a new positioning scheme. (I wonder if overlay-index: none | auto makes sense? It's reminiscent of z-index, except the UA is picking the index according to the host rules. Idk)

nt1m commented 1 year ago

@chrishtr Just wondering, instead of creating a new property, has syncing with display been considered? Mainly putting this out there since it has been done for inert: #8389

Interesting idea. I think it would work in cases where top layer elements animate to display:none, but not cases where they don't. e.g. a developer could add dialog { display:block } or [popover] { display:block } to their style sheet. In that situation, it's unclear when to remove the element from the top layer when dismissing the dialog or popover, without the UA having to try to guess or detect when animations are happening on dismiss.

If your element has display: block even before the transition, you're going to see a visible shift either way because of all the different adjustments top layer makes: position, containing-block, stacking context, etc. Adding a new property can control the timing of that shift, but cannot remove it. So I don't think this is an use case we should worry too much about.

chrishtr commented 1 year ago

If your element has display: block even before the transition, you're going to see a visible shift either way because of all the different adjustments top layer makes: position, containing-block, stacking context, etc. Adding a new property can control the timing of that shift, but cannot remove it. So I don't think this is an use case we should worry too much about.

In some cases, maybe, but I think preventing the z-index shift during animation will still be useful to developers in these cases. And there's still the problem I mentioned earlier of not being able to easily distinguish between an animation to display:none vs animation to something else.

css-meeting-bot commented 1 year ago

The CSS Working Group just discussed [css-animations-2, css-transitions-2] Entry and exit animations for top-layer elements, and agreed to the following:

The full IRC log of that discussion <emeyer> plinss: There was TAG discussion about popover, which turned into discussion about the top layer in general
<emeyer> …TAG is concerned about the overall design of the top layer
<emeyer> …It’s done by monkey-patching CSS
<TabAtkins> q+
<emeyer> …It should be defined by the CSS WG, but hasn’t been getting a lot of love
<emeyer> …There’s room for declaratively creating not just the top layer, but multiple laters
<emeyer> s/laters/layers/
<emeyer> …I think it should be controleld entirely in the CSS layer
<masonf> q?
<emeyer> …Don’t have a specific design, but the TAG feels it needs to be done
<astearns> ack TabAtkins
<emeyer> TabAtkins: I’ve had this on my to-do list
<emeyer> …To pull out painting order and do a spec about that
<emeyer> …We have a resolution on file to put that into the position spec
<emeyer> …Proper specification in CSS is on my task like
<emeyer> …In terms of authors being able to create layers other than the top layer, completely agree
<emeyer> …This has come up with anchor positioning
<emeyer> …I definitely support authors being able to define additional layers you can move things into
<chrishtr> q+
<emeyer> …In terms of making the top layer accessible, that’s been discussed and there are significant concerns
<emeyer> …Anything the UA is using the top layer for shouldn’t be able to be covered up
<emeyer> …That’s a larger, separate conversation
<emeyer> …Doesn’t have to prevent letting authos insert layers between document and “top layer”
<emeyer> s/authos/authors/
<masonf> q+
<emeyer> plinss: I understand the security concerns
<emeyer> …We have precedence for letting the UA override author styles and should use similar mechanisms for the top layer
<emeyer> …While we should allow authors to create layers, the top layer should just be another layer, not something special and magic
<lea> q?
<emeyer> …The magic can come from the UA stylesheet
<emeyer> astearns: Please add a link to the proposal you referenced
<astearns> ack chrishtr
<emeyer> chrishtr: We’re going to do the work to move the top layer stuff into the position spec
<dbaron> I think we might also have a somewhat older resolution for me to create a spec for the CSS painting model... :-/
<emeyer> …Can we go back to the thing in 8189, which is adding transition control for developers entering and exiting top layer?
<emeyer> masonf: In general, I’m in support of moving into positioning spec
<lea> how can we discuss entry/exit animations separarately to whether there will be author control of top-layeredness? These are intrinsically related
<emeyer> …I would be supportive of letting authors create a new top layer under the existing top layer
<emeyer> …Trying to do it with existing CSS in the existing top layer are difficult
<emeyer> …Like the top layer being an ordered set
<emeyer> …So I’d be against allowing direct control of the existing top layer
<emeyer> plinss: I’m not arguing the change how the top layer now works, I just think it should be explained using CSS
<emeyer> …Such as exposing the ordering via CSS
<emeyer> masonf: If that’s possible, I’m in favor of it
<emeyer> plinss: I think so
<emeyer> …it would also be great to fix all the z-index hackery that’s been done since day one
<TabAtkins> Found the resolution https://github.com/w3c/csswg-drafts/issues/6685#issuecomment-930305697
<lea> +1 to everything plinss is saying of course
<emeyer> astearns: I’m hearing a lot of agreement and a stated plan to work on this in the position spec
<emeyer> chrishtr: That would be the first step, yeah
<astearns> ack masonf
<emeyer> …My proposal on 8189 is you can say transition and then a CSS proeprty that refers to the top layer behavior, and then the usual transtion delay
<emeyer> …So you could push transitioning things into the top layer
<emeyer> …My reading of issue commentary is that people are generally positive about the mechanism
<emeyer> …So if we’re good and want to pick a name, I think overlay would be fine
<masonf> +1 to `overlay`. `overlay-behavior` feels odd.
<emeyer> fantasai: I like the idea of using the word overlay, but think overlay-behavior is a bit weird
<bramus> +1 on just `overlay`
<emeyer> …I’m open to thoughts
<masonf> `overlay-index` ? That feels bad too.
<emeyer> astearns: The analogy to z-index would make me wonder why there aren’t integers allowed in the syntax
<masonf> q?
<emeyer> fantasai: This should go into position-4, not -3
<emeyer> chrishtr: Agreed
<emeyer> astearns: I’m seeing more people in favor of `overlay` rather than `overlay-index`
<emeyer> …We could put it into position-4 and see what people say
<emeyer> …So we propose to include `overlay` property with values of `auto` and `none`
<dbaron> (maybe some other name thoughts might be overlay-layer or overlay-level)
<emeyer> plinss: I have concerns this could conflict with other things we might do very soon
<emeyer> astearns: Amended proposal to include `overlay` property with values of `auto` and `none` to position-4 with a note about concerns over extensibility
<masonf> +1
<emeyer> RESOLVED: include `overlay` property with values of `auto` and `none` to position-4 with a note about concerns over extensibility
<TabAtkins> I'd actually totally missed this issue's discussion, but it sounds good to me.
LeaVerou commented 1 year ago

Btw do note that * does not target every possible selector target. E.g. what happens if I do ::before { overlay: auto } ? Is the plan to add every possible pseudo-element in the UA stylesheet so it can get overlay: initial !important?

nt1m commented 1 year ago

Instead of a new property (which I'm still not a fan of, because it's non-intuitive for web developers), I'm thinking:

I think this is what probably feels the most natural, and it should be somewhat simple to do this in WebKit. @chrishtr What do you think?

chrishtr commented 1 year ago

Hi @nt1m,

Can you tell me more about how z-order syncing and adjustments to display would work? Are you suggesting something that automatically detects animations from developers and syncs to them?

nt1m commented 1 year ago

Hi @nt1m,

Can you tell me more about how z-order syncing and adjustments to display would work? Are you suggesting something that automatically detects animations from developers and syncs to them?

Have all the non-z-order ones sync with display (display: block = adjust, display: none = do not adjust) in a similar fashion inert is synced with display. Have the z-order ones sync magically with the z-index property (this would probably involve some magic internal value).

chrishtr commented 1 year ago

Have all the non-z-order ones sync with display (display: block = adjust, display: none = do not adjust) in a similar fashion inert is synced with display. Have the z-order ones sync magically with the z-index property (this would probably involve some magic internal value).

I see. Sounds like the same suggestion you made earlier in the issue? I think my responses here and here are reasons why I think this is not as clean and simple as the overlay CSS property in semantics, "magic" or reliability for web developers.

I also don't agree that overlay will be hard for developers to understand, they just need to use the transition CSS property combined with it, which is straightforward and easy for them to copy-and-paste.

nt1m commented 1 year ago

Have all the non-z-order ones sync with display (display: block = adjust, display: none = do not adjust) in a similar fashion inert is synced with display. Have the z-order ones sync magically with the z-index property (this would probably involve some magic internal value).

I see. Sounds like the same suggestion you made earlier in the issue?

Not really, you mentioned developers want to control the z-index shift separately from display so my suggestion is to control this separately from the display property.

I also don't agree that overlay will be hard for developers to understand, they just need to use the transition CSS property combined with it, which is straightforward and easy for them to copy-and-paste.

I'm not concerned about it being hard to understand. I'm trying to fit top layer into the pre-existing the CSS models, which I do think it leads to a better developer experience it we manage to do so, rather than introducing a new model. E.g. imagine being a web developer knowing nothing about the top layer (which is expected in most cases), but knowing basic CSS, what would be their first intuition to solving the problem?

I think it would be good to think about this first before moving forward with a new property, I'm open to any suggestions that moves towards that direction.

flackr commented 1 year ago

Something like z-index: overlay which would be a z-index value only available for the UA to apply? Then developers could add a transition on that which would preserve the overlay setting on exiting. Downside would be that naively other z-index changes would also transition.