Skip to main content

transition:

transition は、state の変化の結果として DOM に要素が出入りする際にトリガーされます。

ブロック (例えば {#if ...} ブロック) が外へ transition している間、その中のすべての要素 (独自の transition を持たないものも含む) は、ブロック内のすべての transition が完了するまで DOM に保持されます。

transition: ディレクティブは 双方向 transition を示します。これにより、transition の進行中でもスムーズに反転させることができることを意味しています。

<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

組み込みの transition は、svelte/transition モジュールからインポートすることができます。

Local vs global

transition はデフォルトで local です。local transition は、それが属するブロックが作成または破棄されるときにのみ実行され、親ブロックが作成または破棄されるときには実行されません。

{#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

transition にはパラメータを指定することができます。

(二重の {{中括弧}} は特別な構文ではありません。これは式タグ内のオブジェクトリテラルです。)

{#if visible}
	<div transition:fade={{ duration: 2000 }}>fades in and out over two seconds</div>
{/if}

Custom transition functions

transition = (node: HTMLElementnode: HTMLElement, params: anyparams: any, 
options: {
    direction: "in" | "out" | "both";
}
options
: { direction: "in" | "out" | "both"direction: 'in' | 'out' | 'both' }) => {
delay?: number, duration?: number, easing?: (t: numbert: number) => number, css?: (t: numbert: number, u: numberu: number) => string, tick?: (t: numbert: number, u: numberu: number) => void }

transition にはカスタム関数を使用することができます。返されるオブジェクトに css 関数が含まれている場合、Svelte は web animation のキーフレームを生成します。

css に渡される t 引数は、easing 関数が適用された後の 0 から 1 の間の値です。in transition は 0 から 1 に進行し、out transition は 1 から 0 に進行します — 言い換えると、1 は transition が適用されていない要素の自然な状態です。u 引数は 1 - t に等しい値です。

この関数は、transition が開始される前に、異なる t および u 引数とともに繰り返し呼び出されます。

App
<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}
<script lang="ts">
	import { elasticOut } from 'svelte/easing';

	export let visible: boolean;

	function whoosh(node: HTMLElement, params: { delay?: number, duration?: number, easing?: (t: number) => number }) {
		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}

カスタムの transition 関数は、transition の途中で同じ tu の引数と共に呼び出される tick 関数を返すこともできます。

tick の代わりに css を使用できる場合は、そうしてください — web animation はメインスレッドの外で実行されるため、低速なデバイスでのカクつきを防ぐことができます。

App
<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}
<script lang="ts">
	export let visible = false;

	function typewriter(node: HTMLElement, { speed = 1 }: { speed?: number }) {
		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}

transition が transition オブジェクトの代わりに関数を返す場合、その関数は次のマイクロタスク内で呼び出されます。これにより、複数の transition が調整され、クロスフェード効果 を実現できます。

transition 関数は、transition に関する情報を含む第3引数 options を受け取ります。

options オブジェクトで使用可能な値は以下の通りです:

  • direction - transition のタイプに応じて inoutboth のいずれか

Transition events

transition を持つ要素は、標準の DOM イベントに加えて次のイベントをディスパッチします:

  • introstart
  • introend
  • outrostart
  • outroend
{#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}

Edit this page on GitHub

previous next