CSSアニメーションワークレットAPI

W3C 初公開ワーキングドラフト,

このバージョン:
https://www.w3.org/TR/2019/WD-css-animation-worklet-1-20190625/
最新公開バージョン:
https://www.w3.org/TR/css-animation-worklet-1/
編集者ドラフト:
https://drafts.css-houdini.org/css-animationworklet-1/
フィードバック:
public-houdini@w3.org 件名 “[css-animation-worklet] … メッセージのトピック …” (アーカイブ)
課題追跡:
仕様内インライン
GitHub Issues
編集者:

概要

Animation Worklet APIは、一連のアニメーション効果を制御するスクリプトアニメーションを作成するための方法を提供します。このAPIは、ユーザーエージェントがそのようなアニメーションを専用スレッドで実行し、メインスレッドから分離したパフォーマンスを一定程度確保できるように設計されています。

この文書のステータス

このセクションでは、公開時点の文書のステータスについて説明します。他の文書が本書に取って代わる場合があります。現在のW3Cの出版物一覧およびこの技術レポートの最新の改訂版は、W3C技術レポート一覧(https://www.w3.org/TR/)で確認できます。

この文書は最初の公開ワーキングドラフトです。

最初の公開ワーキングドラフトとして公開されたことは、W3Cメンバーシップによる承認を意味するものではありません。この文書はドラフトであり、随時更新・差し替え・廃止される可能性があります。進行中の作業以外としてこの文書を引用するのは不適切です。

この仕様の議論にはGitHub Issuesをご利用ください。課題を提出する際は、タイトルに「css-animation-worklet」という文字列を含めてください。例:「[css-animation-worklet] …コメント概要…」。すべての課題やコメントはアーカイブされています。

この文書はCSSワーキンググループによって作成されました。

この文書は、W3C特許ポリシーの下で活動するグループによって作成されました。W3Cは、そのグループの成果物に関連する特許開示の公開リストを維持しています。そのページには特許開示の方法についても記載されています。ある個人が、必須クレームを含むと信じる特許について実際に知っている場合、その情報をW3C特許ポリシー第6節に従って開示しなければなりません。

この文書は、2019年3月1日版W3Cプロセス文書に従って管理されています。

1. はじめに

このセクションは規範的ではありません。

この文書では、ウェブアニメーションの拡張性を提供し、ウェブ上で高パフォーマンスなインタラクティブな手続き型アニメーションを可能にする新しいプリミティブを紹介します。詳細な動機や背景については [explainer] および [principles] を参照してください。

Animation Worklet APIは、一連のアニメーション効果を制御するスクリプトアニメーションを作成するための方法を提供します。このAPIは、ユーザーエージェントがそのようなアニメーションを専用スレッドで実行し、メインスレッドから分離したパフォーマンスを一定程度確保できるように設計されています。

1.1. Web Animations APIとの関係

このセクションは規範的ではありません。

Animation Worklet実行コンテキスト内で動作するアニメーションは、メインのJavaScript実行コンテキスト上でWeb Animations仕様のAnimation インターフェイスを公開します。つまり、メインスレッドから同じWeb Animation APIを使って制御や検査が可能です。

2. Animation Worklet

Animation Workletは、 Worklet であり、カスタムアニメーションに関連するすべてのクラスを管理します。このworkletはanimationWorklet 属性からアクセスできます。

animationWorkletworkletグローバルスコープ型AnimationWorkletGlobalScopeです。

AnimationWorkletGlobalScopeanimationWorkletのグローバルな実行コンテキストを表します。

[Exposed=Window]
partial namespace CSS {
    [SameObject] readonly attribute Worklet animationWorklet;
};

3. Animator

Animatorは、アニメーションスレッド上で動作するアニメーションインスタンスを表します。 Animatorは一意の名前によって識別され、現在の入力時間に応じてアニメーションのキーフレーム効果がどのように進行するかを決定します。AnimatorインスタンスはAnimationWorkletGlobalScope 内に存在し、各インスタンスはWorkletAnimation インスタンスに関連付けられています。AnimatorはWorkletAnimation の構築によってのみインスタンス化されます。

2種類のAnimatorがサポートされています:StatelessAnimatorStatefulAnimatorであり、 それぞれ異なる状態管理戦略を提供します。

3.1. StatelessAnimatorインターフェイス

このインターフェイスはステートレスなアニメーターを表します。このタイプのアニメーターは、インスタンスやグローバルスコープに保存されるローカル状態に依存しません。実質的に、StatelessAnimator のanimate関数は、同じ入力に対して常に同じ出力を生成する純粋関数として扱うことができます。

[Exposed=AnimationWorklet, Global=AnimationWorklet, Constructor (optional any options)]
interface StatelessAnimator {
};
クラスの例は以下の通りです。
class FooAnimator extends StatelessAnimator {
    constructor(options) {
        // 新しいアニメーターがインスタンス化されたときに呼び出されます。
    }
    animate(currentTime, effect) {
        // アニメーションフレームのロジックはここに記述します。
    }
}

注: ステートレスであることで、アニメーションワークレットは複数のアニメーションフレームを並列に生成したり、非常に安価な初期化・解体処理などの最適化が可能です。このような最適化を可能にするため、StatelessAnimatorの利用が強く推奨されます。

3.2. StatefulAnimatorインターフェイス

このインターフェイスはステートフルなアニメーターを表します。このアニメーターはローカル状態を持つことができ、アニメーションワークレットは、このインターフェイスが要求する契約を満たす限り状態の維持を保証します。

Animation worklet は、異なるスレッドやプロセスにまたがって存在する可能性がある複数のWorkletGlobalScopeを管理します。アニメーションワークレットは、(例:リソースを節約するため)グローバルスコープを一時的に終了したり、(例:特定のスレッドでのみエフェクトが変更可能な場合)実行中のアニメーターインスタンスを異なるグローバルスコープへ移行させることがあります。アニメーションワークレットは、ステートフルアニメーターインスタンスの状態が、インスタンスが異なるグローバルスコープで再生成されても保持されることを保証します。

状態維持の基本的な仕組みは、アニメーションワークレットがlocal stateとしてstate 関数を通じて公開される情報をスナップショットし、後で異なるグローバルスコープでインスタンスが再生成される際に、コンストラクタに渡せるように再現することです。アニメーターインスタンスの移行アルゴリズムは、このプロセスの詳細を記載しています。

ユーザー定義のステートフルアニメーターは、state関数が構造化複製アルゴリズムでシリアライズ可能な状態オブジェクトを返し、同じオブジェクトがコンストラクタに渡された場合に状態を再現できることが契約として求められます。

[Exposed=AnimationWorklet, Global=AnimationWorklet,
Constructor (optional any options, optional any state)]
interface StatefulAnimator {
  any state();
};
このクラスは次のようになります。
class BarAnimator extends StatefulAnimator {
    constructor(options, state) {
      // 新しいアニメーターがインスタンス化されたとき(初回または再生成時)に呼び出されます。
      this.currentVelocity  = state ? state.velocity : 0;
    }
    animate(currentTime, effect) {
        // アニメーションフレームのロジックはここに記述され、this.currentVelocityに依存できます。
        this.currentVelocity += 0.1;
    }
    state() {
      // 返されるオブジェクトは構造化可能なクローンアルゴリズムでシリアライズできる必要があります。
      return {
        velocity: this.currentVelocity;
      }
    }
}

3.3. アニメーター定義

アニメーター定義は、構造体であり、AnimationWorkletGlobalScopeによって必要とされる、著者定義のカスタムアニメーションを記述します。アニメーター定義は以下を含みます:

3.4. アニメーター定義の登録

AnimationWorkletGlobalScopeアニメーター名とアニメーター定義のマップを持ちます。 このマップは、registerAnimator(name, animatorCtor) が呼び出されたときに登録されます。
[ Exposed=AnimationWorklet, Global=AnimationWorklet ]
interface AnimationWorkletGlobalScope : WorkletGlobalScope {
    void registerAnimator(DOMString name, AnimatorInstanceConstructor animatorCtor);
};

callback AnimatorInstanceConstructor = any (any options, optional any state);

registerAnimator(name, animatorCtor) メソッドがAnimationWorkletGlobalScopeで呼び出されたとき、ユーザーエージェントは 次のステップを必ず実行しなければなりません:

  1. nameが有効な<ident>でない場合、throwTypeErrorを投げ、すべてのステップを中止する。

  2. nameアニメーター名とアニメーター定義のマップのキーとして存在する場合、throwNotSupportedErrorを投げ、すべてのステップを中止する。

  3. IsConstructor(animatorCtor)の結果がfalseの場合、throwTypeErrorを投げ、すべてのステップを中止する。

  4. prototypeGet(animatorCtor, "prototype")の結果とする。

  5. SameValue(prototype, StatelessAnimator) がtrueの場合、statefulfalseにする。そうでなくSameValue(prototype, StatefulAnimator) がtrueの場合、statefultrueにする。それ以外の場合はthrowTypeErrorを投げ、すべてのステップを中止する。

  6. animateValueGet(prototype, "animate")の結果とする。

  7. animate変換してanimateValueFunction コールバック関数型にする。例外が投げられた場合は、その例外を再スローし、すべてのステップを中止する。

  8. definitionを新しいアニメーター定義とし、次の内容を持つ:

  9. キーと値のペア(name - definition)をアニメーター名とアニメーター定義のマップに追加する。

4. アニメーターインスタンス

アニメーターインスタンスは、構造体であり、AnimationWorkletGlobalScope内で完全に実現されたカスタムアニメーションインスタンスを記述します。 アニメーター定義への参照を持ち、アニメーション効果やタイムラインなどインスタンス固有の状態を所有します。以下を含みます:

ステートフルアニメーターインスタンスは、対応するアニメーターインスタンスアニメーター定義ステートフルフラグtrueのものです。

4.1. アニメーターインスタンスの作成

アニメーターインスタンスAnimationWorkletGlobalScope内に存在します。

AnimationWorkletGlobalScopeアニメーターインスタンス集合を持ちます。この集合は、ユーザーエージェントがAnimationWorkletGlobalScopeスコープ内で新しいアニメーターインスタンスを構築した時に登録されます。各アニメーターインスタンスはドキュメントスコープ内のworklet animationに対応します。

nametimelineeffectserializedOptionsserializedStateworkletGlobalScopeが与えられた時、新しいアニメーターインスタンスを作成するために、ユーザーエージェントは以下の手順を必ず実行します:

  1. definitionworkletGlobalScopeアニメーター名とアニメーター定義のマップからnameで検索した結果とする。

    definitionが存在しない場合、以降の手順を中止する。

  2. animatorCtordefinitionクラスコンストラクターとする。

  3. optionsStructuredDeserialize(serializedOptions)とする。

  4. stateStructuredDeserialize(serializedState)とする。

  5. animatorInstanceanimatorCtorの構築(引数は«options, state»)の結果とする。例外が発生した場合は再スローし、すべての手順を中止する。

  6. animatorInstanceに以下を設定する:

  7. animatorInstanceworkletGlobalScopeアニメーターインスタンス集合に追加する。

4.2. アニメーターの実行

ユーザーエージェントが新しいアニメーションフレームを生成しようとする時、任意のアニメーターインスタンスの関連するアニメーションリクエストフラグframe-requestedであれば、ユーザーエージェントはそのフレームで必ずアニメーターを実行しなければなりません。

注: ユーザーエージェントは全ての表示フレームでアニメーションを実行する必要はありません。後のフレームまでアニメーションフレームの生成を延期することは許容されます。これにより、ユーザーエージェントはポリシーに応じて異なるサービスレベルを提供できます。

ユーザーエージェントがworkletGlobalScope内でアニメーターを実行する場合、workletGlobalScopeアニメーターインスタンス集合内の全てのアニメーターインスタンスを反復します。各instanceに対して、ユーザーエージェントは以下の手順を必ず実行します:

  1. animatorNameinstanceアニメーター名とする

  2. definitionworkletGlobalScopeアニメーター名とアニメーター定義のマップからanimatorNameで検索した結果とする。

    definitionが存在しない場合、以降の手順を中止する。

  3. instanceアニメーションリクエストフラグframe-currentである、もしくはinstanceの効果が現在のフレームのビジュアルビューポート内に表示されない場合、ユーザーエージェントは以降の手順を省略可能です。

    ユーザーエージェントが遅いアニメーターをスロットルするために実行をスキップする権限を与えることを検討してください。

  4. animateFunctiondefinitionanimate関数とする。

  5. currentTimeinstanceアニメーター現在時刻とする。

  6. effectinstanceアニメーター効果とする。

  7. animateFunctionをコールバックとして呼び出す(引数は«currentTime, effect»、コールバックthis値はinstance)。

注: 非効率的ではありますが、同じフレーム内でユーザーエージェントがアニメーターを複数回実行することは合法です。

animateFunctionが例外を投げた場合の挙動を明示するべきです。少なくとも、キー フレームのlocalTime値は無視されるため、誤った部分更新が発生しない旨の文言が必要です。

4.3. アニメーターインスタンスの削除

instanceworkletGlobalScopeが与えられたとき、アニメーターインスタンスを削除するには、ユーザーエージェントは以下の手順を必ず実行します:

  1. instanceworkletGlobalScopeアニメーターインスタンス集合から削除する。

4.4. アニメーターインスタンスの移行

移行プロセスでは、ステートフルアニメーターインスタンスを別のWorkletGlobalScopeにローカル状態を失うことなく移行できます。

ある WorkletGlobalScope から別の WorkletGlobalScopeアニメーターインスタンスを移行するには、instancesourceWorkletGlobalScopedestinationWorkletGlobalScope が与えられた場合、ユーザーエージェントは以下の手順を 必ず 実行しなければならない:

  1. serializedStateを未定義とする。

  2. タスクをキューし、sourceWorkletGlobalScopeで以下の手順を実行する:

    1. animatorNameinstanceアニメーター名とする。

    2. definitionsourceWorkletGlobalScopeアニメーター名とアニメーター定義のマップから検索した結果とする。

      definitionが存在しなければ、以降の手順を中止する。

    3. statefuldefinitionステートフルフラグとする。

    4. statefulfalseなら、以降の手順を中止する。

    5. stateFunctionを取得する。

    6. statestateFunctionを呼び出し、コールバックthis値としてinstanceを渡す結果とする。例外が発生した場合は再スローし、以降の手順を中止する。

    7. serializedStateStructuredSerialize(state)の結果とする。 例外が発生した場合、以降の手順を中止する。

    8. instancesourceWorkletGlobalScopeを指定してアニメーターインスタンスの削除手順を実行する。

  3. 上記タスクの完了を待つ。タスクが中止された場合、以降の手順を中止する。

  4. タスクをキューし、destinationWorkletGlobalScopeで以下の手順を実行する:

    1. 新しいアニメーターインスタンスの作成手順を以下の引数で実行する:

アニメーターのstate getterが例外を投げた場合、ユーザーエージェントはそのアニメーターを削除し再生成しません。 これによりそのアニメーターインスタンスは実質的に削除されます。

4.5. アニメーションフレームのリクエスト

アニメーターインスタンスは、関連するアニメーションリクエストフラグを持ちます。これはframe-requestedまたはframe-currentのいずれかです。初期値はframe-currentです。様々な状況によりアニメーションリクエストフラグframe-requestedに設定されることがあります。例:

§4.2 アニメーターの実行では、アニメーターのアニメーションリクエストフラグframe-currentにリセットします。

5. Web Animations統合

5.1. Worklet Animation

Worklet Animationは、アニメーションの一種であり、アニメーション再生をアニメーターインスタンスに委譲します。対応するアニメーターインスタンスのライフタイムや再生状態を制御します。

アニメーションであるため、Worklet Animationアニメーション効果タイムラインを持ちます。ただし他のアニメーションとは異なり、Worklet Animationの現在時刻はアニメーション効果のlocal timeinherited time経由)を直接決定しません。 代わりに、関連するアニメーターインスタンスがアニメーション効果のlocal timeを直接制御します。つまり、タイムラインの現在時刻だけではアニメーションの出力は完全に決定されません。

Worklet Animationは、Animationインターフェイスに加えて、以下のプロパティを持ちます:

WorkletAnimationタイミングモデルの概要。
WorkletAnimationタイミングモデルの概要。

アニメーションの現在時刻はアニメーターインスタンスへの入力となり、アニメーション効果のローカル時刻値を生成します。アニメーターインスタンスが並列グローバルスコープで実行されている場合、実装はローカル時刻値を用いて最終的な効果値を生成し、ビジュアルの更新を並列で行うこともできます。

5.2. Worklet Animationの作成

[Exposed=Window,
 Constructor (DOMString animatorName,
              optional (AnimationEffect or sequence<AnimationEffect>)? effects = null,
              optional AnimationTimeline? timeline,
              optional any options)]
interface WorkletAnimation : Animation {
    readonly attribute DOMString animatorName;
};

WorkletAnimation(animatorName, effects, timeline, options)

以下の手順で新しいWorkletAnimationオブジェクトを作成します。

  1. workletAnimationを新しいWorkletAnimationオブジェクトとする。

  2. workletAnimationに対してアニメーションのタイムラインを設定する手順を実行する。timeline引数が指定されていればそれを新しいタイムラインとして渡し、指定されていなければ関連するDocumentデフォルトドキュメントタイムラインを渡す。Window現在のグローバルオブジェクトである。

  3. 以下の最初に一致する条件に従ってeffectを決定する。

    もしeffectsAnimationEffectオブジェクトの場合、

    effecteffectsとする。

    もしeffectsAnimationEffectオブジェクトのリストの場合、

    effectは子をeffectsとする新しいWorkletGroupEffectとする。

    それ以外の場合、

    effectは未定義とする。

  4. workletAnimationに対してアニメーションのターゲット効果を設定する手順を実行し、effectを新しい効果として渡す。

  5. serializedOptionsStructuredSerialize(options)の結果とする。例外が発生した場合は再スローする。

  6. workletAnimationシリアライズオプションserializedOptionsを設定する。

  7. workletAnimationanimation animator nameanimatorNameを設定する。

5.3. Worklet Animationのタイミングモデル

このセクションでは、worklet animationのタイミングモデルが他のアニメーションとどのように異なるかを説明します。

既存のアニメーションreadyとみなされる条件に加え、worklet animationは以下の条件が満たされた場合にのみreadyとみなされます:

§5.1 Worklet Animationで説明されている通り、worklet animationcurrent timeは、そのanimation effectlocal timeを決定しません。代わりに、関連付けられたanimator instancelocal timeを直接制御します。つまり、アニメーション効果のlocal timeはWorkletGlobalScope(並列実行コンテキストである可能性があります)から制御されます。

上記の意味論から導かれる影響は以下の通りです:

Worklet Animationが並列worklet実行コンテキストで実行されている場合、そのアニメーション効果の最新状態は定期的にメインJavaScript実行コンテキストに同期されるべきです。並列worklet実行コンテキストからメインJavaScript実行コンテキストへのeffect valuesの同期は、ドキュメントライフサイクルの一部としてアニメーションフレームコールバックが実行される前に必ず行われなければなりません。このアニメーションモデルの非同期性により、メインJavaScript実行コンテキストでWorklet Animationでアニメーションされているtarget propertyをスクリプトから読み取る場合、ユーザーに表示されているビジュアルフレームで使われている値と比べて古い値が表示される場合があります。これはメインJavaScript実行コンテキストでスクロールオフセットを読むときの非同期スクロールの効果に類似しています。

animator instanceがanimation currentTimeの変更(例えばreverse()、finish()、playbackRateの変更)を通知される適切な仕組みを考案すべきです。これにより適切に反応できるようになります。<https://github.com/w3c/css-houdini-drafts/issues/811>

5.4. アニメーターインスタンスとの連携

worklet animationは任意の時点で最大1つのanimator instanceに対応し、対応するanimator instanceが存在しない場合もあります。worklet animationに対するanimator instanceの対応関係は、アニメーションのplay stateに依存します。

worklet animationのanimator instanceを関連付けるにはworkletAnimationが与えられたとき、ユーザーエージェントは以下の手順を必ず実行します:

  1. workletAnimationに対応するanimator instanceが存在する場合、以降の手順を中止する。

  2. workletGlobalScopeworkletAnimationに関連付けられたAnimationWorkletGlobalScopeとする。

  3. taskをworkletGlobalScopeでキューイングし、以下の値を渡して新しいanimator instanceを作成する手順を実行する:

  4. 手順が成功した場合、結果のanimator instanceworkletAnimationに対応させる。

worklet animationのanimator instanceの関連付け解除にはworkletAnimationが与えられたとき、ユーザーエージェントは以下の手順を必ず実行します:

  1. workletAnimationに対応するanimator instanceが存在しない場合、以降の手順を中止する。

  2. workletGlobalScopeworkletAnimationに関連付けられたAnimationWorkletGlobalScopeとする。

  3. animatorInstanceworkletAnimationの対応するanimator instanceとする。

  4. taskをworkletGlobalScopeでキューイングし、animatorInstance(instanceとして)、workletGlobalScope(workletGlobalScopeとして)を渡してanimator instanceを削除する手順を実行する。

  5. workletAnimationは対応するanimator instanceを持たない状態にする。

worklet animationのanimator instanceをセットするにはworkletAnimationが与えられたとき、ユーザーエージェントは以下の手順を必ず実行します:

  1. worklet animationのanimator instanceの関連付け解除の手順をworkletAnimationに対して実行する。

  2. worklet animationのanimator instanceを関連付ける手順をworkletAnimationに対して実行する。

与えられたworkletAnimationplay statependingrunning、またはpausedに変化した場合、worklet animationのanimator instanceを関連付ける手順をworkletAnimationに対して実行する。

与えられたworkletAnimationplay stateidleまたはfinishedに変化した場合、worklet animationのanimator instanceの関連付け解除手順をworkletAnimationに対して実行する。

与えられたworkletAnimationに対してset the target effect of an animation手順が呼ばれた場合、worklet animationのanimator instanceをセットする手順をworkletAnimationに対して実行する。

与えられたworkletAnimationに対してset the timeline of an animation手順が呼ばれた場合、worklet animationのanimator instanceをセットする手順をworkletAnimationに対して実行する。

5.5. ScrollTimeline

このセクションは規範的ではありません。

ScrollTimeline はウェブアニメーションAPIに追加提案されている新しい概念です。スクロールコンテナのスクロール位置に応じて時間値が変化するアニメーションタイムラインを定義します。Workletアニメーションはスクロールタイムラインを持つことができ、スクロールオフセットに基づいてスクリプト効果を駆動できます。

注: 入力へのアクセス: スクロール以外にも(タッチやポインター入力など)、追加のユーザー入力をこれらのアニメーションに公開することに関心があります。これにより、著者は現在は困難な入力駆動型のジャンクのないアニメーションを作成できるようになります。適切な抽象化やメカニズムを検討中です。

5.6. WorkletGroupEffect

WorkletGroupEffectグループエフェクトの一種であり、子エフェクトlocalTimeを個別に操作できます。

WorkletGroupEffectWorkletAnimationanimation effectに設定されている場合、対応するanimator instance子エフェクトlocalTimeを直接制御できます。これにより、1つのworkletアニメーションで複数のエフェクトを連携させることができます。使用例は§8.2 例2: パララックス背景を参照してください。

[Exposed=AnimationWorklet]
interface WorkletGroupEffect {
  sequence<AnimationEffect> getChildren();
};

[Exposed=AnimationWorklet]
partial interface AnimationEffect {
    // Intended for use inside Animation Worklet scope to drive the effect.
    attribute double localTime;
};

effectlocalTime プロパティに値tを設定するには、ユーザーエージェントは次の最初に一致する条件のアクションを実行します:

親グループを持たない場合

effectのlocalTimeをtに設定する。

親グループがあり、その型がWorkletGroupEffectの場合

effectのstartTimeを(親の変換後の時間 - t)に設定する。これは実質的にeffectのlocalTimeをtに設定することになります。

それ以外の場合

子エフェクトの時間は親グループによってのみ制御可能であることを示す例外を投げる。

上記インターフェースはweb-animation-2で提案されているGroupEffectの保守的なサブセットのみを公開しています。代わりにweb-animationへの差分仕様に移行すべきです。<https://github.com/w3c/csswg-drafts/issues/2071>

5.7. エフェクトスタックと合成順序

他のアニメーションと同様に、workletアニメーションエフェクトスタックに参加します。workletアニメーションは特定のanimation classを持たないため、他のJavaScriptで作成されたWebアニメーションと同じ合成順序となります。

6. セキュリティの考慮事項

これらの機能による既知のセキュリティ問題はありません。

7. プライバシーの考慮事項

これらの機能による既知のプライバシー問題はありません。

8.

8.1. 例1: Twitterヘッダー

Twitterプロフィールヘッダー効果の例。2つの要素(アバターとヘッダー)がスクロールオフセットと同期して更新されます。
// 文書スコープ内。
<div id='scrollingContainer'>
  <div id='header' style='height: 150px'></div>
  <div id='avatar'><img></div>
</div>

<script>
await CSS.animationWorklet.addModule('twitter-header-animator.js');
const animation = new WorkletAnimation(
    'twitter-header',
    [new KeyframeEffect($avatar,  /* スクロールアップで縮小 */
                    [{transform: 'scale(1)'}, {transform: 'scale(0.5)'}],
                    {duration: 1000, iterations: 1}),
    new KeyframeEffect($header, /* スクロールアップで透明度が増加 */
                    [{opacity: 0}, {opacity: 0.8}],
                    {duration: 1000, iterations: 1})],
    new ScrollTimeline({
      scrollSource: $scrollingContainer,
      orientation: 'block',
      timeRange: 1000,
      startScrollOffset: 0,
      endScrollOffset: $header.clientHeight}));
animation.play();

// このアニメーションはグループエフェクトを使用しているため、同じアニメーションインスタンスは異なるハンドルからアクセスできます: $avatarEl.getAnimations()[0], $headerEl.getAnimations()[0]

</script>
// AnimationWorkletGlobalScope内。
registerAnimator('twitter-header', class HeaderAnimator extends StatelessAnimator {
  constructor(options) {
    this.timing_ = new CubicBezier('ease-out');
  }

  animate(currentTime, effect) {
    const scroll = currentTime;  // scrollは[0, 1000]範囲

    // 子供のlocalTimeを個別に設定してグループエフェクトの出力を駆動
    effect.children[0].localTime = scroll;
    effect.children[1].localTime = this.timing_(clamp(scroll, 0, 500));
  }
});

function clamp(value, min, max) {
  return Math.min(Math.max(value, min), max);
}

8.2. 例2:パララックス背景

シンプルなパララックス背景の例です。
<style>
.parallax {
    position: fixed;
    top: 0;
    left: 0;
    opacity: 0.5;
}
</style>
<div id='scrollingContainer'>
  <div id="slow" class="parallax"></div>
  <div id="fast" class="parallax"></div>
</div>

<script>
await CSS.animationWorklet.addModule('parallax-animator.js');
const scrollTimeline = new ScrollTimeline({
  scrollSource: $scrollingContainer,
  orientation: 'block',
  timeRange: 1000
});
const scrollRange = $scrollingContainer.scrollHeight - $scrollingContainer.clientHeight;

const slowParallax = new WorkletAnimation(
    'parallax',
    new KeyframeEffect($parallax_slow, [{'transform': 'translateY(0)'}, {'transform': 'translateY(' + -scrollRange + 'px)'}], {duration: 1000}),
    scrollTimeline,
    {rate : 0.4}
);
slowParallax.play();

const fastParallax = new WorkletAnimation(
    'parallax',
    new KeyframeEffect($parallax_fast, [{'transform': 'translateY(0)'}, {'transform': 'translateY(' + -scrollRange + 'px)'}], {duration: 1000}),
    scrollTimeline,
    {rate : 0.8}
);
fastParallax.play();
</script>
// AnimationWorkletGlobalScope内。
registerAnimator('parallax', class ParallaxAnimator extends StatelessAnimator {
  constructor(options) {
    this.rate_ = options.rate;
  }

  animate(currentTime, effect) {
    effect.localTime = currentTime * this.rate_;
  }
});

適合性

文書の規則

適合性要件は、記述的な断言とRFC 2119の用語を組み合わせて表現されます。規範部分で使われる “MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、“MAY”、“OPTIONAL” というキーワードは、RFC 2119で定義されている通りに解釈されます。ただし、可読性のため、この仕様書ではこれらの単語はすべて大文字では書かれていません。

この仕様の本文は、明示的に非規範的と示されたセクション、例、注記を除き、すべて規範的です。[RFC2119]

この仕様書の例は「例えば」で始まるか、class="example"のように、規範テキストとは区別して示されます。

これは情報提供のための例です。

情報提供的な注記は “Note” で始まり、class="note" のように規範テキストから区別されます:

注:これは情報提供的な注記です。

勧告は特別な注意を喚起するために規範的セクションとして表示され、<strong class="advisement"> のように他の規範テキストと区別されます: UAは必ずアクセシブルな代替手段を提供しなければなりません。

適合クラス

この仕様への適合は、3つの適合クラスについて定義されます:

スタイルシート
CSSスタイルシート
レンダラー
UAであり、スタイルシートの意味を解釈し、それらを利用する文書をレンダリングします。
オーサリングツール
UAであり、スタイルシートを作成します。

スタイルシートが、この仕様書で定義される構文を使うすべての記述が、汎用CSS文法およびこのモジュールで定義される各機能の個別文法に従い有効であれば、そのスタイルシートは本仕様に適合しています。

レンダラーが本仕様に適合するには、適切な仕様で定義される通りにスタイルシートを解釈することに加え、本仕様で定義されたすべての機能を正しくパースし、文書を正しくレンダリングする必要があります。ただし、デバイスの制約によりUAが文書を正しくレンダリングできない場合でも、UAは非適合とはなりません(例:UAはモノクロモニターで色をレンダリングする必要はありません)。

オーサリングツールが本仕様に適合するには、汎用CSS文法およびこのモジュールで定義される各機能の個別文法に従い、構文的に正しいスタイルシートを書き、本モジュールで記述されるスタイルシートのその他の適合要件をすべて満たす必要があります。

部分的な実装

著者が将来互換性のあるパース規則を利用してフォールバック値を指定できるように、CSSレンダラーは必ず、利用可能なレベルのサポートがない@ルール、プロパティ、プロパティ値、キーワード、その他の構文要素を無効として扱い、適切に無視しなければなりません。特に、ユーザーエージェントは、単一の複数値プロパティ宣言でサポートされていないコンポーネント値だけを選択的に無視し、サポートされている値だけを適用してはなりません。いずれかの値が無効(未サポート値は必ず無効)と見なされた場合、CSSは宣言全体が無視されることを要求します。

不安定および独自機能の実装

将来の安定したCSS機能との衝突を避けるため、CSSWGはベストプラクティスに従って不安定な機能や独自拡張の実装を行うことを推奨します。

非実験的な実装

仕様書がCandidate Recommendation段階に到達すると、非実験的な実装が可能となり、実装者は仕様に従って正しく実装できるCRレベルの機能について、プレフィックスなしの実装をリリースするべきです。

CSSの実装間の相互運用性を確立・維持するため、CSSワーキンググループは非実験的なCSSレンダラーに対し、CSS機能のプレフィックスなし実装をリリースする前に、実装報告書(必要に応じてその実装報告書で使われたテストケースも)をW3Cに提出することを要請します。W3Cに提出されたテストケースはCSSワーキンググループによるレビュー・修正の対象となります。

テストケースや実装報告書の提出方法など詳細は、CSSワーキンググループのウェブサイトhttps://www.w3.org/Style/CSS/Test/をご覧ください。ご質問はpublic-css-testsuite@w3.orgメーリングリストへお寄せください。

索引

この仕様で定義されている用語

参照によって定義される用語

参考文献

規範参考文献

[CSS-TRANSITIONS-1]
David Baron; 他. CSS Transitions. 2018年10月11日. WD. URL: https://www.w3.org/TR/css-transitions-1/
[CSS-VALUES-4]
Tab Atkins Jr.; Elika Etemad. CSS Values and Units Module Level 4. 2019年1月31日. WD. URL: https://www.w3.org/TR/css-values-4/
[CSSOM-1]
Simon Pieters; Glenn Adams. CSS Object Model (CSSOM). 2016年3月17日. WD. URL: https://www.w3.org/TR/cssom-1/
[DOM]
Anne van Kesteren. DOM Standard. ライビングスタンダード. URL: https://dom.spec.whatwg.org/
[HTML]
Anne van Kesteren; 他. HTML Standard. ライビングスタンダード. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. ライビングスタンダード. URL: https://infra.spec.whatwg.org/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. 1997年3月. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119
[WEB-ANIMATIONS-1]
Brian Birtles; 他. Web Animations. 2018年10月11日. WD. URL: https://www.w3.org/TR/web-animations-1/
[WebIDL]
Boris Zbarsky. Web IDL. 2016年12月15日. ED. URL: https://heycam.github.io/webidl/
[WORKLETS-1]
Ian Kilpatrick. Worklets Level 1. 2016年6月7日. WD. URL: https://www.w3.org/TR/worklets-1/

参考情報

[EXPLAINER]
Animation Worklet Explainer. URL: https://github.com/w3c/css-houdini-drafts/blob/master/css-animationworklet/README.md
[PRINCIPLES]
Animation Worklet Design Principles and Goals. URL: https://github.com/w3c/css-houdini-drafts/blob/master/css-animationworklet/principles.md

IDL索引

[Exposed=Window]
partial namespace CSS {
    [SameObject] readonly attribute Worklet animationWorklet;
};

[Exposed=AnimationWorklet, Global=AnimationWorklet, Constructor (optional any options)]
interface StatelessAnimator {
};

[Exposed=AnimationWorklet, Global=AnimationWorklet,
Constructor (optional any options, optional any state)]
interface StatefulAnimator {
  any state();
};

[ Exposed=AnimationWorklet, Global=AnimationWorklet ]
interface AnimationWorkletGlobalScope : WorkletGlobalScope {
    void registerAnimator(DOMString name, AnimatorInstanceConstructor animatorCtor);
};

callback AnimatorInstanceConstructor = any (any options, optional any state);


[Exposed=Window,
 Constructor (DOMString animatorName,
              optional (AnimationEffect or sequence<AnimationEffect>)? effects = null,
              optional AnimationTimeline? timeline,
              optional any options)]
interface WorkletAnimation : Animation {
        readonly attribute DOMString animatorName;
};


[Exposed=AnimationWorklet]
interface WorkletGroupEffect {
  sequence<AnimationEffect> getChildren();
};

[Exposed=AnimationWorklet]
partial interface AnimationEffect {
    // Intended for use inside Animation Worklet scope to drive the effect.
    attribute double localTime;
};

課題索引

ユーザーエージェントが遅いアニメーターの処理をスキップしてスロットルする権限を与えることを検討してください。
animateFunctionが例外を投げた場合の挙動を明示するべきです。少なくとも、キー フレームのlocalTime値は無視されるため、誤った部分更新が発生しない旨の文言が必要です。
animator instanceがanimation currentTimeの変更(例えばreverse()、finish()、playbackRateの変更)を通知される適切な仕組みを考案すべきです。これにより適切に反応できるようになります。 <https://github.com/w3c/css-houdini-drafts/issues/811>
上記のインターフェイスはweb-animation-2のGroupEffectで提案されている保守的なサブセットのみを公開しています。代わりにこれをweb-animationに対する差分仕様として移行するべきです。 <https://github.com/w3c/csswg-drafts/issues/2071>