Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

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

Closed
chrishtr opened this issue Dec 6, 2022 · 58 comments

Comments

@chrishtr
Copy link
Contributor

chrishtr commented Dec 6, 2022

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 */
  • Default: none
  • Animatable: yes
  • Discrete: yes
  • Accessible to developers: only via transition CSS property values

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
Copy link
Member

andruud commented Dec 6, 2022

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
Copy link
Contributor Author

chrishtr commented Dec 8, 2022

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
Copy link
Contributor Author

chrishtr commented Dec 9, 2022

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
Copy link
Member

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

@khushalsagar
Copy link
Member

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
Copy link
Member

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
Copy link
Collaborator

emilio commented Jan 11, 2023

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

@LeaVerou
Copy link
Member

LeaVerou commented Jan 11, 2023

@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
Copy link
Member

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//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
Copy link
Contributor

flackr commented Jan 11, 2023

@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
Copy link
Member

@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
Copy link
Member

nt1m commented Jan 11, 2023

@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
Copy link
Member

nt1m commented Jan 11, 2023

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:

  • There is general confusion with the name "top layer", e.g. is it the "topmost" element in the top-layer, or is this every element in the top layer? (In the specs, it refers to the the whole stack of elements).
  • Top layer was meant as an UA implementation detail to alleviate z-index issues. It's OK to document it, just like we document UA presentational hints, but I believe it's generally a bad pattern to expose this vocabulary to the language itself.

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
Copy link
Contributor Author

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
Copy link
Member

nt1m commented Jan 12, 2023

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
Copy link
Member

nt1m commented Jan 17, 2023

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
Copy link
Member

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

@astearns astearns removed the Agenda+ label Jan 24, 2023
aarongable pushed a commit to chromium/chromium that referenced this issue Jan 26, 2023
This CL adds support for top-layer behind a flag accepting two keywords,
'none' and 'browser'.

This CL only covers functionality for parsing and computing top-layer
property.

See: w3c/csswg-drafts#8189
Change-Id: Ic157543f6d7c49ce990150df43b668e617f9b4b0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4188891
Reviewed-by: Anders Hartvoll Ruud <andruud@chromium.org>
Commit-Queue: Rune Lillesveen <futhark@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1097374}
aarongable pushed a commit to chromium/chromium that referenced this issue Jan 30, 2023
Adds top-layer:browser style for fullscreen elements, dialogs, and
popovers.

See: w3c/csswg-drafts#8189
Change-Id: I600c9966e9020a625cc1cdddca51a6ce396222ed
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4193807
Reviewed-by: Mason Freed <masonf@chromium.org>
Commit-Queue: Rune Lillesveen <futhark@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1098420}
@jods4
Copy link

jods4 commented Jan 30, 2023

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
Copy link
Member

nt1m commented Feb 3, 2023

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
Copy link
Contributor Author

chrishtr commented Feb 3, 2023

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
Copy link
Member

nt1m commented Feb 3, 2023

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
Copy link
Contributor Author

chrishtr commented Feb 3, 2023

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.

@LeaVerou
Copy link
Member

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
Copy link
Member

nt1m commented Mar 27, 2023

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

  • sync z-order adjustment of top layer to z-index property
  • sync other adjustments to display property (like done for inert)

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
Copy link
Contributor Author

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
Copy link
Member

nt1m commented Mar 28, 2023

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

marcoscaceres pushed a commit to web-platform-tests/wpt that referenced this issue Mar 28, 2023
This isn't part of the landed spec [1], and will be replaced by
a combination of these five CSSWG issues:

- w3c/csswg-drafts#4441
- w3c/csswg-drafts#6429
- w3c/csswg-drafts#8174
- w3c/csswg-drafts#8189
- w3c/csswg-drafts#8389

After this CL, you will no longer be able to animate your
popover like this:

```
  [popover] {
    opacity: 0;
    transition: opacity 0.2s;
  }
  [popover]:open {
    opacity: 1;
  }
```

Instead you'll need to use CSS animations or (eventually) transitions
and you'll have to explicitly declare the `display` and `top-layer`
properties:

```
  transition: opacity 0.2s, display 0.2s, top-layer 0.2s;
```

[1] https://html.spec.whatwg.org/multipage/popover.html

Bug: 1307772,1413556
Change-Id: I4877dd69a06f2624bdb463b065b2e2b66cbf1154
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4225730
Reviewed-by: David Baron <dbaron@chromium.org>
Commit-Queue: David Baron <dbaron@chromium.org>
Commit-Queue: Mason Freed <masonf@chromium.org>
Auto-Submit: Mason Freed <masonf@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1107048}
@chrishtr
Copy link
Contributor Author

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
Copy link
Member

nt1m commented Mar 28, 2023

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
Copy link
Contributor

flackr commented Mar 28, 2023

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.

@nt1m
Copy link
Member

nt1m commented Mar 30, 2023

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.

I don't see that as a downside. I think this makes sense given z-index doesn't apply in the top layer, and top layer overrides any other z-index.

What made me hesitant of suggesting this was more how top layer does more than changing the z-index. But thinking more about this, it's not uncommon in CSS to have properties that cause side-effects.

@nt1m nt1m added the Agenda+ label Mar 30, 2023
@tabatkins
Copy link
Member

tabatkins commented Mar 30, 2023

I don't see that as a downside. I think this makes sense given z-index doesn't apply in the top layer, and top layer overrides any other z-index.

I'm not sure how that addresses the concern. While an element is not in the top-layer, its z-index can matter. When it is in the top-layer, its z-index doesn't matter (unless we use a new 'overlay' value to indicate its top-layer-ness). So using a transition to delay exiting the top layer has to be carefully scoped so it doesn't accidentally apply to other changes in z-index an element might have (because, presumably, they'd want different and likely unrelated transition behavior; most likely "no transition").

A new specialized property, on the other hand, avoids this concern - you can naively set a transition on the property, and it only applies in the expected situation.

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?

This is something I'm quite concerned about wrt re-using z-index, in fact (or any other property). z-index can be set by the author to any desired value, to put an element in a particular painting order wrt other elements in its stacking context. Elements cannot be put in the top layer via setting a property (and we'd have to define some magic mechanism forcing the computed value back to 'none' if the author tried to do so). The top layer also acts only roughly like z-index; it pulls you all the way out to the root stacking context rather than paying attention to the nearest ancestor stacking context. And then within the top-layer, ordering is totally different from how z-index works - z-index sorts by value, then DOM order, while top-layer is strictly based on top layer order (which is roughly the temporal order things were added, with no relation to DOM order at all).

All told z-index is similar thematically to top layer, but in virtually every specific it's different, and conflating them is imo likely to lead to significantly more confusion than not. A new property requires new learning, sure, but the purpose of the new property is very narrow in the first place (it exists solely to allow an author to add a transition that delays its value change, which is pretty narrow and specific).

@nt1m
Copy link
Member

nt1m commented Mar 30, 2023

A new specialized property, on the other hand, avoids this concern - you can naively set a transition on the property, and it only applies in the expected situation.

I do see the issue, but toying around with z-index outside of the top layer and toggling with that same element in & out of the top layer seems like an unlikely situation. The most common case is having a static z-index or none and toggling in & out of the top layer.

All told z-index is similar thematically to top layer, but in virtually every specific it's different, and conflating them is imo likely to lead to significantly more confusion than not.

I'm aware of the specifics (having implemented top layer in WebKit) and also of the style adjustments associated with top layer, though not sure it's significant from a web developer perspective.

A new property requires new learning, sure, but the purpose of the new property is very narrow in the first place (it exists solely to allow an author to add a transition that delays its value change, which is pretty narrow and specific).

As you mentioned in your first edit, it is weird :) It is also unprecedented in CSS to have properties that exist only for transitions. This is why it would be nice to think a bit more about it. I'm not advocating specifically for the z-index proposal, but more for an alternative proposal. A new property is ok but the standard should be higher for a spec, given they last once you implement them on the web.

@tabatkins
Copy link
Member

I'm aware of the specifics

Right, not suggesting you weren't, just saying that this is better considered a completely novel functionality.

A new property is ok but the standard should be higher for a spec, given they last once you implement them on the web.

The alternative to "a property that exists only for transitions" (and which can have this condition enforced using existing mechanisms like the UA-!important style sheet) is "a property value that exists only for transitions" (and which has to have novel magic defined to enforce this condition). I'm not even sure what the full degree of the magic is, actually; we want to prevent authors from setting it (so the top-layer remains managed by the UA) which could possibly be a constraint on the computed value, but we also want to prevent authors from unsetting it (for the same reason, so we can keep the top layer consistent when, for example, there are stacks that should close together), and I don't know how I'd do that. (I suspect the most straightforward way would be to say elements have a hidden state bit that, when turned on, forces z-index to compute to 'overlay' regardless of what the author does, and it's prevented from computing to 'overlay' otherwise? But that state bit functions identically to the 'overlay' property here.)

Both of a property and a value last once they're implemented, to the exact same degree. I don't think learnability is significantly different between the two? But being able to lean on existing functionality rather than forcing some really novel cascading behavior into one specific value seems like a big benefit of using a new property.

@chrishtr
Copy link
Contributor Author

Both of a property and a value last once they're implemented, to the exact same degree. I don't think learnability is significantly different between the two? But being able to lean on existing functionality rather than forcing some really novel cascading behavior into one specific value seems like a big benefit of using a new property.

Just wanted to +1 this point. The thing I like the most about the overlay property approach is that it doesn't require any new implementation or spec machinery to do with animations, and just re-uses what is already there. Likewise, it re-uses a concept of transitions that developers using animations are already familiar with. And the only new stuff for browsers to implement is how it affects what's in the top layer during the transition, which is I think a browser implementation and spec complexity that any proposal would need to have.

@astearns
Copy link
Member

astearns commented Apr 4, 2023

@nt1m I am removing the agenda+ label for now, as the discussion here seems to be going fine and I do not see consensus on an alternative to what we resolved before.

@astearns astearns removed the Agenda+ label Apr 4, 2023
@tabatkins
Copy link
Member

All the top-layer definitions, along with the 'overlay' property, are now in the Position 4 spec: https://drafts.csswg.org/css-position-4/#top-layer

There have been several minor changes from the text as it existed in Fullscreen.

  • the 'overlay' property now exists, which is automatically set by the UA (and only the UA) to reflect whether the element is in the top layer or not, but which can be affected by author-level transitions to keep something in the top layer temporarily, while an exit animation is playing (fading its opacity, etc). 'overlay' has transition semantics similar to 'visibility', where all intermediate progress values map to 'auto' (rather than flipping at half-progress)
    • as part of this, the "pending top layer removals" list has been added, so other algorithms can tell whether something is actually still in the top layer or just pending removal due to a transition; if it's pending they can go ahead and act as if it wasn't there.
  • modifying the top layer has been abstracted behind a couple of algorithms. They're generally light-touch, with two major changes:
    • unless you explicitly ask for immediate removal, removal instead just adds it to the pending removal list, and it's removed for real during HTML's Update The Rendering. This ensures that transitions added at the same time will get processed and can have an effect on the 'overlay' property, possibly delaying the actual removal. (Immediate removal should only be used for security-related things, or when CSS isn't relevant, like if the element has been removed from the document.)
    • adding something to the top layer that's already in the top layer (and not pending removal) is now considered a spec error, enforced by an assertion. (Previously, it just shifted the element to the end of the top layer, so it rendered topmost.) Now that several features play in the top layer, their interactions are non-trivial, and should be handled more explicitly by each feature. This will require more spec work, probably mostly in the other features' specs.

@chrishtr
Copy link
Contributor Author

chrishtr commented May 8, 2023

I'm going to close this issue now since the spec is defined and accepted by the WG. Further discussion can continue in issue #8730 if needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests