mirror of https://github.com/sveltejs/svelte
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
172 lines
5.0 KiB
172 lines
5.0 KiB
---
|
|
title: transition:
|
|
---
|
|
|
|
A _transition_ is triggered by an element entering or leaving the DOM as a result of a state change.
|
|
|
|
When a block (such as an `{#if ...}` block) is transitioning out, all elements inside it, including those that do not have their own transitions, are kept in the DOM until every transition in the block has been completed.
|
|
|
|
The `transition:` directive indicates a _bidirectional_ transition, which means it can be smoothly reversed while the transition is in progress.
|
|
|
|
```svelte
|
|
<script>
|
|
+++import { fade } from 'svelte/transition';+++
|
|
|
|
let visible = $state(false);
|
|
</script>
|
|
|
|
<button onclick={() => visible = !visible}>toggle</button>
|
|
|
|
{#if visible}
|
|
<div +++transition:fade+++>fades in and out</div>
|
|
{/if}
|
|
```
|
|
|
|
## Built-in transitions
|
|
|
|
A selection of built-in transitions can be imported from the [`svelte/transition`](svelte-transition) module.
|
|
|
|
## Local vs global
|
|
|
|
Transitions are local by default. Local transitions only play when the block they belong to is created or destroyed, _not_ when parent blocks are created or destroyed.
|
|
|
|
```svelte
|
|
{#if x}
|
|
{#if y}
|
|
<p transition:fade>fades in and out only when y changes</p>
|
|
|
|
<p transition:fade|global>fades in and out when x or y change</p>
|
|
{/if}
|
|
{/if}
|
|
```
|
|
|
|
## Transition parameters
|
|
|
|
Transitions can have parameters.
|
|
|
|
(The double `{{curlies}}` aren't a special syntax; this is an object literal inside an expression tag.)
|
|
|
|
```svelte
|
|
{#if visible}
|
|
<div transition:fade={{ duration: 2000 }}>fades in and out over two seconds</div>
|
|
{/if}
|
|
```
|
|
|
|
## Custom transition functions
|
|
|
|
```js
|
|
/// copy: false
|
|
// @noErrors
|
|
transition = (node: HTMLElement, params: any, options: { direction: 'in' | 'out' | 'both' }) => {
|
|
delay?: number,
|
|
duration?: number,
|
|
easing?: (t: number) => number,
|
|
css?: (t: number, u: number) => string,
|
|
tick?: (t: number, u: number) => void
|
|
}
|
|
```
|
|
|
|
Transitions can use custom functions. If the returned object has a `css` function, Svelte will generate keyframes for a [web animation](https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API).
|
|
|
|
The `t` argument passed to `css` is a value between `0` and `1` after the `easing` function has been applied. _In_ transitions run from `0` to `1`, _out_ transitions run from `1` to `0` — in other words, `1` is the element's natural state, as though no transition had been applied. The `u` argument is equal to `1 - t`.
|
|
|
|
The function is called repeatedly _before_ the transition begins, with different `t` and `u` arguments.
|
|
|
|
```svelte
|
|
<!--- file: App.svelte --->
|
|
<script>
|
|
import { elasticOut } from 'svelte/easing';
|
|
|
|
/** @type {boolean} */
|
|
export let visible;
|
|
|
|
/**
|
|
* @param {HTMLElement} node
|
|
* @param {{ delay?: number, duration?: number, easing?: (t: number) => number }} params
|
|
*/
|
|
function whoosh(node, params) {
|
|
const existingTransform = getComputedStyle(node).transform.replace('none', '');
|
|
|
|
return {
|
|
delay: params.delay || 0,
|
|
duration: params.duration || 400,
|
|
easing: params.easing || elasticOut,
|
|
css: (t, u) => `transform: ${existingTransform} scale(${t})`
|
|
};
|
|
}
|
|
</script>
|
|
|
|
{#if visible}
|
|
<div in:whoosh>whooshes in</div>
|
|
{/if}
|
|
```
|
|
|
|
A custom transition function can also return a `tick` function, which is called _during_ the transition with the same `t` and `u` arguments.
|
|
|
|
> [!NOTE] If it's possible to use `css` instead of `tick`, do so — web animations can run off the main thread, preventing jank on slower devices.
|
|
|
|
```svelte
|
|
<!--- file: App.svelte --->
|
|
<script>
|
|
export let visible = false;
|
|
|
|
/**
|
|
* @param {HTMLElement} node
|
|
* @param {{ speed?: number }} params
|
|
*/
|
|
function typewriter(node, { speed = 1 }) {
|
|
const valid = node.childNodes.length === 1 && node.childNodes[0].nodeType === Node.TEXT_NODE;
|
|
|
|
if (!valid) {
|
|
throw new Error(`This transition only works on elements with a single text node child`);
|
|
}
|
|
|
|
const text = node.textContent;
|
|
const duration = text.length / (speed * 0.01);
|
|
|
|
return {
|
|
duration,
|
|
tick: (t) => {
|
|
const i = ~~(text.length * t);
|
|
node.textContent = text.slice(0, i);
|
|
}
|
|
};
|
|
}
|
|
</script>
|
|
|
|
{#if visible}
|
|
<p in:typewriter={{ speed: 1 }}>The quick brown fox jumps over the lazy dog</p>
|
|
{/if}
|
|
```
|
|
|
|
If a transition returns a function instead of a transition object, the function will be called in the next microtask. This allows multiple transitions to coordinate, making [crossfade effects](/tutorial/deferred-transitions) possible.
|
|
|
|
Transition functions also receive a third argument, `options`, which contains information about the transition.
|
|
|
|
Available values in the `options` object are:
|
|
|
|
- `direction` - one of `in`, `out`, or `both` depending on the type of transition
|
|
|
|
## Transition events
|
|
|
|
An element with transitions will dispatch the following events in addition to any standard DOM events:
|
|
|
|
- `introstart`
|
|
- `introend`
|
|
- `outrostart`
|
|
- `outroend`
|
|
|
|
```svelte
|
|
{#if visible}
|
|
<p
|
|
transition:fly={{ y: 200, duration: 2000 }}
|
|
onintrostart={() => (status = 'intro started')}
|
|
onoutrostart={() => (status = 'outro started')}
|
|
onintroend={() => (status = 'intro ended')}
|
|
onoutroend={() => (status = 'outro ended')}
|
|
>
|
|
Flies in and out
|
|
</p>
|
|
{/if}
|
|
```
|