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-view-transitions-2] Media query alternative to cross-document opt-in #8868

Closed
noamr opened this issue May 23, 2023 · 5 comments
Closed
Labels
css-view-transitions-2 View Transitions; New feature requests

Comments

@noamr
Copy link
Collaborator

noamr commented May 23, 2023

In #8048, the proposal is to use a new rule for opting-in to cross-document transitions.
This has a few drawbacks:

  • You can't opt-out of the transition based on things in the document, e.g. body.disable-transitions { @cross-document-transitions: allow; }
  • It's totally different from the way you disable of same-document transitions (::view-transitions { display: none })
  • Its limited to opting in/out, it requires extensions or JS to allow, for example, different names for cross-document transition.
  • It's a bespoke rule, so we have to define how it interacts with other rules and so forth, and developers have to learn it.

Proposing, instead, to use a media-query:

@media (page-tranistion: incoming | outgoing | any | ...` (we can bikeshed this of course)

To accomplish the original requirement of disabling cross-doc transitions by default, the default UA stylesheet can be:

@media (page-transition) { 
  ::view-transition { display: none }
}

This separates the condition (is this a page-transition?) with the action (the transition should be animated/skipped) and thus allows for more mixing and matching, e.g:

@media (page-transition) or (prefers-reduce-motion) {
  ::view-transition { display: none }
}

@media (page-transition: outgoing)  {
  body.disallow-outgoing-tranistions {
    ::view-transition { display: none }
  }
}

We can also change the transition names based on whether this is a page transition:

#my-element { view-transition-name: some-name }

@media (page-transition) {
   #my-element { view-transition-name: some-other-name }
}

We also get the JS API for free matchMedia and MediaQueryList/change event gives the developer all the JS observability they need. There's no need for a ViewTransition object.

Note that to enable this, we would have to clearly define in the lifecycle at which exact points in the navigation/rendering lifecycle the page-transition media is matched, and we would have to enable the ::view-transition pseudo-element when navigating to a page that can potentially trigger a page transition.

@bramus
Copy link
Contributor

bramus commented May 23, 2023

In general, I like this at-rule approach.

A few remarks/questions:

  1. What is the lifetime when these at-rules apply? In internal conversations I heard that the incoming one would only be alive at the very first frame (to actually opt in + optionally set up different transition names) and outgoing one only at the very last frame of the page.

  2. The nested example seems incorrect. I think it should be this, as ::view-transition is a pseudo of the root :

    @media (page-transition: outgoing)  {
      :root:has(body.disallow-outgoing-transitions)::view-transition {
        display: none;
      }
    }

    However, with @media (page-transition) { ::view-transition { display: none } } in the UA, in practice the logic would be flipped around, no? Like this:

    @media (prefers-reduce-motion: no-preference) and (page-transition) {
      ::view-transition { display: block; }
    }

    Or, more selectively:

    @media (prefers-reduce-motion: no-preference) and (page-transition) {
      :root:has(body.allow-outgoing-transitions)::view-transition {
        display: block;
       }
    }
  3. Would this replace the meta tag opt-in? If not, what happens when both are set with contradicting values? More specifically, what happens if the meta tag opts-in, but the the UA default styles (which is essentially an opt-out) is applied?

  4. When the outgoing page does not opt-in but the incoming page does, do we then get a simple fade-in of the root or would all transitions get skipped? Put differently: it’s a double opt-in?

  5. With the JS approach, one quickly can set up some classes on the root based on the directionality of the page hierarchy. For example, clicking from an overview page to a detail page should slide all stuff to the left, whereas then clicking the home icon should slide all stuff to the right as you’re going back from that detail page to the overview page.

    Maybe there should be some way to pass this type of info from one page to another, which could then also be taken into account in the MQ on the new page? That way, an author can set up the appropriate vt-names and animations, based on that piece of data. In [css-view-transitions-2] Declarative opt-in for cross-document navigations #8048, you proposed for the page URL to be that piece of data. Is this still considered?

    (Not sure if this is essential to this issue, or could be discussed separately.)

@noamr
Copy link
Collaborator Author

noamr commented May 24, 2023

In general, I like this at-rule approach.

A few remarks/questions:

  1. What is the lifetime when these at-rules apply? In internal conversations I heard that the incoming one would only be alive at the very first frame (to actually opt in + optionally set up different transition names) and outgoing one only at the very last frame of the page.

Outgoing - I think it should be when a same-origin navigation fetch is initiated, but it can also be the last frame. Either would work, the first one is a bit easier to understand, and perhaps we can use it for other things, e.g. call it navigating-away rather than something VT-specific.

Incoming - when the page is render-unblocked or reactivated, but before presenting.

  1. The nested example seems incorrect. I think it should be this, as ::view-transition is a pseudo of the root :
    @media (page-transition: outgoing)  {
      :root:has(body.disallow-outgoing-transitions)::view-transition {
        display: none;
      }
    }

However, with @media (page-transition) { ::view-transition { display: none } } in the UA, in practice the logic would be flipped around, no? Like this:

@media (prefers-reduce-motion: no-preference) and (page-transition) {
  ::view-transition { display: block; }
}

Or, more selectively:

@media (prefers-reduce-motion: no-preference) and (page-transition) {
  :root:has(body.allow-outgoing-transitions)::view-transition {
    display: block;
   }
}

See below. unlike what I wrote in the OP, I am convinced that we should have a "hard" opt-in, probably in HTML, to avoid cases where someone accidentally enables cross-doc-VT with e.g. by putting ::view-transitions { display: block } without anything in their CSS (media-queries don't add specificity).

  1. Would this replace the meta tag opt-in? If not, what happens when both are set with contradicting values? More specifically, what happens if the meta tag opts-in, but the the UA default styles (which is essentially an opt-out) is applied?

Thinking about this again, I think we should actually keep the meta opt-in and not change the default style.

The reason is that with only using default styles it's very easy to accidentally enable cross-document transition, as media-queries don't affect specificity.

So I suggest to keep the opt-in, and make it very simple and binding. And use the media query for everything else:

  • last-frame/first-frame customizations
  • disabling/enabling the transition based on all kinds of conditions
  1. When the outgoing page does not opt-in but the incoming page does, do we then get a simple fade-in of the root or would all transitions get skipped? Put differently: it’s a double opt-in?

It should be a double opt-in. Transitioning from blank is something that we should address separately, but in general view-transitions don't help you with that at all, and you can use regular keyframes as pages do today - the novelty of VT is by having detailed and separate "old" and "new" states and that doesn't apply to from-blank transitions. We should experiment with how VT interacts with pages that have non-VT entry animations, e.g. perhaps the keyframes can be reused.

  1. With the JS approach, one quickly can set up some classes on the root based on the directionality of the page hierarchy. For example, clicking from an overview page to a detail page should slide all stuff to the left, whereas then clicking the home icon should slide all stuff to the right as you’re going back from that detail page to the overview page.
    Maybe there should be some way to pass this type of info from one page to another, which could then also be taken into account in the MQ on the new page? That way, an author can set up the appropriate vt-names and animations, based on that piece of data. In [css-view-transitions-2] Declarative opt-in for cross-document navigations #8048, you proposed for the page URL to be that piece of data. Is this still considered?

That was an attempt to think ahead, but I actually think we shouldn't do any of this at all. It leaks HTML/routing concerns into CSS. If a developer wants to achieve that kind of customization, they should put something in the DOM, like <body data-prev-page=home> based on the referrer or query variable or whatnot and cascade the CSS changes you want, such as enabling/disabling the transition altogether.

@jakearchibald
Copy link
Contributor

jakearchibald commented May 24, 2023

@noamr

  • It's totally different from the way you disable of same-document transitions (::view-transitions { display: none })

I think the above might be the source of the confusion. The above isn't an opt-out, it isn't a way of 'disabling' view transitions, it's just hiding them. All the events relating to the view transition still happen. It's like saying iframe { display: none } disables iframes - it doesn't, all the loading of the iframe still happens, you just don't see the result.

There isn't an opt-out for SPA transitions, because they're opt-in by calling startViewTransition. If you don't want a view transition, you simply do not call startViewTransition.

Maybe the example in the article is misleading. It should really be a condition around calling startViewTransition, like how the skipTransition option works in the helper function.

Cross-document transitions should work in a similar way, by having an opt-in that you can make conditionally. I don't think we should have a system where the opt-in is big and dumb, and you have to hack around its big-and-dumbness by hiding loads of unintended transitions it creates.

  • Its limited to opting in/out, it requires extensions or JS

I think you're getting too hung up on it being a boolean. The intention is for it to be conditional using existing features like media queries. And, like I pointed out in the other thread, its boolean form is just a shorthand for a block form.

to allow, for example, different names for cross-document transition.

The primary goal should be to allow for cross-document transitions to work exactly like SPA transitions. That's the feedback we got from Mozilla and developers. If you're going to take things in a different direction than that, it should come with good justification.

Right now, with SPA transitions, you can easily add a class name to the root for the duration of the SPA transition. This allows the SPA transition to use particular names for that SPA transition. So, if there's a case where the SPA transition needs to use different names to cross-document transitions, that use-case is already catered for.

#my-element { view-transition-name: some-name }

@media (page-transition) {
   #my-element { view-transition-name: some-other-name }
}

Fwiw, you could also do this with the option 2 at #8683, by using wildcard URLs. I'm not convinced it's useful, but being able to do it based on particular URLs is definitely useful.

we would have to enable the ::view-transition pseudo-element when navigating to a page that can potentially trigger a page transition.

That's a pretty bad smell around this proposal. You're having to create a ::view-transition for a reason other than its designed purpose - you want to use its computed rendered state as a boolean signal. What happens if the developer has specified styles or animations on ::view-transition? Will they see these animations play twice, once on the outgoing page and once on the new page? Will they see a flash of style when ::view-transition is painted on the old page?

I think we should actually keep the meta opt-in and not change the default style.

The meta tag was intended as a temporary hack. If you're wanting to keep it, you need to justify why it's a good part of the design. Since view transitions are a visual design feature, I really think the opt-in should be via CSS. The reason they're not opt-in via CSS for SPA transitions is the timing for the DOM change is already performed by JS, so startViewTransition acts as both an opt-in and indicating the timing of the change.

@bramus
Copy link
Contributor

bramus commented May 25, 2023

Fwiw, you could also do this with the option 2 at #8683, by using wildcard URLs. I'm not convinced it's useful, but being able to do it based on particular URLs is definitely useful.

Oh, I seem so to have missed that issue before. Reading that, I see the entire picture now:

Will chime in on #8683, as that better addresses my last question (number 5) earlier in this thread

@noamr
Copy link
Collaborator Author

noamr commented May 25, 2023

Fwiw, you could also do this with the option 2 at #8683, by using wildcard URLs. I'm not convinced it's useful, but being able to do it based on particular URLs is definitely useful.

Oh, I seem so to have missed that issue before. Reading that, I see the entire picture now:

Will chime in on #8683, as that better addresses my last question (number 5) earlier in this thread

Yea I think I was going with this rather than #8683 because of #8683 (comment) but let's continue the discussion there. closing this one for now.

@noamr noamr closed this as completed May 25, 2023
@fantasai fantasai added the css-view-transitions-2 View Transitions; New feature requests label Jan 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
css-view-transitions-2 View Transitions; New feature requests
Projects
None yet
Development

No branches or pull requests

4 participants