Comments (7)
Does that including transpile CSS2/3 syntax with dynamic value to Javascript on SSR or client side?
Ramjet was nicely done for complex animation!
from svelte.
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 on:mount
/on:unmount
set of hooks per element where the unmount
saves DOM detachment until a returned Promise resolves, I don't think you could get much simpler.
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.
from svelte.
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 t
(the progress through the transition) then maybe reversible transitions are possible:
{{#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. t === 0.05
) and visible
becomes true once again, there's no need for any sort of cancellable Promise hackery or anything like that.
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 t => [style]
function.
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}}
(detachgroup
isn't a particularly elegant name, I'll confess. outgroup
?)
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 t => [style]
thing, then some parameters would be for Svelte to worry about (duration, delay, easing etc) but some would be specific to the transition function itself. So I guess we'd need to do one of these:
<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...
from svelte.
I actually fell asleep thinking about reversible transitions last night (I know, I'm weird).
Nah, that's perfectly normal π.
I wondered if maybe the detaching problem could be solved like so:
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 duration
, delay
, etc to the params object if it so desires. Then implementing the transition becomes: record current property values based on the start state, set the initial properties from the start state, install an appropriate inline transition rule, set the end properties from the end state, somehow watch for interruption (property/function on the node? local flag var, since svelte has the technology?), and add a transitionend
listener, if it will actually fire (probably set a duration
timeout too, just in case). If the transition is interrupted, kill the timer and listener, re-apply the start state, and install a new listener and timer. When the end happens, kill the timer and listener and apply the initial state.
It seems like transition sequences would be pretty reasonable to implement just by reading additional directives: <div in:grow in:fade out:fade out:shrink>...</div>
, which would gather the states for all specified transitions, apply all of the initial states together, and then apply each successive end state as prior transitions completed, adjusting the duration and delay on the inline transition rule as needed along the way. I'd say that parallel transitions would be better left to combined transitions (in:growAndFade
) or perhaps even a svelte built-in e.g. <div in:style="{ opacity: 0; height: '0px' }">...</div>
where the second state is implied to be the initial state of the element (for intro, the end state is implicit, and for outro, the start state is implicit). Actually, thinking about it, I think that style
transition would cover 95% of my transition use already.
That would certainly leave out ramjet-like things, but perhaps that's where transitions as an event hook/decorator comes back into play?
from svelte.
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 visible
to false
would trigger a foo.start
event followed by a foo.end
one, because of name:"foo"
. Perhaps we would also have transition.end
and outro.start
and whatever else β details to ponder another time.)
I love the idea of in:style='{...}'
, particularly it being built in. That would indeed meet 95% of situations. Would like to support the other 5% though as it includes nifty stuff like SVG stroke-dasharray hacks and typewriter effects, which are a guilty pleasure of mine. I'd probably use ramjet-style effects a lot more if it wasn't such a PITA as well.
Given all the headaches I've experienced with transitionend
events, I was wondering if it would be possible to do all this just with timers β i.e. set a 2 second transition off, and assume it's completed when the first requestAnimationFrame
callback happens that's more than 2000 milliseconds in the future. Don't know how bulletproof that is.
from svelte.
Will close this since we have transitions now
from svelte.
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}}
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 delay
values.
from svelte.
Related Issues (20)
- Reactivity problem with fromStore() and objects HOT 1
- feat: fromStore() should be a rune HOT 6
- `state_reference_locally` warning message is unclear HOT 3
- Svelte 5 error "Cannot access '_' before initialization" in version 241 HOT 4
- Injecting CSS via <svelte:head> breaks loading +layout css
- TypeError: Cannot read properties of null (reading 'nodeType') (Astro + Svelte 5) HOT 1
- CSS class hashes do not go down the component tree HOT 1
- CSS zoom on grid breaks flip HOT 5
- [Svelte 5] No more "Attributes need to be unique" error on duplicate class:name and style:property directives
- [feat] Upgrade class:name to choose a class name from multiple values HOT 4
- Svelte 4: elements inside {#each} with "out:" transition get stuck in DOM during changes to store used by {#each}
- [Svelte5] A new rune to create state from a `$props()` value HOT 2
- False positive βupdated, but not declared with `$state`β warning HOT 26
- All Typescript features that modify code are broken HOT 3
- Introduce the $id() rune HOT 2
- Leaving class attribute empty in <a> tag breaks the app
- .svelte.ts files break custom elements HOT 1
- Automatic Conversion of Multiple Snippets into an Array in Props HOT 5
- Svelte 5 next.179+: SSR regression HOT 35
- Binding through function? Functional binding? Bind transformation? Unsure which "name" would be best HOT 6
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. πππ
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google β€οΈ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from svelte.