これを想像してください。新しいプロジェクトに参加し、コードベースに飛び込み、最初の数時間以内に、イライラするほど見覚えのあるものを発見します。スタイルシート全体に散在して、同じ基本アニメーションに対する複数の @keyframes 定義が見つかります。 3 つの異なるフェードイン効果、2 つまたは 3 つのスライド バリエーション、いくつかのズーム アニメーション、および少なくとも 2 つの異なるスピン アニメーション。 @keyframes パルス { {から スケール: 1; } {に スケール: 1.1; } }
@keyframes より大きなパルス { 0%、20%、100% { スケール: 1; } 10%、40% { スケール: 1.2; } }
このシナリオに見覚えがあると思われる場合も、あなたは一人ではありません。さまざまなプロジェクトにわたる私の経験の中で、私が達成できる最も一貫した迅速な成果の 1 つは、キーフレームの統合と標準化です。これは非常に信頼できるパターンになっているので、新しいコードベースでの最初のタスクの 1 つとしてこのクリーンアップを楽しみにしています。 混沌の背後にある論理 この冗長性は、よく考えると完全に理にかなっています。私たちは皆、フェード、スライド、ズーム、スピン、その他の一般的なエフェクトなど、日常の仕事で同じ基本的なアニメーションを使用しています。これらのアニメーションは非常に簡単で、仕事を完了するために簡単な @keyframes 定義を作成するのは簡単です。 集中化されたアニメーション システムがなければ、開発者は自然にこれらのキーフレームを最初から作成することになり、同様のアニメーションがコードベースの他の場所にすでに存在していることに気付かないことになります。これは、チームがアプリケーションのさまざまな部分で並行して作業することが多いため、コンポーネントベースのアーキテクチャで作業する場合 (最近ではほとんどがそうしています) に特に一般的です。 結果?アニメーションのカオス。 小さな問題 キーフレームの重複に関する最も明らかな問題は、開発時間の無駄とコードの不要な肥大化です。複数のキーフレーム定義は、要件が変更されたときに複数の場所を更新することを意味します。フェード アニメーションのタイミングを調整する必要がありますか?コードベース全体のすべてのインスタンスを探し出す必要があります。イージング関数を標準化したいですか?すべてのバリエーションを見つけて頑張ってください。このメンテナンス ポイントの増加により、単純なアニメーションの更新でも時間のかかる作業になります。 より大きな問題 このキーフレームの重複により、表面下に潜むはるかに潜伏性の問題、つまりグローバル スコープの罠が発生します。コンポーネントベースのアーキテクチャを使用する場合でも、CSS キーフレームは常にグローバル スコープで定義されます。これは、すべてのキーフレームがすべてのコンポーネントに適用されることを意味します。いつも。はい、アニメーションでは、コンポーネントで定義したキーフレームが必ずしも使用されるわけではありません。グローバル スコープにロードされたものとまったく同じ名前に一致する最後のキーフレームが使用されます。 すべてのキーフレームが同一である限り、これは小さな問題のように見えるかもしれません。しかし、特定のユースケースに合わせてアニメーションをカスタマイズしたいと思った瞬間、あなたは問題に直面することになるか、さらに悪いことに、あなたが問題の原因となることになります。 別のコンポーネントが後でロードされてキーフレームを上書きするためにアニメーションが機能しなくなるか、コンポーネントが最後にロードされて、そのキーフレームの名前を使用している他のすべてのコンポーネントのアニメーション動作が誤って変更されてしまい、それに気付かない可能性があります。 この問題を示す簡単な例を次に示します。 .component-1 { /* コンポーネントのスタイル */ アニメーション: パルス 1 秒イーズインアウト無限代替。 }
/* この @keyframes 定義は機能しません */ @keyframes パルス { {から スケール: 1; } {に スケール: 1.1; } }
/* コードの後半... */
.component-2 { /* コンポーネントのスタイル */ アニメーション: パルス 1 秒、イーズインアウト無限。 }
/* このキーフレームは両方のコンポーネントに適用されます */ @keyframes パルス { 0%、20%、100% { スケール: 1; } 10%、40% { スケール: 1.2; } }
どちらのコンポーネントも同じアニメーション名を使用しますが、2 番目の @keyframes 定義は最初の @keyframes 定義を上書きします。これで、どのコンポーネントがどのキーフレームを定義したかに関係なく、コンポーネント 1 とコンポーネント 2 の両方が 2 番目のキーフレームを使用するようになります。 Amit Sheen による「ペン キーフレーム トークン - デモ 1 [フォーク]」を参照してください。 最悪の部分は?これは多くの場合、ローカル開発では完全に機能しますが、実稼働環境では、ビルド プロセスでスタイルシートの読み込み順序が変更されると、不思議なことに機能しません。どのコンポーネントがどの順序でロードされるかに応じて、アニメーションの動作が異なります。 解決策: 統合キーフレーム この混乱に対する答えは驚くほど簡単です。事前定義された動的キーフレームを共有スタイルシートに保存することです。すべてのコンポーネントに独自のアニメーションを定義させる代わりに、十分に文書化され、簡単に操作できる集中化されたキーフレームを作成します。使用性、保守性が高く、プロジェクトの特定のニーズに合わせて調整できます。 これをキーフレーム トークンと考えてください。私たちが色や間隔にトークンを使用し、多くの人がすでに持続時間やイージング関数などのアニメーション プロパティにトークンを使用しているのと同じように、キーフレームにもトークンを使用しないのはなぜでしょうか。 このアプローチは、現在使用している任意の設計トークン ワークフローと自然に統合でき、小さな問題 (コードの重複) と大きな問題 (グローバル スコープの競合) の両方を一度に解決できます。 アイデアは単純です。すべての一般的なアニメーションについて、信頼できる単一の情報源を作成します。この共有スタイルシートには、プロジェクトが実際に使用するアニメーション パターンをカバーする、慎重に作成されたキーフレームが含まれています。フェード アニメーションがコードベースのどこかに既に存在するかどうかを推測する必要はもうありません。他のコンポーネントのアニメーションを誤って上書きすることはもうありません。 しかし重要なのは、これらは単なる静的なコピー&ペーストのアニメーションではないということです。これらは CSS カスタム プロパティを通じて動的かつカスタマイズできるように設計されているため、一貫性を維持しながら、1 か所で少し大きな「パルス」アニメーションが必要な場合など、アニメーションを特定のユースケースに適応させる柔軟性を維持できます。 最初のキーフレーム トークンの構築 最初に取り組むべき簡単な成果の 1 つは、「フェードイン」アニメーションです。最近のプロジェクトの 1 つで、10 を超える個別のフェードイン定義を見つけました。はい、それらはすべて、単純に不透明度を 0 から 1 にアニメーション化するものでした。 そこで、新しいスタイルシートを作成して kf-tokens.css という名前を付け、プロジェクトにインポートし、その中に適切なコメントを付けてキーフレームを配置しましょう。 /* キーフレーム-トークン.css */
/* * フェードイン - フェード入場アニメーション * 使用法: アニメーション: kf フェードイン 0.3 秒イーズアウト。 */ @keyframes kf-フェードイン { {から 不透明度: 0; } {に 不透明度: 1; } }
この単一の @keyframes 宣言は、コードベース全体に散在するすべてのフェードイン アニメーションを置き換えます。すっきりしていてシンプルで、世界中に適用可能です。このトークンを定義したので、プロジェクト全体の任意のコンポーネントからこのトークンを使用できます。 .modal { アニメーション: kf フェードイン 0.3 秒イーズアウト。 }
.tooltip { アニメーション: kf フェードイン 0.2 秒イーズイン アウト。 }
.notification { アニメーション: kf フェードイン 0.5 秒イーズアウト。 }
Amit Sheen による「ペン キーフレーム トークン - デモ 2 [フォーク]」を参照してください。 注: すべての @keyframes 名で kf- 接頭辞を使用しています。このプレフィックスは、プロジェクト内の既存のアニメーションとの名前の競合を防止する名前空間として機能し、これらのキーフレームがキーフレーム トークン ファイルからのものであることをすぐに明らかにします。 動的なスライドを作成する kf フェードイン キーフレームは、シンプルで混乱する余地がほとんどないため、非常にうまく機能します。ただし、他のアニメーションでは、より動的にする必要があり、ここでは CSS カスタム プロパティの大きな力を活用できます。これは、点在する静的アニメーションと比較して、キーフレーム トークンが真価を発揮する場所です。 「スライドイン」アニメーションという一般的なシナリオを考えてみましょう。しかし、どこから滑り込むのでしょうか?右から100pxくらいでしょうか?左から50%くらいかな?画面の上から入力すればいいのでしょうか?それとも底から浮かんでくるのでしょうか?非常に多くの可能性がありますが、方向やバリエーションごとに個別のキーフレームを作成する代わりに、すべてのシナリオに適応する 1 つの柔軟なトークンを構築できます。 /* * スライドイン - 方向性のあるスライドアニメーション * 方向を制御するには --kf-slide-from を使用します * デフォルト: 左からスライドイン (-100%) * 使用方法: * アニメーション: kf スライドイン 0.3 秒イーズアウト; * --kf-slide-from: -100px 0; // 左からスライド * --kf-slide-from: 100px 0; // 右からスライド * --kf-slide-from: 0 -50px; // 上からスライド */
@keyframes kf-slide-in { {から 翻訳: var(--kf-slide-from, -100% 0); } {に 翻訳: 0 0; } }
--kf-slide-from カスタム プロパティを変更するだけで、この単一の @keyframes トークンを任意のスライド方向に使用できるようになりました。 .サイドバー { アニメーション: kf スライドイン 0.3 秒イーズアウト。 /* デフォルト値を使用します: 左からスライドします */ }
.notification { アニメーション: kf スライドイン 0.4 秒イーズアウト。 --kf-slide-from: 0 -50px; /* 上からスライド */ }
.modal { アニメーション: kfフェードイン0.5秒、 kf-slide-in 0.5s cubic-bezier(0.34, 1.56, 0.64, 1); --kf-slide-from: 50 ピクセル 50 ピクセル; /* 右下からスライド */ }
このアプローチにより、一貫性を維持しながら驚くべき柔軟性が得られます。 1 つのキーフレーム宣言で無限の可能性。 Amit Sheen による「ペン キーフレーム トークン - デモ 3 [フォーク]」を参照してください。 また、アニメーションをさらに柔軟にして、「スライドアウト」効果も可能にしたい場合は、次のようにすることができます。次のセクションで説明するものと同様に、--kf-slide-to カスタム プロパティを追加するだけです。 双方向ズームキーフレーム プロジェクト間で複製されるもう 1 つの一般的なアニメーションは、「ズーム」効果です。トースト メッセージの微妙な拡大、モーダルの劇的なズームイン、または見出しの穏やかな縮小効果など、ズーム アニメーションはあらゆる場所にあります。 スケール値ごとに個別のキーフレームを作成する代わりに、柔軟な kf-zoom キーフレームのセットを 1 つ構築しましょう。
/* * ズーム - スケールアニメーション * スケール値を制御するには --kf-zoom-from および --kf-zoom-to を使用します * デフォルト: 80% から 100% (0.8 から 1) にズームします。 * 使用方法: * アニメーション: kf-zoom 0.2 秒イーズアウト; * --kf-zoom-from: 0.5; --kf-ズーム: 1; // 50% から 100% にズームします * --kf-zoom-from: 1; --kf ズーム: 0; // 100% から 0% にズームします * --kf-zoom-from: 1; --kf-zoom-to: 1.1; // 100% から 110% にズームします */
@keyframes kf-zoom { {から スケール: var(--kf-zoom-from, 0.8); } {に スケール: var(--kf-zoom-to, 1); } }
1 つの定義で、必要なズームのバリエーションを実現できます。 .toast { アニメーション: kf-スライドイン0.2秒、 kf-zoom 0.4秒イーズアウト。 --kf-slide-from: 0 100%; /* 上からスライド */ /* デフォルトのズームを使用します: 80% から 100% にスケールします */ }
.modal { アニメーション: kf-zoom 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); --kf-ズームから: 0; /* 0% から 100% までの劇的なズーム */ }
.見出し { アニメーション: kf-フェードイン 2、 kf-zoom 2s イーズイン。 --kf-zoom-from: 1.2; --kf ズーム: 0.8; /* 緩やかにスケールダウン */ }
デフォルトの 0.8 (80%) は、トースト メッセージやカードなど、ほとんどの UI 要素に完璧に機能しますが、特殊な場合に合わせてカスタマイズするのも簡単です。 Amit Sheen による「ペン キーフレーム トークン - デモ 4 [フォーク]」を参照してください。 最近の例で興味深いことに気づいたかもしれません。アニメーションを組み合わせています。 @keyframes トークンを使用する主な利点の 1 つは、トークンが相互にシームレスに統合されるように設計されていることです。この滑らかな構図は偶然ではなく意図的なものです。 アニメーションの構成については、問題が発生する可能性がある部分も含めて後ほど詳しく説明しますが、ほとんどの組み合わせは単純で簡単に実装できます。 注: この記事を書いている間、そしておそらくそれを書いたおかげで、私は入場アニメーションのアイデア全体を再考していることに気づきました。最近の CSS の進歩にもかかわらず、CSS はまだ必要なのでしょうか?幸運なことに、アダム アーガイルも同じ疑問を調査し、ブログで見事に表現しました。これはここに書かれていることと矛盾するわけではありませんが、特にプロジェクトが入口アニメーションに大きく依存している場合には、検討する価値のあるアプローチを示しています。 連続アニメーション 「フェード」、「スライド」、「ズーム」などの入口アニメーションは 1 回発生して停止しますが、連続アニメーションは無期限にループして注意を引いたり、進行中のアクティビティを示したりします。私が遭遇する最も一般的な連続アニメーションの 2 つは、「スピン」 (インジケーターの読み込み用) と「パルス」 (重要な要素のハイライト用) です。 これらのアニメーションでは、キーフレーム トークンの作成に関して独特の課題が生じます。通常、ある状態から別の状態に移行する開始アニメーションとは異なり、連続アニメーションは動作パターンを高度にカスタマイズできる必要があります。 スピンドクター どのプロジェクトも複数のスピン アニメーションを使用しているようです。時計回りに回転するものもあれば、反時計回りに回転するものもあります。 1 回の 360 度回転を行うものもあれば、より迅速な効果を得るために複数回回転するものもあります。バリエーションごとに個別のキーフレームを作成する代わりに、すべてのシナリオを処理する 1 つの柔軟なスピンを構築しましょう。
/* * スピン - 回転アニメーション * --kf-spin-from と --kf-spin-to を使用して回転範囲を制御します * 回転量を制御するには --kf-spin-turns を使用します * デフォルト: 0 度から 360 度まで回転します (1 回転) * 使用方法: * アニメーション: kf-spin 1s 線形無限; * --kf-スピンターン: 2; // 2 回転 * --kf-spin-from: 0 度; --kf スピン先: 180 度; // 半回転 * --kf-spin-from: 0 度; --kf-スピン先: -360 度; // 反時計回り */
@keyframes kf-spin { {から 回転: var(--kf-spin-from, 0deg); } {に 回転: calc(var(--kf-spin-from, 0deg) + var(--kf-spin-to, 360deg) * var(--kf-spin-turns, 1)); } }
これで、好みのスピンのバリエーションを作成できるようになりました。
.loading-スピナー { アニメーション: kf-spin 1s リニア無限。 /* デフォルトを使用します: 0 度から 360 度まで回転します */ }
.fast-loader { アニメーション: kf-spin 1.2s イーズインアウト無限代替。 --kf-スピンターン: 3; /* 1 サイクルあたり各方向に 3 回転*/ }
.ステップリバース { アニメーション: kf-spin 1.5 秒ステップ (8) 無限。 --kf-スピン先: -360 度; /* 反時計回り */ }
.微妙な動き { アニメーション: kf-spin 2s イーズインアウト無限代替。 --kf-spin-from: -16 度; --kf スピン先: 32 度; /* 36 度小刻みに動かす: -18 度から +18 度の間 */ }
Amit Sheen による「ペン キーフレーム トークン - デモ 5 [フォーク]」を参照してください。 このアプローチの利点は、同じキーフレームがスピナーのロード、アイコンの回転、ウィグル エフェクト、さらには複雑なマルチターン アニメーションにも機能することです。 パルスパラドックス パルス アニメーションは、さまざまなプロパティを「パルス」する可能性があるため、より複雑です。スケールをパルスするもの、不透明度をパルスするもの、明るさや彩度などの色のプロパティをパルスするものもあります。プロパティごとに個別のキーフレームを作成するのではなく、任意の CSS プロパティで機能するキーフレームを作成できます。 以下は、スケールと不透明度のオプションを備えたパルス キーフレームの例です。
/* * パルス - パルスアニメーション * --kf-pulse-scale-from および --kf-pulse-scale-to を使用してスケール範囲を制御します * 不透明度の範囲を制御するには --kf-pulse-opacity-from と --kf-pulse-opacity-to を使用します * デフォルト: パルスなし (すべての値が 1) * 使用方法: * アニメーション: kf-pulse 2s イーズインアウト無限代替。 * --kf-pulse-scale-from: 0.95; --kf-pulse-scale-to: 1.05; // スケールパルス * --kf-pulse-opacity-from: 0.7; --kf-pulse-opacity-to: 1; // 不透明度パルス */
@keyframes kf-pulse { {から スケール: var(--kf-pulse-scale-from, 1); 不透明度: var(--kf-pulse-opacity-from, 1); } {に スケール: var(--kf-pulse-scale-to, 1); 不透明度: var(--kf-pulse-opacity-to, 1); } }
これにより、複数のプロパティをアニメーション化できる柔軟なパルスが作成されます。 .call-to-action { アニメーション: kf-pulse 0.6s 無限代替。 --kf-pulse-opacity-from: 0.5; /* 不透明パルス */ }
.notification-dot { アニメーション: kf-pulse 0.6 秒イーズインアウト無限代替。 --kf-pulse-scale-from: 0.9; --kf-pulse-scale-to: 1.1; /* スケールパルス */ }
.text-ハイライト { アニメーション: kf-pulse 1.5 秒イーズアウト無限。 --kf-pulse-scale-from: 0.8; --kf-pulse-opacity-from: 0.2; /* スケールと不透明度パルス */ }
Amit Sheen による「ペン キーフレーム トークン - デモ 6 [フォーク]」を参照してください。 この 1 つの kf-pulse キーフレームは、微妙な注目の獲得から劇的なハイライトまで、すべてを簡単にカスタマイズできます。 高度なイージング キーフレーム トークンを使用することの優れた点の 1 つは、アニメーション ライブラリを拡張し、ほとんどの開発者がわざわざ最初から作成する必要のない、エラスティックやバウンスなどの効果を簡単に提供できることです。 以下は、 --kf-bounce-from カスタム プロパティを使用してジャンプの高さを制御する単純な「バウンス」キーフレーム トークンの例です。 /* * バウンス - 跳ねる入場アニメーション * --kf-bounce-from を使用してジャンプの高さを制御します * デフォルト: 100vh からジャンプ (画面外) * 使用方法: * アニメーション: kf-bounce 3s イーズイン; * --kf-bounce-from: 200px; // 高さ 200px からジャンプ */
@keyframes kf-bounce { 0% { 変換: 0 calc(var(--kf-bounce-from, 100vh) * -1); }
34% { 変換: 0 calc(var(--kf-bounce-from, 100vh) * -0.4); }
55% { 変換: 0 calc(var(--kf-bounce-from, 100vh) * -0.2); }
72% { 変換: 0 calc(var(--kf-bounce-from, 100vh) * -0.1); }
85% { 変換: 0 calc(var(--kf-bounce-from, 100vh) * -0.05); }
94% { 変換: 0 calc(var(--kf-bounce-from, 100vh) * -0.025); }
99% { 変換: 0 calc(var(--kf-bounce-from, 100vh) * -0.0125); }
22%、45%、64%、79%、90%、97%、100% { 翻訳: 0 0; アニメーション タイミング関数: イーズアウト; } }
「エラスティック」のようなアニメーションは、キーフレーム内で計算が行われるため、少し難しくなります。 --kf-elastic-from-X と --kf-elastic-from-Y を個別に定義する必要があります (両方ともオプション)。これらを一緒に使用すると、画面上の任意の点から柔軟な入り口を作成できます。
/* * Elastic In - 伸縮性のある入口アニメーション * --kf-elastic-from-X および --kf-elastic-from-Y を使用して開始位置を制御します ※デフォルト:中央上から入力(0、-100vh) * 使用方法: * アニメーション: kf-elastic-in 2s easy-in-out 両方; * --kf-elastic-from-X: -50px; * --kf-elastic-from-Y: -200px; // (-50px, -200px) から入力します */
@keyframes kf-elastic-in { 0% { 翻訳: calc(var(--kf-elastic-from-X, -50vw) * 1) calc(var(--kf-elastic-from-Y, 0px) * 1); }
16% { 変換: calc(var(--kf-elastic-from-X, -50vw) * -0.3227) calc(var(--kf-elastic-from-Y, 0px) * -0.3227); }
28% { 変換: calc(var(--kf-elastic-from-X, -50vw) * 0.1312)calc(var(--kf-elastic-from-Y, 0px) * 0.1312); }
44% { 変換: calc(var(--kf-elastic-from-X, -50vw) * -0.0463) calc(var(--kf-elastic-from-Y, 0px) * -0.0463); }
59% { 変換: calc(var(--kf-elastic-from-X, -50vw) * 0.0164) calc(var(--kf-elastic-from-Y, 0px) * 0.0164); }
73% { 変換: calc(var(--kf-elastic-from-X, -50vw) * -0.0058) calc(var(--kf-elastic-from-Y, 0px) * -0.0058); }
88% { 変換: calc(var(--kf-elastic-from-X, -50vw) * 0.0020) calc(var(--kf-elastic-from-Y, 0px) * 0.0020); }
100% { 翻訳: 0 0; } }
このアプローチにより、単一のカスタム プロパティを変更するだけで、プロジェクト全体で高度なキーフレームを簡単に再利用およびカスタマイズできるようになります。
.バウンスアンドズーム { アニメーション: kf-bounce 3s イーズイン、 kf-zoom 3s リニア。 --kf-ズームから: 0; }
.バウンスアンドスライド { アニメーション構成: 追加; /* どちらのアニメーションも翻訳を使用します */ アニメーション: kf-bounce 3s イーズイン、 KF スライドイン 3S イーズアウト。 --kf-slide-from: -200px; }
.elastic-in { アニメーション: kf-elastic-in 2s easy-in-out 両方。 }
Amit Sheen による「ペン キーフレーム トークン - デモ 7 [フォーク]」を参照してください。 ここまで、スマートかつ効率的な方法でキーフレームを統合する方法を見てきました。もちろん、プロジェクトのニーズに合わせて調整することもできますが、ここではいくつかの一般的なアニメーションと日常的なユースケースの例を取り上げました。これらのキーフレーム トークンを配置すると、プロジェクト全体で一貫性があり、保守可能なアニメーションを作成するための強力な構成要素が得られます。キーフレームが重複したり、グローバル スコープの競合が発生したりすることはもうありません。すべてのアニメーションのニーズを処理するためのクリーンで便利な方法です。 しかし、本当の問題は、これらの構成要素をどのように組み合わせて構成するかということです。 すべてをまとめる 基本的なキーフレーム トークンを組み合わせるのは簡単であることがわかりました。特別なことは何も必要ありませんが、最初のアニメーションを定義し、2 番目のアニメーションを定義し、必要に応じて変数を設定するだけです。 /* フェードイン + スライドイン */ .toast { アニメーション: kfフェードイン0.4秒、 kf-slide-in 0.4s cubic-bezier(0.34, 1.56, 0.64, 1); --kf-slide-from: 0 40px; }
/* ズームイン + フェードイン */ .modal { アニメーション: kfフェードイン0.3秒、 kf-zoom 0.3s 立方ベジェ(0.34, 1.56, 0.64, 1); --kf-zoom-from: 0.7; --kf-ズーム: 1; }
/* スライドイン + パルス */ .notification { アニメーション: kf-スライドイン0.5秒、 kf-pulse 1.2s イーズインアウト無限代替。 --kf-slide-from: -100px 0; --kf-pulse-scale-from: 0.95; --kf-pulse-scale-to: 1.05; }
各アニメーションは不透明度、変換 (移動/スケール) などの異なるプロパティを対象としているため、これらの組み合わせは美しく機能します。しかし、競合が発生する場合があり、その理由と対処方法を知る必要があります。 2 つのアニメーションが同じプロパティ (たとえば、両方のスケールをアニメーション化する、または両方とも不透明度をアニメーション化するなど) をアニメーション化しようとすると、結果は期待したものになりません。デフォルトでは、実際にそのプロパティに適用されるアニメーションは 1 つだけで、アニメーション リストの最後のものです。これは、CSS が同じプロパティで複数のアニメーションを処理する方法の制限です。 たとえば、kf-pulse アニメーションのみが適用されるため、これは意図したように機能しません。 .bad-combo { アニメーション: kf-zoom 0.5 秒前方、 kf-pulse 1.2s 無限代替。 --kf-zoom-from: 0.5; --kf-zoom-to: 1.2; --kf-pulse-scale-from: 0.8; --kf-pulse-scale-to: 1.1; }
アニメーションの追加 同じプロパティに影響を与える複数のアニメーションを処理する最も簡単かつ直接的な方法は、animation-composition プロパティを使用することです。上記の最後の例では、kf-pulse アニメーションが kf-zoom アニメーションを置き換えるため、初期ズームは表示されず、予想される 1.2 のスケールも得られません。 追加するアニメーション構成を設定することで、両方のアニメーションを組み合わせるようにブラウザーに指示します。これにより、希望する結果が得られます。 .component-2 { アニメーション構成: 追加; }
Amit Sheen による「ペン キーフレーム トークン - デモ 8 [フォーク]」を参照してください。 このアプローチは、同じプロパティのエフェクトを組み合わせたいほとんどの場合にうまく機能します。これは、アニメーションと静的プロパティ値を組み合わせる必要がある場合にも役立ちます。 たとえば、translate プロパティを使用して希望する場所に正確に配置する要素があり、それを kf-slide-in キーフレームでアニメーション化したい場合、アニメーション合成を行わないと、目に見えるジャンプが表示されます。 Amit Sheen による「ペン キーフレーム トークン - デモ 9 [フォーク]」を参照してください。 アニメーション合成を追加するように設定すると、アニメーションが既存のアニメーションとスムーズに組み合わされます。変換すると、要素は所定の位置に留まり、期待どおりにアニメーション化されます。 アニメーション千鳥 複数のアニメーションを処理するもう 1 つの方法は、アニメーションを「ずらす」ことです。つまり、最初のアニメーションが終了した少し後に 2 番目のアニメーションを開始します。これはすべてのケースに有効な解決策ではありませんが、開始アニメーションの後に連続アニメーションが続く場合には便利です。 /* フェードイン + 不透明パルス */ .notification { アニメーション: kf-フェードイン 2s イーズアウト、 kf-pulse 0.5 秒 2 秒イーズインアウト無限代替。 --kf-pulse-opacity-to: 0.5; }
Amit Sheen による「ペン キーフレーム トークン - デモ 10 [フォーク]」を参照してください。 順序の問題 私たちが扱うアニメーションの大部分は、transform プロパティを使用します。ほとんどの場合、この方が単に便利です。また、変換アニメーションを GPU で高速化できるため、パフォーマンス上の利点もあります。ただし、変換を使用する場合は、変換を実行する順序が重要であることを受け入れる必要があります。たくさん。 これまでのキーフレームでは、個別の変換を使用してきました。仕様によれば、これらは常に固定された順序で適用されます。最初に要素が移動し、次に回転し、次にスケールします。これは当然のことであり、私たちのほとんどが期待していることです。 ただし、transform プロパティを使用する場合、関数が記述される順序が、関数が適用される順序になります。この場合、X 軸上で何かを 100 ピクセル移動してから 45 度回転すると、最初に 45 度回転してから 100 ピクセル移動するのと同じではありません。 /* ピンクの四角形: 最初に移動し、次に回転します */ .example-1 { 変換: 変換X(100px) 回転(45度); }
/* 緑色の四角形: 最初に回転し、次に平行移動します */ .example-2 { 変換: 回転(45度) 変換X(100ピクセル); }
Amit Sheen による「ペン キーフレーム トークン - デモ 11 [フォーク]」を参照してください。 ただし、変換順序によれば、すべての個々の変換 (キーフレーム トークンに使用したすべてのもの) は、変換関数の前に発生します。つまり、transform プロパティで設定した内容はすべてアニメーションの後に発生します。ただし、たとえば kf-spin キーフレームと一緒に移動を設定すると、移動はアニメーションの前に行われます。まだ混乱していますか? これにより、次の場合のように、静的な値によって同じアニメーションでも異なる結果が生じる可能性があります。
/* 両方のスピナーに共通のアニメーション */ .スピナー { アニメーション: kf-spin 1s リニア無限。 }
/* ピンクのスピナー: 回転前に変換します (個別の変換) */ .スピナーピンク { 翻訳: 100% 50%; }
/* 緑色のスピナー: 回転してから移動します (関数の順序) */ .スピナーグリーン { 変換: 変換(100%, 50%); }
Amit Sheen による「ペン キーフレーム トークン - デモ 12 [フォーク]」を参照してください。 最初のスピナー (ピンク) は、kf-spin の回転前に変換が行われるため、最初にその場所に移動してから回転することがわかります。 2 番目のスピナー (緑) は、個々の変換後に発生する translation() 関数を取得します。そのため、要素は最初に回転し、次に現在の角度に相対して移動し、広い軌道効果が得られます。 いいえ、これはバグではありません。これは、CSS について知っておく必要があることの 1 つであり、複数のアニメーションや複数の変換を操作するときに留意する必要があります。必要に応じて、rotate() 関数を使用して要素を回転する kf-spin-alt キーフレームの追加セットを作成することもできます。 モーションの軽減 代替キーフレームについて話している間、「アニメーションなし」オプションを無視することはできません。キーフレーム トークンを使用する最大の利点の 1 つは、アクセシビリティを組み込むことができることですが、これは実際には非常に簡単です。アクセシビリティを念頭に置いてキーフレームを設計することで、モーションを減らしたいユーザーが、余分な作業やコードの重複を行うことなく、よりスムーズで気を散らすことのないエクスペリエンスを確実に得ることができます。 「Reduced Motion」の正確な意味は、アニメーションごとに、またプロジェクトごとに若干異なる場合がありますが、留意すべき重要な点がいくつかあります。 キーフレームのミュート 一部のアニメーションは柔らかくしたり遅くしたりすることができますが、モーションの低減が要求された場合に完全に消える必要があるアニメーションもあります。パルスアニメーションが良い例です。これらのアニメーションがモーション削減モードで実行されないようにするには、アニメーションを適切なメディア クエリでラップするだけです。
@media (reduced-motion を優先: 優先なし) { @keyfrmaeskfパルス{ {から スケール: var(--kf-pulse-scale-from, 1); 不透明度: var(--kf-pulse-opacity-from, 1); } {に スケール: var(--kf-pulse-scale-to, 1); 不透明度:var(--kf-pulse-opacity-to, 1); } } }
これにより、prefers-reduced-motion を Reduce に設定したユーザーはアニメーションが表示されず、好みに合わせたエクスペリエンスが得られます。 インスタントイン 入場アニメーションなど、単純に削除できないキーフレームもあります。値は変化し、アニメーション化する必要があります。そうしないと、要素に正しい値が設定されなくなります。しかし、縮小されたモーションでは、初期値からのこの移行は瞬時に行われる必要があります。 これを達成するには、値がすぐに終了状態にジャンプする追加のキーフレームのセットを定義します。これらはデフォルトのキーフレームになります。次に、前の例と同様に、prefers-reduced-motion を no-preference に設定するためのメディア クエリ内に通常のキーフレームを追加します。 /* 即座にポップインして動きを軽減 */ @keyframes kf-zoom { から、へ、 スケール: var(--kf-zoom-to, 1); } }
@media (reduced-motion を優先: 優先なし) { /* オリジナルのズームキーフレーム */ @keyframes kf-zoom { {から スケール: var(--kf-zoom-from, 0.8); } {に スケール: var(--kf-zoom-to, 1); } } }
こうすることで、モーションを減らしたいユーザーには要素が即座に最終状態で表示され、他のユーザーにはアニメーション化されたトランジションが表示されます。 ソフトなアプローチ 動きを残しておきたい場合もありますが、元のアニメーションよりもはるかに柔らかく、穏やかなものになります。たとえば、バウンスの入り口を緩やかなフェードインに置き換えることができます。
@keyframes kf-bounce { /* モーションを軽減するソフト フェードイン */ }
@media (reduced-motion を優先: 優先なし) { @keyframes kf-bounce { /* オリジナルのバウンス キーフレーム */ } }
現在、動きの減少を有効にしても、ユーザーは外観の感覚を得ることができますが、バウンスや弾性アニメーションの激しい動きはありません。 構成要素を適切に配置したら、次の問題は、それらを実際のワークフローの一部にする方法です。柔軟なキーフレームを作成することは別のことですが、大規模なプロジェクト全体で信頼性の高いキーフレームを作成するには、苦労して学ばなければならなかったいくつかの戦略が必要です。 実装戦略とベストプラクティス キーフレーム トークンの堅牢なライブラリを作成したら、本当の課題は、それらを日常の作業にどのように組み込むかです。
すべてのキーフレームを一度に入力して、問題が解決したと宣言したくなる誘惑にかられますが、実際には、徐々に採用することで最良の結果が得られることがわかりました。フェードやスライドなどの最も一般的なアニメーションから始めます。これらは、大規模な書き換えを必要とせずにすぐに価値を示す簡単な勝利です。 ネーミングも注目すべきポイントだ。一貫したプレフィックスまたは名前空間により、どのアニメーションがトークンであり、どのアニメーションがローカルの 1 回限りのものであるかが明確になります。また、偶発的な衝突を防ぎ、新しいチームメンバーが共有システムを一目で認識できるようにします。 ドキュメントはコード自体と同じくらい重要です。各キーフレーム トークンの上に短いコメントを追加するだけでも、後で推測する時間を節約できます。開発者は、トークン ファイルを開いて必要な効果をスキャンし、使用パターンをコンポーネントに直接コピーできる必要があります。 柔軟性があるからこそ、このアプローチは努力する価値があります。賢明なカスタム プロパティを公開することで、システムを壊すことなくアニメーションを適応させる余地をチームに与えます。同時に、過度に複雑にしないようにしてください。重要なノブを提供し、残りの部分は自分の意見に合わせてください。 最後に、アクセシビリティを思い出してください。すべてのアニメーションにモーションを減らした代替手段が必要なわけではありませんが、多くのアニメーションには必要があります。これらの調整を早期に組み込むことは、後から調整する必要がないことを意味し、ユーザーが言及しなくても、ユーザーが気づくレベルの配慮を示しています。
私の経験では、キーフレーム トークンをデザイン トークン ワークフローの一部として扱うことで、キーフレーム トークンが定着するのです。一度配置されると、特殊効果のように感じることはなくなり、デザイン言語の一部となり、製品の動きや反応の自然な延長になります。 まとめ アニメーションはインターフェイス構築の最も楽しい部分の 1 つですが、構造がなければフラストレーションの最大の原因の 1 つになる可能性もあります。キーフレームをトークンとして扱うことで、通常は煩雑で管理が難しいものを、明確で予測可能なシステムに変えることができます。 本当の価値は、コードを数行節約することだけにあるわけではありません。フェード、スライド、ズーム、スピンを使用するときに、プロジェクト全体でどのように動作するかを正確に把握できるという自信があります。それは、無限のバリエーションによる混乱のないカスタム プロパティから得られる柔軟性にあります。そしてそれは、追加として追加されるのではなく、基盤に組み込まれたアクセシビリティにあります。後付けの考え。 私はこれらのアイデアがさまざまなチームやさまざまなコードベースで機能するのを見てきましたが、そのパターンは常に同じでした。 トークンが配置されると、キーフレームは散在するトリックのコレクションではなくなり、デザイン言語の一部になります。これらにより、製品がより意図的で、より一貫性があり、より生き生きとしているように感じられます。 この記事から 1 つのことを理解するなら、それは次のとおりです。アニメーションには、色、タイポグラフィ、間隔に対してすでに行っているのと同じ注意と構造が必要です。キーフレーム トークンへの少額の投資は、インターフェイスが移動するたびに効果をもたらします。