-
Notifications
You must be signed in to change notification settings - Fork 690
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] Syntax for customizing transitions based on their type #8960
Comments
Are you needing to:
|
My use-case is a simple page transition, and currently just checking a data attribute which holds the type of visual transition to play. Based on the type I change animation properties on both old and new. Could be also on group if I had other animations. I think it boils down to managing transition state in general.
And then I guess we communicate it to developers before it gets messy. |
A pattern I saw from @jakearchibald which seemed like the easiest/most performant way to do this was using class names on html. When calling startViewTransition, you should know the type of transition. Let's call it type. Add a class corresponding to this type to html for the lifetime of the transition. And then all the CSS is gated on checking whether html has that class. Script function doTransition(type, updateCallback) {
document.documentElement.classList.add(type);
let transition = document.startViewTransition(updateCallback);
transition.finished.then(() => {
document.documentElement.classList.remove(type);
});
} CSS :root.type ::view-transition-old(foo) {
...
} Would that work? |
Thanks @khushalsagar , I'm already doing that as well. This could be especially problematic for developers of component libraries, where they don't have access to their embedding context, which is also somewhat the case I have at hand, only I'm allowed to play both sides in my case. |
Would it help if you had any of these available, while being able to read that info in CSS so you can respond to it:
|
Yes, that would help. The only problem is that for now this may lead authors to add
Not sure what you mean by that. Talking about SPAs, the transition is triggered via JS and any state at that point can be managed as written above. I'm mostly concerned with handling the declarative state in CSS without causing any potential harm. |
@ydaniv thanks for clarifying. Do you mind updating the issue title? It doesn't sound like we have a perf issue. It's having to leak information from a component triggering/managing the transition to the embedding context. Also updating the label since this seems like a future feature request but not an issue that needs to be fixed in the current spec. FWIW, I feel like involving the root (or embedding page) for transitions which span the entire Document makes sense. The whole Document is going to be paused with a layer (view transition stacking context) on top of the whole Document. So a component trying to do it transparently, i.e, avoiding setting state on the documentElement doesn't make sense. It is a valid question for scoped transitions. But assuming the whole setup (like the view transition stacking context) is scoped to the element which is the root of the transition (and thus the originating element for all pseudos associated with that transition), you could do the class based approach by targeting the element which is the root of that transition. This is conceptually similar to how a transition in an iframe would work. |
Sure @khushalsagar, I generally agree, but the problematic pattern still remains. We might as well resolve on adding a note in MDN (and perhaps web.dev and other places) about avoiding this, and using the other method of setting an attribute on documentElement or a custom property on :root. |
This is covered in https://developer.chrome.com/docs/web-platform/view-transitions/#changing-on-navigation-type, which reads:
|
Thanks for the pointer @bramus. Let me add this to the agenda to make sure the group agrees that this is the most optimal approach. We can add it to the MDN docs as well. |
This situation will be improved if #8683 lands in a way that can also be made available to SPA transitions, which is my recommendation. |
@jakearchibald, #8683 can help in some cases but not all.
|
The CSS Working Group just discussed
The full IRC log of that discussion<fantasai> khush: We've seen use cases where authors want to change view transitions based on state of the DOM<fantasai> khush: some tutorial suggest setting up a class on the root element <fantasai> khush: to get custom transitions <fantasai> khush: Is this the most optimal way? <fantasai> khush: or should we allow startViewTransition() to pass in a keyword <fantasai> khush: which then gets propagated to e.g. a media query <fantasai> khush: I don't know that it's worth making a custom feature for this, rather than just recommending using class names on the root <fantasai> ydaniv_: The issue started as a perf problem, and then changed to a ?? API <fantasai> ydaniv_: we have state that's under the HTML object. In order to lift that so that the DOM tree for the transition can be styled based on that state <fantasai> ydaniv_: using the :has() selector <fantasai> ydaniv_: but that's a big perf no-no <fantasai> ydaniv_: putting that aside, maybe even if browsers can optimize that it's only styling the pseudo-tree for transitions <fantasai> ydaniv_: but aside from preferred way, after DOM callback, to set attributes or ? <fantasai> ydaniv_: there was also a thought for maybe on the next level, expose the state <bramus> q+ <astearns> ack fantasai <khush> Issue is correct <TabAtkins> fantasai: i think it would be prettys traightforward to create this kind of tag in the arguments of th estartViewTransition() function <TabAtkins> fantasai: easy way to expose it would be with ::view-transition-root() thing <khush> You mean ::view-transition(foo)? <TabAtkins> fantasai: it does feel like modifying the dom which isn't great <TabAtkins> fantasai: modifying the dom to pass arguments is awkward even if it's performant <TabAtkins> (yes, that's what was intended, khush) <TabAtkins> fantasai: So if we can pass a name to startViewTransition() then select based on that name, it seems nicer <TabAtkins> fantasai: I think people would probably also want it for cross-document stuff <TabAtkins> fantasai: from urls A to urls B it's X class of transition <TabAtkins> bramus: I was going to propose something similar <astearns> ack bramus <TabAtkins> bramus: the flag or label in JS which you can read in CSS <TabAtkins> bramus: in addition to that maybe a MQ <TabAtkins> fantasai: you can't do an MQ because you might have multiple VTs going <TabAtkins> bramus: a CQ maybe? <TabAtkins> fantasai: That's why I think having it be an argument in ::view-transition() <TabAtkins> vmpstr: Problem with that is all the nested elements are accessed via the root element directly, so it's unclear to me how to limit a style to a group to only apply in this case <TabAtkins> fantasai: might be able to just pass that directly in as a second argument? <TabAtkins> (or define that ::view-transition-group() is *also* accessible under ::view-transition ?) <TabAtkins> vmpstr: I'm also ok with MQs but agree it could be confusing with multiples VTs running <TabAtkins> fantasai: With Tab's idea, nice thing is if Nesting allowed pseudos you could open up brackets and put them all inside of there <TabAtkins> khush: We didn't want to have to express the entire pseudo tree, how would you target something deep? <TabAtkins> vmpstr: You just put them under the ::view-transition, it's like having them come off of html <TabAtkins> fantasai: let's talk about this on the break <TabAtkins> fantasai: does anyone think we should *not* make this work, and rely just on class names? <TabAtkins> YehonatanDaniv: I think it's very good to pass to the startViewTransition and recognize somehow in CSS, yeah <noamr> q+ <TabAtkins> fantasai: k great let's try to come up with a proposal in this issue <khush> q+ <TabAtkins> noamr: we ahve to think how this applies cross-document too <astearns> ack noamr <TabAtkins> fantasai: I think this gives you more options cross-origin, yeah, you don't have to try and modify the destination dom <astearns> ack khush <TabAtkins> khush: i want to make sure i udnerstand the reason for not using MQ <TabAtkins> khush: MQ is nice because you can configure what things get a vt name based on type <TabAtkins> khush: But using a ::view-transition() would only let you hit the pseudos <TabAtkins> fantasai: You said earlier that you plan to have the ability to have multiple simultenous VTs. How does that work? <TabAtkins> khush: If you have different VTs, each will have different originating elements <TabAtkins> khush: So rather than html::view-* you'll have .foo::view-* <TabAtkins> khush: so that's how it's different <TabAtkins> fantasai: But the MQ can't match based on element... <TabAtkins> Okay so they *would* all match in the MQ at once (and you'd use the selector to actually target the right element) <TabAtkins> bramus: So if you have multiple transitions going on, the name you attach to each would ahve to be different <TabAtkins> khush: I just want to have the MQ syntax on the table to discuss <TabAtkins> fantasai: Confusing bit is just if you start two transitions, they both set the vt name, and they set it in the same subtree, it can get confused with each other <TabAtkins> vmpstr: right MQ is global, these subtrees are very local. mixing the two seems prone to weird conflicts <TabAtkins> khush: okay, seems fine <TabAtkins> khush: you can always toggle some class names at the same time as you call startVT() with a name, sure <TabAtkins> astearns: so should we resolve that we want a solution, and continue in the issue? <TabAtkins> khush: yeah <TabAtkins> astearns: objections? <TabAtkins> RESOLVED: Have some way to assign a name to a VT and style differently based on it, details tbd |
Assuming we have a parameter passed to Alternate would be media-query but because there will be support for concurrent transitions eventually, a global concept like media-query does not make sense. |
I would pass in the parameter to document.startViewTransition(updateTheDom, {
type: 'back',
}); I like the idea of adding a parameter to the pseudos, but was thinking towards reusing the qualified name syntax for it, as that would not break the existing syntax: ::view-transition-old(*) {
animation-name: slide-out-to-left;
}
::view-transition-new(*) {
animation-name: slide-in-from-right;
}
/* Respond to the “back” type of transition, by setting that type as a prefix to the argument */
::view-transition-old(back|*) {
animation-name: slide-out-to-right;
}
::view-transition-new(back|*) {
animation-name: slide-in-from-left;
} Or maybe have it as an argument to the /* Respond to the “back” type of transition, by setting that type as the name to the enclosing ::view-transition() pseudo */
::view-transition(back) {
::view-transition-old(*) {
animation-name: slide-out-to-right;
}
::view-transition-new(*) {
animation-name: slide-in-from-left;
}
} In this last syntax, only the One other idea that was floated was to use an at-rule for this, but as @khushalsagar already mentioned “Media queries are globally applied on the Document so are not a good fit for scoped transitions.” The syntaxes proposed here are not affected by it, as one can prepend the scoping element to the selector, e.g. |
There's also a possibility of adding a new pseudo class that applies to all elements (including view transition pseudos) that get activated right before the capture element discovery, something like ::view-transition-old(*):vt(back) {
...
} This enables the possibility of having optional view-transition-names on non-view-transition pseudos based on the navigation type: #foo {
view-transition-name: foo;
}
#foo:vt(back) {
view-transition-name: none;
} which is likely desirable as well? |
@bramus can you check how this work for the example here? The thing is that sometimes you want to use the same transition for many page types. e.g. a main-page transition. By working with page types rather than transition types, you put a lot of Based on how I saw people using the feature so far, I feel that people think in terms of transitions rather than page types. |
Proposal to be discussed at TPAC: Proposed syntaxUsing a set of idents and a pseudo class, like this: document.startViewTransition({
update: updateTheDOMSomehow,
classNames: ["main-page-slide", "product-expand", "back"]
}); html:active-view-transition(main-page-slide product-expand) .hero-image {
view-transition-name: hero;
} So we pass a set of class names when starting a view transition, and those classify the view transition from that point until the transition is finished. The Some reasons for this direction
To be discussed:
|
A couple of other bikeshed items:
|
Fwiw, in the Navigation API, it's Custom element callbacks do, but they seem unusual in that way. |
Fair enough, for some reasons when I originally proposed |
Pretty much like example 3, basically.
That would be this, without specifying any @view-transition { … } Alternatively, wildcards would be added, to indicate that @view-transition (from: * to *) { … } |
The CSS Working Group just discussed
The full IRC log of that discussion<noamr> Summary: https://github.com//issues/8960#issuecomment-1708702647<TabAtkins> noamr: I posted a summary content for where we've gotten to and what the proposal is <TabAtkins> noamr: We also gave a summary in general of VT yesterday <TabAtkins> noamr: This is a continuation from the f2f a few months ago <TabAtkins> noamr: With a single document with many VTs possible - think of a spotify that can slide-transition between main pages, and a different between a played song where it expands <TabAtkins> noamr: So we want a way to say "don't take everything from the page that can transition", but rather name the type of transition and pick and choose which elements go with what <TabAtkins> noamr: So far the way to do it is modifying the DOM: put a class on <html> that you use in a selector to set v-t-name <TabAtkins> noamr: Some issues, using DOM as ephemeral state for something that's entirely style <TabAtkins> noamr: Plus when we go later in cross-document, we want a declarative way to do this <TabAtkins> noamr: So we want a notion of cross-frame transitions that's embedded into CSS rather than a general-purpose JS mechanism. <TabAtkins> noamr: Proposed syntax is something that looks and feels like class names <TabAtkins> noamr: We'd pass it together with the v-t <TabAtkins> noamr: Currently it only accepts one parameter, the update callback <TabAtkins> noamr: We suggest another parameter, a list of a transition types <TabAtkins> noamr: like "slide" or "reverse-slide", etc <TabAtkins> noamr: And then have a pseudo-class on whatever's scoping the transition (currently, always <html>), and that matches based on which transition types are activated <TabAtkins> noamr: I want to present the alternative we consdiered, too <TabAtkins> noamr: Which was to qualify the pseudo-elements that are created <TabAtkins> noamr: We thought that wasn't enough, since the transition type also affects which elements are picked for the transition, not just which pseudo-elements are created. <TabAtkins> noamr: The more advanced alternative is we qualify pseudo-element names too. <TabAtkins> noamr: That's possible, but felt limiting. <TabAtkins> noamr: Perhaps you want to hide something in the page while the transition is going on, it' snot necessarily participating in the transition. <vmpstr> q? <TabAtkins> noamr: So we felt there's not much reason to avoid our preferred solution, and the other ways are all limited. <TabAtkins> +1, this sounds good <vmpstr> TabAtkins: i like this idea, and sounds reasonable. official cases brought up with things that don't participate makes sense <khush> q+ <astearns> ack khush <TabAtkins> khush: I prefer "type" over class names <fantasai> +1 <noamr> q+ <TabAtkins> khush: because there's another feature request where people want to apply styles to some pseudos <TabAtkins> khush: right now you can either do all ::v-t-group() or one with a particular name, can't do just some in a group <vmpstr> q+ <TabAtkins> khush: Second is "and" vs "or" <TabAtkins> khush: keeping the same syntax as proposed here seems good <astearns> ack fantasai <TabAtkins> fantasai: I agree with khushal that using classes seems tied into html classes, seems confusing. "type" seems fine. <eeeps> lea: https://github.com//issues/8960 <TabAtkins> fantasai: Another q, when you specify multiple names in the pseudo-class, is that "and" or "or". If it's "or" you should use a comma. <TabAtkins> fantasai: Overall a good approach. <astearns> ack noamr <TabAtkins> noamr: I thought "types" were a bit [missed], it describes something nominal <TabAtkins> noamr: But im' fine with that <TabAtkins> noamr: For "and" vs "or", we thought of spaces meanin "and" and commas meaning "or" <khush> sounds good <fantasai> +! <fantasai> s/!/1/ <TabAtkins> TabAtkins: Other option is we just do neither and rely on selector syntax to handle and/or <TabAtkins> TabAtkins: Depends on how common we think selecting on multiple names will be <ydaniv> q+ <TabAtkins> astearns: That would also be more compatible with future development <TabAtkins> noamr: Yeah, that's a possibility <TabAtkins> vmpstr: Comment about the name <fantasai> ... It's a reallllly long pseudo-class name, let's not make people type out that much for simple booleans :) <TabAtkins> vmpstr: I prefer "class" over "type" specifically because I think there's a possibility of using this in other contexts like web animations <astearns> could think of and/or as a future extension to solve that pain :) <TabAtkins> vmpstr: This would be able to set a number of additional classes that last for some duration <TabAtkins> vmpstr: In this case the pseudo-class name would have to be in there, so it's not tied to VT <TabAtkins> vmpstr: But if it's specifically "class"... I'm not particularly tied to it but it invokes CSS classes which is what this acts like. <fantasai> TabAtkins: This is basically an automatically-managed class <fantasai> TabAtkins: browser is adding/removing for you <astearns> ack ydaniv <astearns> ack vmpstr <TabAtkins> YehonatanDaniv: The direction is good, if we had a list of types/classes/whatever, I think doing "and" would be more productive <TabAtkins> YehonatanDaniv: But in general having a list of types, this covers the need <TabAtkins> astearns: I had an instinctual yuck against using space/comma to indicate and/or <TabAtkins> astearns: Any strong reason to not use `and` and `or` keywords? <TabAtkins> noamr: No particular reason, jsut consistency with selectors. But that would be consistent with MQs, so. <TabAtkins> noamr: Another idea was to borrow the class selector syntax, so `.page.slide, .foo-slide` <TabAtkins> astearns: How much do you think we can resolve on today? <hober> q? <TabAtkins> noamr: I'd like to say that we'll decide on the name and the and/or syntax later, but the general idea is good. <fantasai> We use commas to mean "or" in several places in functional pseudo-class syntax <TabAtkins> astearns: I'd like to add a specific syntax in the spec if possible <TabAtkins> astearns: If people have concerns about what we chose, they can raise issues. <TabAtkins> noamr: I suggest to resolve for now on "type" and not having and/or syntax yet <TabAtkins> noamr: Since selectors can already do and/or for now. <TabAtkins> khush: If we resolve on this now, will this break if someone makes a VT type named "and"? <TabAtkins> TabAtkins: No, since we'll currently be allowing only one name. In the future if we allow and/or internally, it'll be written ":v-t-type(and and foo)`, which is perfectly unambiguous (to a machine) <ydaniv> q+ <TabAtkins> fantasai: we use commas all over selector syntax to mean "or" <noamr> +1 <TabAtkins> fantasai: So even if we decide to add boolean keywords later, we'd probably still want commas for consistency with tons of things <TabAtkins> fantasai: So I think we should adopt that in the first iteration as well <astearns> ack fantasai <TabAtkins> +1, it is very natural <astearns> ack ydaniv <TabAtkins> and the "and" selector behavior is shorter <TabAtkins> YehonatanDaniv: So if I get this right, I can specify a few tpes in the startViewTransition() call <fantasai> TabAtkins: They'll all apply <TabAtkins> noamr: So elika do you want space for "and"? <TabAtkins> fantasai: I'm fine with that, I mainly just care about commas for "or" <fantasai> TabAtkins: and might inhibit future syntax design <fantasai> s/and might/"and" might/ <TabAtkins> astearns: So it sounds like we have consensus on adding a list of types to VT <TabAtkins> khush: yes <TabAtkins> astearns: and add exapmles for referring to them <TabAtkins> astearns: Objections to list of types? <TabAtkins> vmpstr: Are we specifically calling these "types"? <TabAtkins> fantasai: For the argument we can say "names", editorially we can call them type names or class names or wahtever. <TabAtkins> noamr: Yeah because the name wouldn't occur in CSS <noamr> we use the word "names" as the parameter name in CSS, and that word does not appear in CSS <noamr> sorry, we use the word "names" as the parameter name in JS, and that word does not appear in CSS <TabAtkins> s/name in CSS/name in JS/ <fantasai> PROPOSED: Add a 'names' argument to startViewTransition that takes a list of CSS identifiers, allow them to match against a pseudo-class which accepts a comma-separated (or) list of view transition names to match <fantasai> s/to match/during which it matches/ <TabAtkins> vmpstr: So clarifying the syntax, there's a distinction between adding the second param to sVT(), which is different from Noam's comment that has a dict <TabAtkins> noamr: We'r enot proposing a second param, we want sVT() to accept *either* a callback or an options bag <TabAtkins> The options will be a callback and the names <TabAtkins> dbaron: Is there a reason not to do a callback followed by an options bag? <TabAtkins> noamr: This is an API design more from Jake; we don't think the update callback is the obvious first param, it was just the only one earlier. <TabAtkins> dbaron: That makes sense. <TabAtkins> zcorpan: Slight concern with "names" as the name. We already have view-transition-name <fantasai> that's a good point <TabAtkins> TabAtkins: I propose that we resolve on the name of the option in two weeks, when we next meet <fantasai> PROPOSED: Add a 'TBD' argument to startViewTransition that takes a list of CSS identifiers, allow them to match against a pseudo-class which accepts a comma-separated (or) list of view transition names during which it matches <TabAtkins> TabAtkins: What's the pseudoclass called? <fantasai> RESOLVED: Add a 'TBD' argument to startViewTransition that takes a list of CSS identifiers, allow them to match against a pseudo-class which accepts a comma-separated (or) list of view transition names during which it matches <TabAtkins> noamr: :active-view-transition() <noamr> https://github.com//issues/8048 <TabAtkins> noamr: And we wait for "and" semantic later if needed |
Bikeshed proposals for the argument:
I think my favorite so far is |
The problem is, they're not actions. They're just 'tags'. It's down to the developer to decide how they're interpreted on the other side.
Actions on a notification are turned into buttons for the user to action. Feels like a generic name is better, since there's no policing of what the developer does with these 'tags'. My gut feeling is that the best practice would be for the outgoing page to provide 'information' rather than 'actions', and the incoming page will use this information to determine the action to take. |
I see your point, actions is a bit over-opinionated.
Any suggestions? Perhaps types or typeNames?
In the current plan this information is passed either via |
Currently in order to change the style of the generated pseudo-tree based on state of the DOM one has to use a
:has()
selector on thehtml
element to capture that state and then chain the pseudo-elements from there to style them.I have discussed this with @una, @lilles, and @andruud at CSS Day and they said that using a
:has()
on an element so high up the DOM tree may be a big perf issue with rendering possibly taking a few seconds in some cases.Here is a codepen with a simple example: https://codepen.io/ydaniv/pen/QWJjgQp
Basically it has this:
And styles:
And the JS for triggering VT is:
My concern is that this may become a common pattern and cause big frustration, probably even more so users than to authors.
It's possible to work around this by lifting all such state up to the
html
element and try to mitigate this with communicating this to authors.However, I think it's worth trying to find another solution for avoiding it altogetehr.
The text was updated successfully, but these errors were encountered: