モーションとは、ユーザーを次のインタラクションに誘導する、デジタル エクスペリエンスの中核となる要素です。ただし、ウェブ プラットフォームではアニメーションがスムーズに再生されない部分がいくつかあります。これには、開始と終了のアニメーションを簡単にアニメーション化したり、ダイアログやポップオーバーなどの閉じられる要素のトップレイヤとの間でスムーズにアニメーション化したりできる機能が含まれます。
これらのギャップを埋めるために、Chrome 116 と 117 には、個別のプロパティの滑らかなアニメーションと遷移を可能にする 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. 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;
}
/* 1. BEFORE-OPEN STATE */
/* Starting point for the transition */
@starting-style {
.item {
opacity: 0;
height: 0;
}
}
/* 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 リスト項目の開始状態と終了状態の両方が設定されました。
最上位レイヤとの間で要素をアニメーション化する
要素をトップレイヤとの間でアニメーション化するには、[open] 状態に @starting-style
を指定して、アニメーションの開始位置をブラウザに伝えます。ダイアログの場合、開いている状態は [open]
属性で定義されます。ポップオーバーの場合は、:popover-open
疑似クラスを使用します。
ダイアログの簡単な例を次に示します。
/* 0. IS-OPEN STATE */
dialog[open] {
translate: 0 0;
}
/* 1. BEFORE-OPEN STATE */
@starting-style {
dialog[open] {
translate: 0 100vh;
}
}
/* 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. IS-OPEN STATE */
/* state when popover is open, BOTH:
what we're transitioning *in* to
and transitioning *out* from */
transform: translateY(0);
opacity: 1;
/* 1. 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;
}
}
/* 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 を変更する場合は、ビュー遷移もスムーズなアニメーションに適したソリューションです。ビュー遷移を使用して作成した上記の例を 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
を追加する必要があります。
まとめ
これらの新しいプラットフォーム機能により、ウェブ プラットフォームでのスムーズなエントリ アニメーションと終了アニメーションに一歩近づきました。詳しくは、以下のリンクをご覧ください。