モーションはあらゆるデジタル エクスペリエンスの中核であり、ユーザーを次のインタラクションへと導くものです。しかし、ウェブ プラットフォームでのスムーズなアニメーションには、いくつかのギャップがあります。たとえば、開始と終了のアニメーションを簡単にアニメーション化したり、ダイアログやポップオーバーなどの閉じることができる要素のために最上位レイヤとの間でスムーズにアニメーション化したりすることが可能です。
こうしたギャップを埋めるために、Chrome 116 と 117 には 4 つの新しいウェブ プラットフォーム機能が含まれており、個別のプロパティのスムーズなアニメーションと遷移を可能にします。
新機能は次の 4 つです。
- キーフレーム タイムラインで
display
とcontent-visibility
をアニメーション化できるようになりました(Chrome 116 以降)。 transition-behavior
プロパティとallow-discrete
キーワード。display
などの個別のプロパティの移行を有効にします(Chrome 117 以降)。display: none
から最上位のレイヤまで、エントリの効果をアニメーション化する@starting-style
ルール(Chrome 117 以降)。- アニメーション中の最上位レイヤの動作を制御する
overlay
プロパティ(Chrome 117 以降)。
キーフレームにアニメーションを表示する
Chrome 116 以降では、キーフレーム ルールで display
と content-visibility
を使用できます。これらはキーフレームが発生した時点で入れ替えられます。これをサポートするために追加の新しい値は必要ありません。
.card {
animation: fade-out 0.5s forwards;
}
@keyframes fade-out {
100% {
opacity: 0;
display: none;
}
}
上記の例では、持続時間 0.5 秒で不透明度が 0 にアニメーション化され、続いて display が none に設定されます。また、forwards
キーワードを使用すると、アニメーションが終了状態のままになるため、適用先の要素は display: none
と opacity: 0
のままになります。
これは、移行でできることを模倣した簡単な例です(移行セクションのデモをご覧ください)。ただし、遷移では、次の例のような複雑なアニメーションを作成することはできません。
.card {
animation: spin-and-delete 1s ease-in forwards;
}
@keyframes spin-and-delete {
0% {
transform: rotateY(0);
filter: hue-rotate(0);
}
80% {
transform: rotateY(360deg);
filter: hue-rotate(180deg);
opacity: 1;
}
100% {
opacity: 0;
display: none;
}
}
spin-and-delete
アニメーションは終了アニメーションです。まず、カードが y 軸で回転し、色相の回転を行います。その後、タイムラインの 80%
で、不透明度が 1 から 0 に移行します。最後に、カードが display: block
から display: none
に切り替わります。
これらの終了アニメーションについては、要素に直接適用するのではなく、アニメーションのトリガーを設定できます。たとえば、アニメーションを適用するクラスをトリガーするボタンにイベント リスナーをアタッチします。次に例を示します。
.spin-out {
animation: spin-and-delete 1s ease-in forwards;
}
document.querySelector('.delete-btn').addEventListener('click', () => {
document.querySelector('.card').classList.add('spin-out');
})
上記の例の終了状態が display:none
になりました。さらに、アニメーションが先に終了するようにタイムアウト付きの DOM ノードを削除したいケースも多数あります。
個別のアニメーションの遷移
キーフレームで個別のプロパティをアニメーション化する場合とは異なり、個別のプロパティを遷移するには、allow-discrete
遷移動作モードを使用する必要があります。
transition-behavior
プロパティ
allow-discrete
モードは個別の遷移を可能にするもので、transition-behavior
プロパティの値となります。transition-behavior
には、normal
と allow-discrete
の 2 つの値を指定できます。
.card {
transition: opacity 0.25s, display 0.25s;
transition-behavior: allow-discrete; /* Note: be sure to write this after the shorthand */
}
.card.fade-out {
opacity: 0;
display: none;
}
transition
省略形もこの値を設定するため、プロパティを省略して、代わりに各遷移の transition
省略形の最後に allow-discrete
キーワードを使用できます。
.card {
transition: opacity 0.5s, display 0.5s allow-discrete;
}
.card.fade-out {
opacity: 0;
display: none;
}
複数の個別のプロパティをアニメーション化する場合は、アニメーション化する各プロパティの後に allow-discrete
を含める必要があります。例:
.card {
transition: opacity 0.5s, display 0.5s allow-discrete, overlay 0.5s allow-discrete;
}
.card.fade-out {
opacity: 0;
display: none;
}
エントリ アニメーションの @starting-style
ルール
ここまで、終了アニメーションについて説明しました。開始アニメーションを作成するには、@starting-style
ルールを使用する必要があります。
@starting-style
を使用すると、ページ上で要素が開く前にブラウザが検索できるスタイルを適用できます。これは「オープン前」の状態です(アニメーションの起点)。
/* 0. BEFORE-OPEN STATE */
/* Starting point for the transition */
@starting-style {
.item {
opacity: 0;
height: 0;
}
}
/* 1. IS-OPEN STATE */
/* The state at which the element is open + transition logic */
.item {
height: 3rem;
display: grid;
overflow: hidden;
transition: opacity 0.5s, transform 0.5s, height 0.5s, display 0.5s allow-discrete;
}
/* 2. EXITING STATE */
/* While it is deleting, before DOM removal in JS, apply this
transformation for height, opacity, and a transform which
skews the element and moves it to the left before setting
it to display: none */
.is-deleting {
opacity: 0;
height: 0;
display: none;
transform: skewX(50deg) translateX(-25vw);
}
これで、これらの TODO リストアイテムの開始状態と終了状態が得られました。
最上位レイヤとの間で要素をアニメーション化する
最上位レイヤとの間で要素をアニメーション化するには、@starting-style
を「オープン」状態で指定し、ブラウザに対してどこからアニメーション化するかを指示します。ダイアログでは、開いた状態は [open]
属性で定義されます。ポップオーバーには、:popover-open
疑似クラスを使用します。
簡単なダイアログの例を次に示します。
/* 0. BEFORE-OPEN STATE */
@starting-style {
dialog[open] {
translate: 0 100vh;
}
}
/* 1. IS-OPEN STATE */
dialog[open] {
translate: 0 0;
}
/* 2. EXIT STATE */
dialog {
transition: translate 0.7s ease-out, overlay 0.7s ease-out allow-discrete, display 0.7s ease-out allow-discrete;
translate: 0 100vh;
}
次の例では、開始効果と終了効果が異なります。ビューポートの下部から上にアニメーション化して開始し、ビューポートの上部で効果を終了します。また、視覚的なカプセル化のために、ネストされた CSS を使用して記述しています。
ポップオーバーをアニメーション化する場合は、以前に使用した open
属性の代わりに :popover-open
疑似クラスを使用します。
.settings-popover {
&:popover-open {
/* 0. BEFORE-OPEN STATE */
/* Initial state for what we're animating *in* from,
in this case: goes from lower (y + 20px) to center */
@starting-style {
transform: translateY(20px);
opacity: 0;
}
/* 1. IS-OPEN STATE */
/* state when popover is open, BOTH:
what we're transitioning *in* to
and transitioning *out* from */
transform: translateY(0);
opacity: 1;
}
/* 2. EXIT STATE */
/* Initial state for what we're animating *out* to ,
in this case: goes from center to (y - 50px) higher */
transform: translateY(-50px);
opacity: 0;
/* Enumerate transitioning properties,
including display and allow-discrete mode */
transition: transform 0.5s, opacity 0.5s, display 0.5s allow-discrete;
}
overlay
件の宿泊施設
最後に、最上位レイヤから popover
または dialog
をフェードアウトするには、遷移のリストに overlay
プロパティを追加します。popover
と dialog
は、祖先のクリップと変換をエスケープし、コンテンツを最上位レイヤに配置します。overlay
をトランジションしない場合、要素はすぐにクリップされて変形され、覆われた状態に戻ります。この場合、トランジションは行われません。
[open] {
transition: opacity 1s, display 1s allow-discrete;
}
代わりに、遷移またはアニメーションに overlay
を含めて、overlay
を他の機能とともにアニメーション化し、アニメーション化時に最上位レイヤに残るようにします。これでかなりスムーズになります。
[open] {
transition: opacity 1s, display 1s allow-discrete, overlay 1s allow-discrete;
}
また、最上位のレイヤで複数の要素を開いている場合、オーバーレイを使用すると、最上層のレイヤを出入りする際のスムーズな遷移をコントロールできます。違いについては、こちらの簡単な例をご覧ください。2 番目のポップオーバーを遷移させるときに overlay
を適用しない場合、そのポップオーバーはまず一番上のレイヤから出て、他のポップオーバーの後ろにジャンプしてから、遷移を開始します。これはあまりスムーズな効果ではありません。
ビュー遷移に関する注意事項
DOM の要素を追加または削除するなど、DOM を変更する場合は、スムーズなアニメーションを実現するためのもう 1 つのソリューションとしてビュー遷移があります。ビュー遷移を使用して作成された上記の例を 2 つ紹介します。
この最初のデモでは、@starting-style
などの CSS 変換を設定するのではなく、ビュー遷移によって処理します。ビュー遷移は次のように設定します。
まず、CSS で、各カードに個別の view-transition-name
を設定します。
.card-1 {
view-transition-name: card-1;
}
.card-2 {
view-transition-name: card-2;
}
/* etc. */
次に、JavaScript で DOM ミューテーション(この場合はカードの削除)をビュー遷移でラップします。
deleteBtn.addEventListener('click', () => {
// Check for browser support
if (document.startViewTransition) {
document.startViewTransition(() => {
// DOM mutation
card.remove();
});
}
// Alternative if no browser support
else {
card.remove();
}
})
これで、ブラウザで各カードのフェードアウトと新しい位置へのモーフを処理できるようになりました。
この機能が役立つもう一つの例として、リストアイテムの追加と削除のデモがあります。この場合は、作成したカードごとに一意の view-transition-name
を追加する必要があります。
まとめ
これらの新しいプラットフォーム機能により、ウェブ プラットフォーム上でのスムーズな開始と終了のアニメーションに一歩近づきました。詳しくは、以下のリンクをご覧ください。