この記事のアイデアと記事に含まれる数式は、@Thai Pangsakulyanont が共有した記事「CSS での Spring アニメーション」から来ています。
CSS アニメーションは Web アニメーションではもはや新しい技術ではありませんが、アニメーションを作成する場合、タイミング関数の使用方法に苦労することがよくあります。通常の状況では、アニメーション タイミング関数/トランジション タイミング関数に付属するいくつかのキーワード アニメーション関数が使用されます。 Web アニメーションに少し慣れている学生は、いくつかのタイミング関数の作成に cubic-bezier.com を使用できます。多くの場合、これらはすべて、原理が何であるかを知らずに使用に限定されています。
さらに、これらの基本的なタイミング関数を使用して、実際のバウンス (バネの弾性と同様) アニメーション効果をシミュレートすることはほとんど不可能です。
実際にはそうではありません。なぜそんなことを言うのですか?アニメーションを作成するプロセスでは、数学はより多くの意味のあることを行うのに役立ちます。たとえば、数学的な微積分の原理を使用すると、より現実的なアニメーション効果を作成できます。まさにスプリングバウンス効果と同じです。この記事はこの内容について書いていますので、興味のある方は読み進めてください。
まずアニメーション効果の例を見てみましょう:
上記のアニメーションの例は、@dtinth によって書かれたケースからのものです。作者の Stylus が Sass に置き換えられただけです。
ちなみに、これらの数式は @Thai Pangsakulyanont さんがシェアした記事「CSS での Spring アニメーション」から引用しています。また、私は20年近く学校から離れており、多くの知識を先生方に還元してきましたので、もし記事に間違いがあればご指摘ください。
これは永遠のテーマであり、実際には心配する必要はありません。 JavaScript について何も知らないクラスメートがよく追求するのは、CSS を通じてアニメーション効果を完成させ、同様の効果を JavaScript で実現する方法です (これはほぼ不可能ですが、多くの場合、ほとんど関係ありません)。これらはさておき、技術的な観点から見ると、現在、 React-motion 、 Velocity.js 、 GSAP など、Web アニメーションを実装するための優れたライブラリが数多くあります。しかし、それらにはすべて問題があります。DOM への JavaScript アクセスはシングルスレッドです。 CSS アニメーションを使用する場合、この問題は発生しません。
ボックスを左:100px から左:200px に押すなど、簡単なアニメーションを見てみましょう。
これは、時間が経っても 100 ピクセルと 200 ピクセルの間で止まらないことを意味します。
アニメーションが実行されると、覆われた領域が 100 ピクセル (100% から 0%) 減少し、同時に覆われた領域が 200 ピクセル (0% から 100%) に増加します。
アニメーションを 200px まで処理するプロセスがあります。このプロセスを略して p と呼びます。p を使用して、各期間の left の値を計算できます。
$$left: (1-p) )(100px )+p(200px)$$
次の図は、その仕組みを説明しています:
要約すると、アニメーションが A から B に遷移し、動きの進行状況が p の場合、その属性値はそれは次のようになります:
$$(1-p)A+pB$$
一部の生徒は次のように書きたがるかもしれません:
$$A+p(B-A)$$
これを lerp と呼ぶか、 線形補間 (線形補間)。
これは線形と呼ばれていますが、現実世界のアニメーションは線形ではありません。たとえば、アニメーションをゆっくりと開始し、すぐに終了するようにしたい場合があります (オブジェクトの加速と同等)。イージング関数はアニメーションの再生中に使用できますが、その場合の処理と時間は線形操作ではありません。
イージング関数は主に、時間とアニメーションの展開との関係を作成するために使用されます。
イージング関数は、アニメーション効果をより現実的に見せるために実行される速度を指定します。現実の物体は一定のリズムで動きますが、最初はあまり速く動きません。引き出しを開けるとき、私たちは最初にスピードを上げ、次にスピードを落とします。何かが落ちると、最初はますます速く落ち、地面にぶつかり、跳ね返り、最後に再び床にぶつかります。 —— イージング関数
注: mj.js の公式 Web サイトでは、イージング関数について詳しく説明されています。
以下は、動いていないときの位置が x = 1 であると仮定したスプリング ブロックです:
ここでスプリングを押すと、その位置は x = 0 になります:
手を放したときスプリングを押さないと、スプリングは平衡位置 x = 1 に達するまで前後に動き、その後停止します。
これはイージング関数のようなものです。つまり、0%から始まり100%で終わる時間関数(タイミング関数)です。バネは内部のオブジェクトの 1 つです。
以下の内容は複雑になり始めます。いきなり CSS アニメーションについて話しているのではなく、物理を学び始めているように感じます。以下では、いくつかの物理方程式 (力学、バネ関連の物理方程式) が関係します。
まず スプリング力を見てみましょう スプリング ブロックを平衡位置まで引き戻します。ここ、この抵抗がなければ、バネが前後に揺れなくなることを想像してみてください。
$$F_{d}=-cv$$
次に、バネにかかる力を計算できます: $$F=F_{s}+F_{d}=-kX-cv $$
誰もがニュートンの第 2 法則について聞いたことがあると思います:
$$F=ma$$
簡単にするために、質量の値を仮定します (私の記憶が正しければ、これは密度を指すようです)オブジェクト) は 1 (つまり m=1) なので、次のようになります:
$$F=-kX-cv$$ $$ma=-kX-cv$$ $$a=-kX-cv$$
さて、X は平衡位置からの物体の動きを表します。これは、x = x から x = 1 に移動したい場合、指定された位置に到達するために毎回 x-1 移動する必要があることを意味します。
$$X=x-1$$
これは左の値を計算できます:
$$a=-k(x-1)-cv$$
これは運動方程式です。これで、物理方程式から必要な運動方程式を導き出す作業が完了しました。
計算
微積分の知識をまだ覚えていれば、次の内容は難しくありません。次に、いくつかの微積分の公式を使用して、オブジェクトの移動の位置と時間の関係を計算します。
$$x=f(t)$$
$$v=frac{dx}{dt}=f'(t)$$
速度に従って、加速度を取得します:
$$a=frac{dv}{dt}=f''(t)$$
運動方程式を思い出してください:
$$a=-k(x-1)-cv $$
上記を使用します x、v、a を数式で置き換えると、今表示されている数式は次のようになります:
$$f''(t)=-k(f(t)-1)-cf '(t)$$
これは微分方程式です。これらは私には複雑すぎます。もしあなたが私と同じで、微積分の知識を使ってそれらを解決する方法がわからない場合は、Wolfram | Alpha を使用してください。
物事を簡単にするために、複雑さを軽減するためにいくつかの制限を設けます。
ブロックを移動させる前に、ブロックの位置は x=0 にあると想定されることを思い出してください。つまり、ブロックの初期位置は x=0、初期時間は t=0 であるため、次の結果が得られます:
$$f(0)=0$$
また、特別なボディが次のことを行うこともわかっています。これは、次のような式があることも意味します:
$$f'(0)=0$$
残念ながら、Wolfram|Alpha は k や c のような変数を使用してこの方程式を解くことができません。他の値も必要です。
たとえば、react-motion ライブラリのウォブル アニメーションは k=180、c=12 に設定されています。これで方程式が解けます:
$$f(0)=0$$ $$f'(0)=0$$ $$f''(t)=-180(f(t)-1)-12f ' (t)$$
Wolfram | Alpha に入力します:
f(0) = 0; f'(0) = 0; f''(t) = -180(f(t) - 1) - 12f'(t)
以下の図が表示されます:
Wolfram | Alpha は答えを与えます:
$$x=-frac{1}{ 2}e ^{-6t}(-2e^{6t}+sin(12t)+2cos(12t))$$
1/2、6、sin()、cos() はどこから来たのかわかりません。これは私にとってあまりにも複雑で、難しすぎ、信じられないほどです。
しかし、これは合法に見えます (合法かどうかはわかりませんが、Wolfram | Alpha の計算は間違っていないものと仮定します)。春。 t=0 から t=1 までの値を 0.01 ずつ区切って次のような絵を描きます。
CSS アニメーション
このような複雑な方程式を CSS に適用することはできませんが、いくつかの近似式を生成することはできます。 CSS アニメーションでは、これは @keyframes で指定できますが、方程式は連続関数です。
上に描いた図のように、これを CSS の @keyframes に適用すると、たとえばアニメーション期間が 1 秒の場合、CSS コードは次のようになります。
@keyframes keyframe-name { 0% { /* css code for t=0.00s */ } 1% { /* css code for t=0.01s */ } 2% { /* css code for t=0.02s */ } 3% { /* css code for t=0.03s */ } /* ... */ 99% { /* css code for t=0.99s */ } 100% { /* css code for t=1.00s */ }}
@Thai Pangsakulyanont がシェアした記事「CSS での Spring アニメーション」では Stylus を使用しています。 Stylusに慣れていないのでSassに変更しました。
まず、Sass を使用して、Wolfram | Alpha から与えられた答えを関数に変更する必要があります:
@function spring-wobbly($t) { @return -0.5 * pow(2.71828, (-6 * $t)) * (-2 * pow(2.71828, (6 * $t)) + sin(12 * $t) + 2 * cos(12 * $t))}
Sass 自体は、sin() や cos() などの数学関数を提供していないためです。これらの関数を自分で書かなければならない場合は、非常に面倒です。ここでは、非常に優れた Sass ライブラリをお勧めします
MathSass
。このライブラリは一般的な関数をカバーしています。詳細な使用方法については、使用仕様を参照してください。たとえば、上記の関数の前に数学を導入します:
@import "node_modules/mathsass/dist/math";
実際のプロジェクトでは、上記のアドレスを独自のプロジェクト アドレスに置き換えて有効にします。 还记得前面使用插值函数覆盖tweeing动画那部分吗,我们也可以写一个函数: 接下来生成 @keyframes : 生成的CSS: 接下来只需要引用声明好的动画: 效果如下: 在动画中其实运用到数学原理还是很多的,比如@bboy90的《 CSS3动画帧数科学计算法 》一文详细介绍了如何通过公式合理的计算 @keyframes 。另外附上@月影 姐姐分享的PPT,里面详细介绍了一些动画控制: 上面PPT里的数学公式和一些DEMO,非常值得我们去思考。另外附上一个视频: 回到文中主要介绍的内容,在实际动画制作中,你完全可以根据自己需要的材质密度和摩擦系数去自定义自己所需的动画效果。 当然你也可以尝试去修改 f'(0) 的值。比如设置一个负值,让盒子从相反的方向反弹回来。 你也可以使用不同的参数,让他运动得更快或更慢。总而言之,你可以根据上面的原理,去制定所需要的一切动画效果。 谁说编程不需要数学,今天不是编程,仅仅只是做一个动画效果,都运用到了物理学和数学中的微积分。所以说,你学的一切都是有用的。 在我看来,不管你懂不懂微积分,或者说物理相关的知识,你只需要知道其中的原理,哪怕你都不懂这些,你也可以借助第三方工具(比如说文中提到的Wolfram Alpha)可以帮助你解决你所欠缺的知识。 总而言之,学到的都是属于你的。如果想让一件事情做得更为完美,那么你的知识都将是其中的基石。@function lerp($a, $b, $p) { @return $a + $p * ($b - $a);}
@keyframes move { @for $i from 0 through 100 { #{$i}% { left: lerp(100px, 200px, spring-wobbly($i / 100)); } }}
.box { animation: 1s move linear; animation-fill-mode: both;}
定制
总结