w3c / csswg-drafts

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

[view-transitions-2] Allow styling based on navigation/transition state #10434

Open ydaniv opened 3 months ago

ydaniv commented 3 months ago

With the introduction of declarative MPA transitions it's now possible to navigate to a different page on same site seamlessly. This also introduces a need to style elements differently based on whether the page was loaded via a VT or a simple load.

A common example of that is entrance animations, and a current specific use-case I have is the animation of shared elements, say a site's header. Let's say I have a header that should be flying in from above the top of the page down to its original position at the top of the page. On subsequent page loads, when navigating between pages on same site using VTs the author may want to keep the header in-place, probably by excluding it from the transition using view-transition-name: header, but also specify that it should not animate again.

Here's the example in code:

@keyframes flyIn {
  from {
    translate: 0 -100%;
  }
}

header {
  aniamtion: flyIn 600ms backwards ease-out;
}

And to prevent the animation with selector/conditional it should look something like:

@view-transition-enabled {
  header {
    animation: none;
  }
}

Currently there's no persistent selector that says "this page was navigated to via VT", there's only the transient :active-view-transition pseudo-class which is removed once the transition ends and is no longer active.

Though we could achieve this using the pagereveal event, we should probably have some rule/selector to specify this declaratively. The pattern above already exists in SPAs today, and in order to easily transform SPAs to MPAs we'll need some simple mechanism to eliminate the need for keeping that state in user-land.

cc @khushalsagar @noamr

khushalsagar commented 3 months ago

The pattern above already exists in SPAs today, and in order to easily transform SPAs to MPAs we'll need some simple mechanism to eliminate the need for keeping that state in user-land.

Are SPAs doing it by keeping this in user-land?

The idea seems reasonable to me and should be trivial to add for cross-document navigations. Its the CSS equivalent of NavigationActivation so we should probably go for a syntax that allows adding other stuff from NavigationActivation to CSS.

But I'm not sure how to reason about it for the SPA case.

noamr commented 3 months ago

So this is somethlng like having CSS instead of the following line?

addEventListener("pagereveal", e => {
  document.documentElement.classList.toggle("has-view-transition", !!e.viewTransition)
});
ydaniv commented 3 months ago

Are SPAs doing it by keeping this in user-land?

I can say I have this feature of keeping track of played animations that needs to not be re-played, which I don't wish to keep supporting since it's not MPA-compat.

The idea seems reasonable to me and should be trivial to add for cross-document navigations. Its the CSS equivalent of NavigationActivation so we should probably go for a syntax that allows adding other stuff from NavigationActivation to CSS.

I guess this state currently isn't just about whether there was a cross-docuemnt transition or not, so perhaps extending this further to the concept of navigation could also make sense, but I suspect the need is more urgent when a VT is used.

But I'm not sure how to reason about it for the SPA case.

If you're on same document, replacing DOM, and applying a VT, it would be nice to declaratively also style elements differently if they were replaced.

So this is somethlng like having CSS instead of the following line?

addEventListener("pagereveal", e => document.documentElement.classList.toggle("has-view-transition", !!e.viewTransition) );`

Exactly!

khushalsagar commented 3 months ago

How about something like:

@navigation-activation (viewTransition: yes) {
  ...
}

where viewTransition specifies whether the Document was activated with a transition. And if we want to add more features to this rule as needed.

noamr commented 3 months ago

I think a condition that's like :active-view-transition but is sticky and MPA-only (hence a condition and not a pseudo-class) would work for this: @inbound-view-transition(types) { }

I don't think it's necessary to generalize it into a navigation-activation namespace, unless we have ideas for several other similar conditions.

khushalsagar commented 3 months ago

^ can't think of a use-case right now but something like this is what I had in mind, in case other data in activation could also be useful.

@navigation-activation (type: back) {
   ...
}

But it's fairly trivial to do this via script so I don't feel strongly. @inbound-view-transition(types) { } also SGTM with one suggestion, can we omit types for now? Just do @inbound-view-transition { } where the rule applies if the Document was activated with a transition.

types can technically be changed during the transition and it's not clear to me whether this should also be changed with them. And since we don't have a use-case for types right now, it's hard to decide. We can easily extend the syntax to add types later if a use-case comes up.

ydaniv commented 3 weeks ago

@noamr @khushalsagar I think we have a general agreement here, you think we can add agenda+ here for proposing the above pending BS?

noamr commented 3 weeks ago

@noamr @khushalsagar I think we have a general agreement here, you think we can add agenda+ here for proposing the above pending BS?

I don't think we have a clear proposal yet and I don't see it as high priority since the alternative requires ~3 lines of JS. If you want to drive it forward though I'm happy to help!