CSS のみのウルフェンシュタイン 私が数週間前に作った小さなプロジェクトです。 CSS 3D 変換とアニメーションの実験でした。
に触発された FPSデモ 別 ウルフェンシュタイン CodePen、私は自分のバージョンを構築することにしました。 これは、元の Wolfenstein 1D ゲームのエピソード 9 – フロア 3 に大まかに基づいています。
編集者: このゲームでは、ゲーム オーバー画面を回避するために、意図的に迅速な対応が求められます。
ここにプレイスルービデオがあります:
一言で言えば、私のプロジェクトは、慎重にスクリプト化された長い CSS アニメーションに他なりません。 さらに、 チェックボックスハック.
:checked ~ div { animation-name: spin; }
環境は 3D グリッド フェースで構成され、アニメーションはほとんどプレーンな 3D 移動と回転です。 本当に空想的なものは何もありません。
ただし、次の XNUMX つの問題を解決するのは特に困難でした。
- プレイヤーが敵をクリックするたびに、「武器発射」アニメーションを再生します。
- 動きの速いボスが最後の一撃を食らうと、ドラマチックなスローモーションに突入。
技術レベルでは、これは次のことを意味します。
- 次のチェックボックスがチェックされているときにアニメーションを再生します。
- チェックボックスがチェックされている場合、アニメーションを遅くします。
実際、私のプロジェクトではどちらも適切に解決されませんでした! 最終的に回避策を使用するか、あきらめました。
一方、掘り下げた結果、最終的に両方の問題の鍵を見つけました。それは、実行中の CSS アニメーションのプロパティを変更することです。 この記事では、このトピックについてさらに詳しく説明します。
- インタラクティブな例がたくさん。
- 分析: 各例はどのように機能するか (または機能しないか)?
- 舞台裏: ブラウザはアニメーションの状態をどのように処理するのですか?
私にさせて 「レンガを投げて」.
問題 1: アニメーションの再生
最初の例: 「ちょうど別のチェックボックス」
私の最初の直感は、「別のチェックボックスを追加するだけ」でしたが、機能しません。
各チェックボックスは個別に機能しますが、両方が同時に機能するわけではありません。 XNUMX つのチェックボックスが既にオンになっている場合、もう XNUMX つのチェックボックスは機能しなくなります。
これがどのように機能するか (または「機能しない」) は次のとおりです。
-
animation-name
of<div>
isnone
デフォルトでは - ユーザーが XNUMX つのチェックボックスをクリックすると、
animation-name
になるspin
となり、アニメーションが最初から始まります。 - しばらくして、ユーザーは他のチェックボックスをクリックします。 新しい CSS ルールが有効になりますが、
animation-name
is まだspin
、つまり、アニメーションは追加も削除もされません。 アニメーションは、何も起こらなかったかのように再生を続けます。
XNUMX 番目の例: 「アニメーションの複製」
実用的なアプローチの XNUMX つは、アニメーションのクローンを作成することです。
#spin1:checked ~ div { animation-name: spin1; }
#spin2:checked ~ div { animation-name: spin2; }
しくみはこうです:
animation-name
isnone
最初は- ユーザーが「Spin!」をクリックすると、
animation-name
になるspin1
. アニメーションspin1
追加したばかりなので最初から始めます。 - ユーザーが「Spin again!」をクリックすると、
animation-name
になるspin2
. アニメーションspin2
追加したばかりなので最初から始めます。
ステップ #3 では、 spin1
CSS ルールの順序のため、削除されます。 「もう一度回して!」ではうまくいきません。 最初にチェックされます。
XNUMX番目の例: 「同じアニメーションを追加する」
別の実用的なアプローチは、「同じアニメーションを追加する」ことです。
#spin1:checked ~ div { animation-name: spin; }
#spin2:checked ~ div { animation-name: spin, spin; }
これは前の例に似ています。 実際には、次のように動作を理解できます。
#spin1:checked ~ div { animation-name: spin1; }
#spin2:checked ~ div { animation-name: spin2, spin1; }
「Spin again!」の際に注意してください。 がチェックされている場合、古い実行中のアニメーションが新しいリストの XNUMX 番目のアニメーションになり、直感的でない可能性があります。 直接的な結果は次のとおりです。次の場合、トリックは機能しません。 animation-fill-mode
is forwards
. ここにデモがあります:
なぜこれが当てはまるのか疑問に思っている場合は、いくつかの手がかりがあります。
animation-fill-mode
isnone
デフォルトでは、これは「再生していない場合、アニメーションはまったく効果がない」ことを意味します。animation-fill-mode: forwards;
は、「アニメーションの再生が終了した後、最後のキーフレームに永遠にとどまる必要がある」ことを意味します。spin1
の決定は常にオーバーライドされますspin2
なぜならspin1
リストの後半に表示されます。- ユーザーが「Spin!」をクリックし、完全にスピンするのを待ってから、「Spin again!」をクリックしたとします。 この瞬間。
spin1
はすでに終了しており、spin2
ちょうど始まります。
議論
経験則: 既存の CSS アニメーションを「再開」することはできません。 代わりに、新しいアニメーションを追加して再生したいと考えています。 これは、 W3C仕様:
アニメーションが開始されると、終了するかアニメーション名が削除されるまで続きます。
最後の XNUMX つの例を比較すると、実際には、特に CSS プリプロセッサが利用可能な場合は、「アニメーションのクローン作成」の方がうまくいくことが多いと思います。
問題 2: スローモーション
アニメーションを遅くすることは、より長く設定するだけの問題だと思うかもしれません animation-duration
:
div { animation-duration: 0.5s; }
#slowmo:checked ~ div { animation-duration: 1.5s; }
実際、これは機能します:
…またはそうですか?
いくつかの調整により、問題を簡単に確認できるはずです。
はい、アニメーションが遅くなります。 いいえ、見栄えがよくありません。 チェックボックスを切り替えると、犬は(ほとんど)常に「ジャンプ」します。 さらに、犬は最初の位置ではなくランダムな位置にジャンプするようです。 どうして?
XNUMX つの「影の要素」を導入すると、理解しやすくなります。
両方のシャドウ要素が異なるアニメーションで同じアニメーションを実行しています animation-duration
. チェックボックスの影響を受けません。
チェックボックスを切り替えると、要素は XNUMX つのシャドウ要素の状態を即座に切り替えます。
引用 W3C仕様:
アニメーションの実行中にアニメーション プロパティの値を変更すると、アニメーションが開始時からそれらの値を持っているかのように適用されます。
これは、次の ステートレス これにより、ブラウザはアニメーションの値を簡単に判断できます。 実際の計算方法が書かれています こちら & こちら.
別の試み
XNUMX つのアイデアは、現在のアニメーションを一時停止してから、そこから引き継ぐ遅いアニメーションを追加することです。
div {
animation-name: spin1;
animation-duration: 2s;
}
#slowmo:checked ~ div {
animation-name: spin1, spin2;
animation-duration: 2s, 5s;
animation-play-state: paused, running;
}
だからそれは動作します:
…またはそうですか?
「Slowmo!」をクリックすると速度が遅くなります。 しかし、完全な円を待つと、「ジャンプ」が表示されます。 実は「Slowmo!」のときは必ずその位置にジャンプします。 をクリックします。
その理由は、 from
キーフレームが定義されていますが、そうすべきではありません。 ユーザーが「Slowmo!」をクリックすると、 spin1
ある位置で一時停止し、 spin2
全く同じ位置からスタート。 その位置を事前に予測することはできません…またはできますか?
実用的なソリューション
私たちはできる! カスタム プロパティを使用して、最初のアニメーションで角度をキャプチャし、それを XNUMX 番目のアニメーションに渡すことができます。
div {
transform: rotate(var(--angle1));
animation-name: spin1;
animation-duration: 2s;
}
#slowmo:checked ~ div {
transform: rotate(var(--angle2));
animation-name: spin1, spin2;
animation-duration: 2s, 5s;
animation-play-state: paused, running;
}
@keyframes spin1 {
to {
--angle1: 360deg;
}
}
@keyframes spin2 {
from {
--angle2: var(--angle1);
}
to {
--angle2: calc(var(--angle1) + 360deg);
}
}
注: @property
がこの例で使用されています。 すべてのブラウザでサポートされているわけではありません.
「完璧な」ソリューション
前の解決策には注意点があります。「slowmo の終了」はうまく機能しません。
より良い解決策は次のとおりです。
このバージョンでは、スローモーションをシームレスに開始または終了できます。 実験的な機能も使用されていません。 それで、それは完璧な解決策ですか? はいといいえ。
このソリューションは、「シフト」「ギア」のように機能します。
- ギア: XNUMX つあります
<div>
秒。 一方は他方の親です。 どちらもspin
アニメーションだが異なるanimation-duration
. 要素の最終的な状態は、両方のアニメーションの累積です。 - シフト:最初はXNUMXつだけ
<div>
アニメーションが実行されています。 もう一方は一時停止中です。 チェックボックスを切り替えると、両方のアニメーションの状態が入れ替わります。
結果はとても気に入っていますが、問題が XNUMX つあります。 spin
一般に、他のタイプのアニメーションでは機能しません。
実用的なソリューション (JS を使用)
一般的なアニメーションの場合、少しの JavaScript でスローモーション機能を実現できます。
簡単な説明:
- カスタム プロパティは、アニメーションの進行状況を追跡するために使用されます。
- チェックボックスをオンにすると、アニメーションが「再開」されます。
- JS コードは正しい
animation-delay
シームレスな移行を保証します。 私はお勧め この記事 の負の値に慣れていない場合animation-delay
.
このソリューションは、「アニメーションの再開」と「ギアシフト」アプローチのハイブリッドと見なすことができます。
ここでは、アニメーションの進行状況を正しく追跡することが重要です。 次の場合に回避策が可能です。 @property
利用できません。 例として、このバージョンでは z-index
進行状況を追跡するには:
補足: 当初、CSS のみのバージョンも作成しようとしましたが、成功しませんでした。 100%確かではありませんが、それが原因だと思います animation-delay
is アニメート不可.
これは最小限の JavaScript を使用したバージョンです。 「スローモーションに入る」のみ動作します。
動作する CSS のみのバージョンを作成できたら、お知らせください。
スローモーションの任意のアニメーション (JS を使用)
最後に、複雑なアニメーションが複数ある場合でも、(ほぼ) あらゆるアニメーションで機能するソリューションを共有したいと思います。 @keyframes
:
基本的に、アニメーションの進行状況トラッカーを追加してから、慎重に計算する必要があります animation-delay
新しいアニメーションのために。 ただし、正しい値を取得するのが難しい場合があります (ただし、可能です)。
例:
animation-timing-function
ではありませんlinear
.animation-direction
ではありませんnormal
.- 複数の値
animation-name
異なるとanimation-duration
'砂animation-delay
's。
この方法も記載されています こちら WebアニメーションAPI.
謝辞
CSS のみのプロジェクトに遭遇した後、私はこの道を歩み始めました。 一部は 繊細なアートワーク、そしていくつかは 複雑な仕掛け. 私のお気に入りは、3D オブジェクトを含むものです。たとえば、これです。 弾むボール この パッキングキューブ.
最初は、これらがどのように作られているのかわかりませんでした。 後で私は読んで多くのことを学びました Ana Tudor によるこの素敵なチュートリアル.
結局のところ、CSS を使用して 3D オブジェクトを作成してアニメーション化することは、CSS を使用して行うことと大差ありません。 ブレンダー、ちょっと違う風味で。
まとめ
この記事では、CSS アニメーションの動作を調べました。 animate-*
プロパティが変更されます。 特に、「アニメーションの再生」と「アニメーションのスローモーション」のソリューションを考え出しました。
この記事が興味深いものであることを願っています。 あなたの考えを教えてください!