拡張エコシステム
レガシーアニメーション

AngularのAnimationsパッケージから移行する

v20.2以降、@angular/animationsパッケージは非推奨になり、同時にアプリケーションへアニメーションを追加するための新しいanimate.enterおよびanimate.leave機能が導入されました。これらの新機能を使うと、@angular/animationsベースのアニメーションをすべて、プレーンなCSSまたはJSアニメーションライブラリで置き換えられます。アプリケーションから@angular/animationsを削除すると、JavaScriptバンドルのサイズを大幅に削減できます。ネイティブCSSアニメーションは、ハードウェアアクセラレーションの恩恵を受けられるため、一般により優れたパフォーマンスを発揮します。このガイドでは、@angular/animationsからネイティブCSSアニメーションへコードをリファクタリングする手順を説明します。

ネイティブCSSでアニメーションを書く方法

ネイティブCSSでアニメーションを書いたことがない場合は、入門に役立つ優れたガイドがいくつもあります。以下にいくつか紹介します。
MDNのCSSアニメーションガイド
W3SchoolsのCSS3アニメーションガイド
CSSアニメーションの完全チュートリアル
初心者向けCSSアニメーション

また、次の動画も参考にしてください。
9分でCSSアニメーションを学ぶ
Net NinjaのCSSアニメーションチュートリアル再生リスト

まずは、これらのガイドやチュートリアルに目を通し、その後にこのガイドへ戻ってきてください。

再利用可能なアニメーションを作成する

アニメーションパッケージと同様に、アプリケーション全体で共有できる再利用可能なアニメーションを作成できます。アニメーションパッケージでは共有のTypeScriptファイルでanimation()関数を使っていましたが、ネイティブCSSでも考え方は似ており、共有のCSSファイルに定義します。

Animationsパッケージの場合

animations.ts

export const sharedAnimation = animation([
  style({
    height: 0,
    opacity: 1,
    backgroundColor: 'red',
  }),
  animate('1s'),
]);

ネイティブCSSの場合

animations.css

@keyframes sharedAnimation {
  to {
    height: 0;
    opacity: 1;
    background-color: 'red';
  }
}

.animated-class {
  animation: sharedAnimation 1s;
}

要素にanimated-classクラスを追加すると、その要素でアニメーションがトリガーされます。

トランジションをアニメーション化する

状態とスタイルをアニメーション化する

アニメーションパッケージでは、コンポーネント内でstate()関数を使ってさまざまな状態を定義できました。たとえば、定義の中にそれぞれの状態に対応するスタイルを含むopenやclosedといった状態です。例を示します。

Animationsパッケージの場合

open-close.ts

// ...
state(
  'open',
  style({
    height: '200px',
    opacity: 1,
    backgroundColor: 'yellow',
  }),
),

この動作は、キーフレームアニメーションまたはトランジションスタイルとCSSクラスを使うことで、ネイティブにも実現できます。

ネイティブCSSの場合

animations.css

.open {
  height: '200px';
  opacity: 1;
  background-color: 'yellow';
  transition: all 1s;
}

.closed {
  height: '100px';
  opacity: 0.8;
  background-color: 'blue';
  transition: all 1s;
}

openまたはclosed状態のトリガーは、コンポーネント内で要素のクラスを切り替えて行います。例は、テンプレートガイドで確認できます。

同様の例として、テンプレートガイドのスタイルを直接アニメーション化するも参照してください。

トランジション、タイミング、イージング

アニメーションパッケージのanimate()関数では、継続時間や遅延、イージングといったタイミングを指定できました。これはネイティブでも、複数のCSSプロパティまたはショートハンドプロパティを使って実現できます。

キーフレームアニメーションでは、animation-duration、animation-delay、animation-timing-functionを指定するか、代わりにanimationショートハンドプロパティを使用します。

animations.css

.example-element {
  animation-duration: 1s;
  animation-delay: 500ms;
  animation-timing-function: ease-in-out;
}

.example-shorthand {
  animation: exampleAnimation 1s ease-in-out 500ms;
}

同様に、@keyframesを使用しないアニメーションでは、transition-duration、transition-delay、transition-timing-function、およびtransitionショートハンドを使用できます。

animations.css

.example-element {
  transition-duration: 1s;
  transition-delay: 500ms;
  transition-timing-function: ease-in-out;
  transition-property: margin-right;
}

.example-shorthand {
  transition: margin-right 1s ease-in-out 500ms;
}

アニメーションをトリガーする

アニメーションパッケージでは、trigger()関数を使ってトリガーを指定し、その中にすべての状態をネストする必要がありました。ネイティブCSSでは、これは不要です。CSSのスタイルやクラスを切り替えるだけでアニメーションをトリガーできます。要素にクラスが存在するとアニメーションが実行され、クラスを削除すると、その要素に定義されているCSSへ戻ります。これにより、同じアニメーションをはるかに少ないコードで実現できます。例を示します。

Animationsパッケージの場合

ネイティブCSSの場合

トランジションとトリガー

事前定義された状態とワイルドカードマッチング

アニメーションパッケージでは、文字列を使って定義済みの状態をトランジションに対応付けられます。たとえば、openからclosedへのアニメーションはopen => closedとなります。ワイルドカードを使うと任意の状態から対象状態へのマッチングができ、* => closedのように書けます。また、voidキーワードはenterおよびexitの状態に使えます。たとえば、要素がビューを離れるときは* => void、要素がビューに入るときはvoid => *です。

CSSで直接アニメーション化する場合、こうした状態マッチングパターンはまったく不要です。要素に設定するクラスやスタイルに応じて、どのトランジションや@keyframesアニメーションを適用するかを管理できます。DOMに入った直後の要素の見た目を制御するために@starting-styleを追加できます。

ワイルドカードによる自動プロパティ計算

アニメーションパッケージでは、固定した高さからheight: autoへのアニメーションのように、従来は難しかったアニメーションを実現できました。これは現在では純粋なCSSでも可能です。

Animationsパッケージの場合

CSS Gridを使うと、height: autoへのアニメーションを実現できます。

ネイティブCSSの場合

すべてのブラウザをサポートする必要がない場合は、height: autoをアニメーション化するための本命の解決策であるcalc-size()も確認してください。詳しくは、MDNのドキュメントとこのチュートリアルを参照してください。

ビューへの出入りをアニメーション化する

アニメーションパッケージでは、前述のenterとleaveのパターンマッチングに加えて、:enterと:leaveというショートハンドエイリアスも提供していました。

Animationsパッケージの場合

ネイティブCSSの場合

ネイティブCSSの場合

animate.enterとanimate.leaveについて詳しくは、EnterとLeaveのアニメーションガイドを参照してください。

インクリメントとデクリメントをアニメーション化する

前述の:enterと:leaveに加えて、:incrementと:decrementもあります。これらもクラスを追加・削除することでアニメーションできます。アニメーションパッケージの組み込みエイリアスとは異なり、値が増減したときにクラスが自動で適用されるわけではありません。適切なクラスをプログラムから付与できます。例を示します。

Animationsパッケージの場合

ネイティブCSSの場合

親子アニメーション

アニメーションパッケージとは異なり、あるコンポーネント内に複数のアニメーションを指定しても、どのアニメーションも他より優先されず、どのアニメーションの発火もブロックされません。アニメーションの順序付けは、animationやtransitionの遅延を使ったCSSアニメーション定義、あるいは次にアニメーションさせるCSSを追加するためのanimationendまたはtransitionendによって処理する必要があります。

Child animations fire only within the same component template. In the @angular/animations package, parent animations could query and trigger animations in nested child components using query() and animateChild(). With animate.leave and native CSS animations, animations defined inside nested child component templates will not fire when a parent component removes an element or view. Only nested animations within the same Angular component template will execute. See the Enter and Leave Animations guide for more information on this.

アニメーションまたはすべてのアニメーションを無効にする

ネイティブCSSアニメーションでは、指定したアニメーションを無効にしたい場合、複数の選択肢があります。

  1. animationとtransitionをnoneに強制するカスタムクラスを作成します。
.no-animation {
  animation: none !important;
  transition: none !important;
}

このクラスを要素に適用すると、その要素ではどのアニメーションも発火しなくなります。代わりにDOM全体またはDOMの一部にスコープして、この挙動を強制できます。ただし、この方法ではアニメーションイベントが発火しなくなります。要素削除のためにアニメーションイベントを待っている場合、この方法は機能しません。回避策としては、継続時間を1ミリ秒に設定します。

  1. prefers-reduced-motionメディアクエリを使用して、アニメーションを控えたいユーザーにはアニメーションを再生しないようにします。

  2. プログラムからアニメーションクラスを追加しないようにします。

アニメーションのコールバック

アニメーションパッケージは、アニメーション終了時に何かをしたい場合に使用できるコールバックを公開していました。ネイティブCSSアニメーションにも同様のコールバックがあります。

OnAnimationStart
OnAnimationEnd
OnAnimationIteration
OnAnimationCancel

OnTransitionStart
OnTransitionRun
OnTransitionEnd
OnTransitionCancel

Web Animations APIには、他にも多くの機能があります。利用できるすべてのアニメーションAPIについては、ドキュメントを参照してください。

NOTE: これらのコールバックではバブリングの問題に注意してください。子要素と親要素の両方をアニメーション化している場合、イベントは子要素から親要素へバブルアップします。子ノードからバブルしてきたイベントではなく、意図したイベントターゲットに応答しているかを判断するために、伝播を停止するか、イベントの詳細を確認してください。適切なノードを対象にしているかは、animationnameプロパティやトランジション対象のプロパティを調べることで確認できます。

複雑なシーケンス

アニメーションパッケージには、複雑なシーケンスを作成するための組み込み機能がありました。これらのシーケンスはどれも、アニメーションパッケージなしで十分に実現できます。

特定の要素を対象にする

アニメーションパッケージでは、document.querySelector()に似たquery()関数を使って、CSSクラス名で特定の要素を見つけて対象にできました。ネイティブCSSアニメーションでは、これは不要です。代わりにCSSセレクターを使ってサブクラスを対象にし、必要なtransformやanimationを適用できます。

テンプレート内の子ノードのクラスを切り替えるには、クラスバインディングとスタイルバインディングを使って、適切なタイミングでアニメーションを追加できます。

stagger()

stagger()関数では、指定した時間だけリスト内の各項目のアニメーションを遅らせて、カスケード効果を作成できました。この挙動は、ネイティブCSSでもanimation-delayまたはtransition-delayを利用して再現できます。以下はそのCSSの例です。

Animationsパッケージの場合

ネイティブCSSの場合

並行アニメーション

アニメーションパッケージには、複数のアニメーションを同時に再生するgroup()関数がありました。CSSでは、アニメーションのタイミングを完全に制御できます。複数のアニメーションを定義している場合は、それらを一度にすべて適用できます。

.target-element {
  animation:
    rotate 3s,
    fade-in 2s;
}

この例では、rotateとfade-inのアニメーションが同時に発火します。

並び替えられるリストの項目をアニメーション化する

リスト項目の並び替えは、前述の手法を使うだけでそのまま機能します。特別な追加作業は必要ありません。@forループ内の項目は適切に削除されて再追加されるため、enterアニメーションとして@starting-stylesを使用したアニメーションが発火します。代わりに、同じ挙動をanimate.enterで実現できます。上の例のように、要素が削除されるときはanimate.leaveを使ってアニメーションします。

Animationsパッケージの場合

ネイティブCSSの場合

AnimationPlayerの使用箇所を移行する

AnimationPlayerクラスを使うと、コードからアニメーションを一時停止、再生、再開、完了するなど、より高度な操作をするためにアニメーションへアクセスできます。これらはすべてネイティブでも処理できます。

Element.getAnimations()を使うと、要素に関連付けられたアニメーションを直接取得できます。これは、その要素上のすべてのAnimationを配列として返します。Animation APIを使えば、アニメーションパッケージのAnimationPlayerが提供していたものよりも多くのことを行えます。ここからcancel()、play()、pause()、reverse()などを呼び出せます。このネイティブAPIだけで、アニメーションを制御するために必要な機能が揃うはずです。

ルートトランジション

ルート間をアニメーションさせるには、ビュー遷移を使用できます。始めるには、ルートトランジションアニメーションガイドを参照してください。