-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Transitions #7
Comments
Does that including transpile CSS2/3 syntax with dynamic value to Javascript on SSR or client side? Ramjet was nicely done for complex animation! |
I've been pondering transitions for a while now, and I'm starting to come around to @martypdx's view that transitions are more an extension of the eventing system than their own standalone construct. An intro is just a sort of stepped decorator transform that you want to apply to a node immediately after it is attached to the DOM, and an outro is the same but to be applied immediately before it is detached. If you can achieve an Once you have a good starting point, you can throw sugar at it, probably in the form of compiler plugins, though the penalties for more code in the svelte compiler are significantly less far-reaching than those in a runtimier library. The tricky bit is coordinating when to transition or remove a particular node, depending on whether it, an ancestor, or a child have a transition(s) or should transition if they have ancestors transitioning. There are scenarios in which you would want to have a child skip its transitions because an ancestor is transitioning and you don't want the child to slide about while it's group is fading out. I don't really see a way to do abortable or reversible transitions while still keeping the mechanism for transitioning fairly open ended (css transition, css animation, js, ... something else?). The safest way to achieve that would probably be to expose the hook queue of the transitioning node to the listeners. Then a (probably js-only for sanity) plugin could do state-based transitions and handle stopping the in-flight transitions and setting up the state for its starting point. |
I actually fell asleep thinking about reversible transitions last night (I know, I'm weird). There's definitely a tension between the state-driven paradigm that Svelte, Ractive, React, Vue et al represent and the event-driven paradigm (jQuery, Backbone etc) it replaces, and transitions straddle the two awkwardly. So I was wondering if there's a way to reconcile them. I haven't sat down and properly thought this through, but it occurred to me that if a 'transition' is just a function that returns a function that takes a single argument {{#if visible}}
<p transition:fade>now you see me...</p>
{{/if}}
<script>
export default {
transitions: {
fade ( node ) { // or `( node, params ) => {...}` as appropriate — see below
return t => node.style.opacity = t;
}
}
};
</script> That's a terrible example because it should be a CSS transition (which I'll come to) but you get the idea — rather than the transition function taking care of business and saying 'hey Svelte, I'm done' once it finishes, Svelte is driving the whole thing. So if the element is 95% faded out (i.e. For CSS transitions, you'd basically just be specifying the start and end states, which is effectively the same as letting the browser create the Coordination between transitions (chaining, skipping transitions for children of transitioning parents, etc) is definitely not a straightforward problem, nor is figuring out when an element can be detached. I wondered if maybe the detaching problem could be solved like so: {{#if visible}}
<p detachgroup:foo>
this will remain in the DOM until all nodes in this detachgroup have outro'd
<p>
<p outro:fade='{duration: 2000}' detachgroup:foo>
this will fade out over two seconds
</p>
<p>
this will detach immediately when `visible` becomes false, because
it's not part of any detachgroup
</p>
{{/if}} ( Chaining could maybe be done like this: {{#if visible}}
<p outro:fade='{priority: 2}'>
this will fade out once the other <p> fade out is complete
<p>
<p outro:fade='{priority: 1}'>
this will fade out first
</p>
{{/if}} Or maybe something like this: {{#if visible}}
<p outro:fade='{start: "foo.end"}'>
this will fade out once the other <p> fade out is complete
<p>
<p outro:fade='{name: "foo"}'>
this will fade out first
</p>
{{/if}} One possible answer to the problem of transitions-in-transitions: {{#if a}}
<div outro:fly>
<div outro:slide>this will slide out while flying out</div>
</div>
{{#if b}}
<div outro:spin>
this won't do anything if `b` becomes falsy
at the same time as `a`
</div>
{{/if}}
{{/if}} Maybe you'd want more control than that, I don't know. Finally, we'd want to have some control over the transition. If we did the <div transition:foo='{delay:500}' transitionparams:'{scale:2}'>...</div>
<div transition:foo='{delay:500, params: {scale: 2}}'>...</div>
<div transition:foo='{delay:500}, {scale: 2}'>...</div>
<div transition:foo='{scale: 2}, {delay:500}'>...</div> Feels good to try and articulate some of this stuff! Implementing any of it would probably feel less good... |
Nah, that's perfectly normal 😃.
Named grouping would be an interesting approach to detachment. It might get hairy with component boundaries and runtime tracking, which seems to be core to the issue of transitions in svelte. We're trying to avoid runtime wherever it can be, and transitions are inherently runtimey (at least they are to me). Given that and that you don't usually won't a ton of animations kicking off at the same time while, for instance, changing page routes, perhaps it would be better to simply limit transitioning to non-nested nodes (meaning no transitions within transitions) in the topmost transitioning component? The compiler can probably manage a bitmap of some sort for tracking transitioning nodes pretty safely/easily, but component boundaries would probably become a problem if you try to allow crossing them. It probably doesn't matter so much for intros. (Probably talking to myself for this, as I'm pretty sure you're already thought/dreamed through it much more thoroughly) Since all non-EOL browsers appear to support CSS transitions, I suppose you could base transitions entirely on those. Pass the whole transition params object into the transition function to get back the start and end state and allow it to add custom default It seems like transition sequences would be pretty reasonable to implement just by reading additional directives: That would certainly leave out ramjet-like things, but perhaps that's where transitions as an event hook/decorator comes back into play? |
Ack, component boundaries! Didn't think of that. Certainly does make things harder, or at least limit our ability to write the code ahead of time. If components emitted transition events (which I think they would have to in any case) then I suppose you could do this: <Widget on:foo.end='destroy()' visible='{{bar}}'/>
<!-- equivalent to this, if this was possible -->
{{#if bar}}
<Widget out:fade='{name:"foo"}/>
{{/if}}
(I'm imagining that setting I love the idea of Given all the headaches I've experienced with |
Will close this since we have transitions now |
Sorry to thread necromance 😁 but I was wondering if 4 years later there is a good practice for transition chaining. We're making a "Duolingo for cooking" PWA in Svelte (https://parsnip.ai/) and there are a lot of moments for the user where they complete something or were awarded a badge where we have to show several transitions sequentially. For now, I've just been chaining by using manually computed |
A UI library needs a transition system. Ideally it would have the following features:
out-in
, which is nice – could get even more granular for staggered transitions)visible
, and you toggle it again before the fade completes, it'd be great to unfade the same element, rather than letting the fade complete and rendering a new element)Proposed syntax, following that used by existing directives:
The text was updated successfully, but these errors were encountered: