時計仕掛けのように、またはCSS 3で60 FPSでアニメーション化

画像とテキストは著者に属します。







モバイルアプリの要素をアニメーション化するのは簡単です。 この記事のヒントに従えば、 正しいアニメーションも簡単になります。







現在、プロジェクトでCSS 3アニメーションを使用していない人は、それでも、すべてだけでなく、正しく実行できる人はほとんどいません。 いわゆる「ベストプラクティス」でも説明されていますが、人々は独自の方法で物事を続けています。 おそらく、すべてがこのように配置されている理由を理解していないためであり、そうでない場合はそうではありません。









モバイルデバイスの範囲は拡大していることを行うだけなので、これを念頭に置いてコードを最適化しないと、このアプローチは遅かれ早かれ、ユーザーが遭遇するアプリケーションブレーキの形で感じられます。







覚えておいてください:世界には常に進歩を推進している主要な機器がいくつかあるにもかかわらず、人々はお気に入りのアンティークを使います。







CSS 3を正しく使用すると、いくつかの問題が修正されるので、いくつかのことを理解できるように支援したいと思います。







調教時間



ページ上のこれらすべての要素をレンダリングおよび管理するプロセスで、ブラウザーは何をしますか? 答えは、 CRP (Critical Rendering Path)と呼ばれるこのシンプルなタイムラインです。







画像



スムーズなアニメーションを実現するには、 Compositeステップに影響するプロパティの変更に集中する必要があります。







スタイル



画像



ブラウザはスタイルの計算を開始し、スタイルを要素に適用します。







フレーム



画像



この段階で、ブラウザはページ上の要素の位置を形成および決定します。 この時点で、ブラウザは幅、高さ、インデントなどのページ属性を設定します。







描画



画像



ブラウザは要素を個別のレイヤーとして形成し、 box-shadowborder-radiuscolorbackground-colorなどのプロパティを適用します。







全体像



画像



現時点では、ブラウザーはすべての形成されたレイヤーを画面に描画するため、この段階で魔法が必要になります。 最新のブラウザは、4種類のプロパティを完全にアニメーション化し、変換と半透明で動作します。







  1. 位置。 変換:translateX( n )translateY( n )translateZ( n );

  2. スケーリング。 変換:スケール( n );

  3. ターン。 変換:回転( n deg);

  4. 半透明。 不透明度: n ;



60 FPSに到達する方法



HTMLから始めて、 .layout



コンテナ内のアプリケーションメニューの単純な構造を作成しましょう。







 <div class="layout"> <div class=”app-menu”></div> <div class=”header”></div> </div>
      
      





画像



間違った方法



 .app-menu { left: -300px; transition: left 300ms linear; } .app-menu-open .app-menu { left: 0px; transition: left 300ms linear; }
      
      





変更しているプロパティに注目しましたか? 左/上/右/下のプロパティを持つ変換を使用しないでください。 ブラウザが毎回レイヤーを再構築するように強制するため、スムーズなアニメーションを作成できません。これはすべての子に影響します。







結果は次のようになります。







画像



アニメーションが遅い。 DevToolsのタイムラインをチェックして、実際に何が起こるかを確認しました。結果は次のとおりです。







画像



この図は、FPSの不安定性とその結果としてのパフォーマンスの低下を明確に示しています。







変換の使用



 app-menu { -webkit-transform: translateX(-100%); transform: translateX(-100%); transition: transform 300ms linear; } .app-menu-open .app-menu { -webkit-transform: none; transform: none; transition: transform 300ms linear; }
      
      





上記のプロパティとは異なり、変換は既に描画されたブロックに、つまりCompositeステージで適用されます。 上記の例では、アニメーションを開始する前に、すべてのレイヤーがすでに描画され、操作の準備ができていることをブラウザに伝えます。







画像



タイムラインは、FPSがより均一になったことを示しているため、アニメーションはやや滑らかに見えます。







画像



GPUアニメーション



すべてがさらに良くなる可能性があります。 このために、グラフィックアクセラレータを使用します。







 .app-menu { -webkit-transform: translateX(-100%); transform: translateX(-100%); transition: transform 300ms linear; will-change: transform; }
      
      





translateZ()またはtranslate3d()は、一部のハックのように、一部のブラウザーでは引き続き必要ですが、将来のプロパティは変更されます。 ブラウザーに、要素を別のレイヤーに移動して、アセンブリまたはレンダリングのためにワイヤーフレーム全体をチェックしないように指示します。







画像



アニメーションがどれだけ滑らかになったかをご覧ください。 タイムラインはこれを確認します:







画像



FPSはさらに安定しましたが、まだ最初にアニメーションの遅い部分が1つあります。 メニュー構造に基づいて、JSは通常次のように書き込みます。







 function toggleClassMenu() { var layout = document.querySelector(".layout"); if(!layout.classList.contains("app-menu-open")) { layout.classList.add("app-menu-open"); } else { layout.classList.remove("app-menu-open"); } } var menu = document.querySelector(".menu-icon"); menu.addEventListener("click", toggleClassMenu, false);
      
      





問題は、クラスを.layout



コンテナに追加することにより、ブラウザーにスタイルの再カウントを強制し、レイアウトとレンダリングの速度に影響することです。







時計仕掛けのように



しかし、メニューが範囲外にある場合はどうでしょうか? これを行ったら、実際にアニメーション化する必要がある要素、つまりメニューのみを使用します。 明確にするために、HTML構造は次のとおりです。







 <div class="menu"> <div class="app-menu"></div> </div> <div class="layout"> <div class="header"></div> </div>
      
      





これで、少し異なる方法でメニューのステータスを制御できます。 transitionendイベントを使用して、アニメーションが終了した後に削除されるクラスを介してアニメーションを制御します。







 function toggleClassMenu() { myMenu.classList.add("menu--animatable"); myMenu.classList.add("menu--visible"); } function onTransitionEnd() { myMenu.classList.remove("menu--animatable"); } var myMenu = document.querySelector(".menu"), menu = document.querySelector(".menu-icon"); myMenu.addEventListener("transitionend", onTransitionEnd, false); menu.addEventListener("click", toggleClassMenu, false);
      
      





さて、今すべて一緒に。 あなたの注意はCSS 3の完全な例であり、すべてが整っています:







 .menu { position: fixed; left: 0; top: 0; width: 100%; height: 100%; overflow: hidden; pointer-events: none; z-index: 150; } .menuvisible { pointer-events: auto; } .app-menu { background-color: #fff; color: #fff; position: relative; max-width: 400px; width: 90%; height: 100%; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.5); -webkit-transform: translateX(-103%); transform: translateX(-103%); display: flex; flex-direction: column; will-change: transform; z-index: 160; pointer-events: auto; } .menu-visible.app-menu { -webkit-transform: none; transform: none; } .menu-animatable.app-menu { transition: all 130ms ease-in; } .menu--visible.menu-animatable.app-menu { transition: all 330ms ease-out; } .menu:after { content: ''; display: block; position: absolute; left: 0; top: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.4); opacity: 0; will-change: opacity; pointer-events: none; transition: opacity 0.3s cubic-bezier(0,0,0.3,1); } .menu.menu--visible:after{ opacity: 1; pointer-events: auto; }
      
      





画像



そして、タイムラインは何を示していますか?







画像



そのようなもの。








All Articles