Skip to content

Latest commit

 

History

History
350 lines (273 loc) · 11.7 KB

README.ja.md

File metadata and controls

350 lines (273 loc) · 11.7 KB

CSS Spring Animation

English | 日本語

直感的で動作の予測がしやすい CSS トランジションベースのスプリングアニメーションライブラリです。WWDC 2023 の Animate with springs にインスパイアされて開発されています。このライブラリの特徴は以下の通りです。

  • CSS トランジションを使ったスプリングアニメーションの実装
  • オプションが直感的で動作を予測しやすい
    • bounce: アニメーションのバウンス度合い
    • duration: アニメーションの長さ
  • ライブラリで使っている機能をサポートしていないブラウザに対しては requestAnimationFrame を使ったグレースフルデグラデーションでアニメーションを実行

Getting Started

Vue 用のバインディングがあります。npm (または yarn, pnpm) でインストールします。

$ npm install @css-spring-animation/vue

<script setup> を使っているシングルファイルコンポーネントでは以下のように spring コンポーネントを使うことができます。

<script setup>
import { ref } from 'vue'
import { spring } from '@css-spring-animation/vue'

const moved = ref(false)
</script>

<template>
  <button type="button" class="button" @click="moved = !moved">Toggle</button>

  <!-- :spring-style で指定されたスタイルに応じてアニメーションする <div> 要素を描画 -->
  <spring.div
    class="rectangle"
    :spring-style="{
      translate: moved ? '100px' : '0px',
    }"
    :duration="600"
    :bounce="0.3"
  ></spring.div>
</template>

spring. の後のプロパティ名が描画される要素名になります。例えば、<spring.div><div> 要素を描画します。要素は :spring-style プロパティで指定されたスタイルを持ちます。:spring-style プロパティの値が変更されるとスプリングアニメーションが実行されます。

Bounce と Duration

bounceduration オプションはバウンスの度合いとアニメーションの長さを指定するために使われます。

bounce
アニメーションのバウンス度合いを指定します。値は -1 から 1 の間で指定します。デフォルト値は 0 です。

duration
アニメーションの長さ(ミリ秒)を指定します。デフォルト値は 1000 です。

スタイル指定時の注意点

スタイルに含まれる数値はすべて同じ単位で、同じ順番で現れる必要があります。例えば、以下のような :spring-style の値は正しく動作しません。

<template>
  <!-- ❌ この例は正しく動きません -->
  <spring.div
    :spring-style="{ transform: flag ? 'translate(100px, 100px)' : 'scale(2)' }"
  ></spring.div>
</template>

これはライブラリがスタイル内の数値をパースして、それぞれの数値ごとにアニメーションを計算しているためです。ライブラリは translatescale の意味を解釈しませんし、100%100px の違いも予測できません。上記の例を正しく動作させるには、:spring-style に含まれる数値がすべて同じ単位、同じ順番で現れるようにする必要があります。

<template>
  <!-- ✅ :spring-style のすべての数値が同じ単位、同じ順番で現れている -->
  <spring.div
    :spring-style="{
      transform: flag
        ? 'scale(1) translate(100px, 100px)'
        : 'scale(2) translate(0, 0)',
    }"
  ></spring.div>
</template>

How It Works

このライブラリはアニメーションの対象となるスタイルのプロパティに、経過時間のカスタムプロパティを含む、スプリングアニメーションの数式をセットしています(そのカスタムプロパティを --t とします)。そして、CSS.registerProperty を使って --t を登録し、そのプロパティに対して CSS トランジションを適用します。スプリングアニメーションの擬似コードは以下のようになります。

// --t を登録
CSS.registerProperty({
  name: '--t',
  syntax: '<number>',
  inherits: false,
  initialValue: 0,
})

// 初期状態を設定
el.style.setProperty('--t', 0)

// --t を含むスプリングアニメーションの数式をセット
el.style.translate = 'calc(P * (A * var(--t) + B) * exp(-C * var(--t)) - Q)'

// 再描画を実行させる
requestAnimationFrame(() => {
  // アニメーションの開始
  el.style.setProperty('--t', 1)
  el.style.transition = '--t 1000ms linear'
})

また、このライブラリは CSS.registerProperty や CSS の exp() 関数をサポートしていないブラウザに対しては、CSS トランジションを使わず、requestAnimationFrame を使ったグレースフルデグラデーションでアニメーションを実行します。

API リファレンス

<spring> コンポーネント

<spring> コンポーネントは、プロパティ名と同じタグ名のネイティブ HTML 要素を描画します(例えば、<spring.div><div> 要素を描画します)。

プロパティ

  • spring-style: アニメーションさせるスタイルオブジェクト
  • bounce
  • duration
<script setup>
import { spring } from '@css-spring-animation/vue'

const position = ref(0)
</script>

<template>
  <spring.div
    :spring-style="{
      translate: `${position.value}px`,
    }"
    :duration="600"
    :bounce="0.3"
  ></spring.div>
</template>

<SpringTransition> コンポーネント

<SpringTransition> は Vue の <Transition> コンポーネントのスプリングアニメーション版です。enter 時には enter-from のスタイルから spring-style へ、leave 時には spring-style から leave-to のスタイルへとアニメーションを行います。

プロパティ

  • spring-style: 子要素のデフォルトスタイル
  • enter-from: enter 前の子要素のスタイル
  • leave-to: leave 後の子要素のスタイル。指定されていない場合は enter-from のスタイルが使われます。
  • mode
  • bounce
  • duration

イベント

  • before-enter
  • after-enter
  • enter-cancelled
  • before-leave
  • after-leave
  • leave-cancelled
<script setup>
import { ref } from 'vue'
import { SpringTransition } from '@css-spring-animation/vue'

const isShow = ref(false)
</script>

<template>
  <button type="button" class="button" @click="isShow = !isShow">Toggle</button>

  <!-- 子要素に対してスプリングアニメーションを行う -->
  <SpringTransition
    :spring-style="{
      translate: '0',
    }"
    :enter-from="{
      translate: '-100px',
    }"
    :leave-to="{
      translate: '100px',
    }"
    :duration="600"
    :bounce="0"
  >
    <!-- v-show の値が変わった時に .rectangle 要素がアニメーションする -->
    <div v-show="isShow" class="rectangle"></div>
  </SpringTransition>
</template>

<SpringTransitionGroup> コンポーネント

<SpringTransitionGroup> は Vue の <TransitionGroup> コンポーネントのスプリングアニメーション版です。<SpringTransition> と同じように spring-styleenter-fromleave-to のスタイルを指定できます。

Props

  • spring-style: 子要素のデフォルトスタイル
  • enter-from: enter 前の子要素のスタイル
  • leave-to: leave 後の子要素のスタイル。指定されていない場合は enter-from のスタイルが使われます。
  • tag: ラッパー要素のタグ名。デフォルト値: Fragment(ラッパー要素を描画しない)
  • bounce
  • duration

Events

  • before-enter
  • after-enter
  • enter-cancelled
  • before-leave
  • after-leave
  • leave-cancelled
<script setup>
import { SpringTransitionGroup } from '@css-spring-animation/vue'

const list = ref([
  // ...
])
</script>

<template>
  <!-- 子要素に対してスプリングアニメーションを行う -->
  <SpringTransitionGroup
    tag="ul"
    :spring-style="{
      opacity: 1,
    }"
    :enter-from="{
      opacity: 0,
    }"
    :leave-to="{
      opacity: 0,
    }"
    :duration="800"
    :bounce="0"
  >
    <!-- リストの項目は key プロパティを指定する必要あり -->
    <li v-for="item of list" :key="item.id">
      <!-- ... -->
    </li>
  </SpringTransitionGroup>
</template>

useSpring composable

スプリングアニメーションを適用した style オブジェクトを返す composable 関数です。また、現在のスタイル中の数値の実際の値と、速度も返します。これらは、スタイルオブジェクトと同じ形式のオブジェクトで、値が数値の配列になっています。

第一引数はアニメーションさせるスタイルを返す関数、または ref です。第二引数はオプションオブジェクトです。これも関数、または ref にすることができます。

<spring> コンポーネントでは実装できない複雑なユースケースで使うことを想定しています。

<script setup>
import { ref } from 'vue'
import { useSpring } from '@css-spring-animation/vue'

const position = ref(0)

const { style, realValue, realVelocity } = useSpring(
  () => {
    return {
      translate: `${position.value}px`,
    }
  },
  () => {
    return {
      duration: 600,
      bounce: 0.3,
    }
  },
)
</script>

<template>
  <div :style="style"></div>
  <ul>
    <li>realValue: {{ realValue.translate[0] }}</li>
    <li>realVelocity: {{ realVelocity.translate[0] }}</li>
  </ul>
</template>

useSpring が返す値には、現在のアニメーションが完了するまで待つ onFinishCurrent 関数があります。この関数には、進行中のアニメーションが完了したときに呼ばれるコールバック関数を登録できます。

<script setup>
import { ref } from 'vue'
import { useSpring } from '@css-spring-animation/vue'

const position = ref(0)

const { style, onFinishCurrent } = useSpring(() => {
  return {
    translate: `${position.value}px`,
  }
})

function move() {
  // 100px まで移動
  position.value = 100

  // 上記の position の更新によってトリガーされたアニメーションが完了するまで待つ
  onFinishCurrent(() => {
    // 0px まで移動
    position.value = 0
  })
}
</script>

v-spring-style, v-spring-options ディレクティブ

v-spring-style ディレクティブはアニメーションさせるスタイルを指定するために使います。v-spring-options ディレクティブはアニメーションのオプションを指定するために使います。

<script setup> ではない環境(<spring> コンポーネントを使えない)で使うことを想定しています。

springDirectives としてエクスポートされているプラグインオブジェクトを使ってディレクティブを登録できます。

import { createApp } from 'vue'
import App from './App.vue'
import { springDirectives } from '@css-spring-animation/vue'

createApp(App).use(springDirectives).mount('#app')

そして、テンプレートでディレクティブを使えます。

<template>
  <div
    v-spring-style="{
      translate: `${position}px`,
    }"
    v-spring-options="{
      duration: 600,
      bounce: 0.3,
    }"
  ></div>
</template>