CSS3アニメーションジャミングソリューションについての簡単な説明

CSS3アニメーションジャミングソリューションについての簡単な説明

なぜ詰まっているのでしょうか?

言及しなければならない前提があります。フロントエンド開発者は皆、ブラウザが単一のスレッドで実行されることを知っています。ただし、シングル スレッド、メイン スレッド、合成スレッドという概念を明確にする必要があります。

ブラウザは JS を単一のスレッドで実行しますが (ブラウザにスレッドが 1 つしかないのではなく、実行中であることに注意してください)、実際にはブラウザにはメイン スレッドと合成スレッドという 2 つの重要な実行スレッドがあり、これらが連携して Web ページをレンダリングします。

一般に、メイン スレッドは、JavaScript の実行、HTML 要素の CSS スタイルの計算、ページのレイアウト、1 つ以上のビットマップへの要素の描画、およびこれらのビットマップの合成スレッドへの受け渡しを担当します。

したがって、合成スレッドは、GPU を介してビットマップを画面に描画すること、ページの表示されている部分または間もなく表示される部分のビットマップを更新するようにメイン スレッドに通知すること、ページのどの部分が表示されているかを計算すること、ページをスクロールしたときにどの部分が表示されるかを計算すること、およびページをスクロールしたときに、対応する位置の要素を可視領域に移動する役割を担います。

では、なぜアニメーションがフリーズするのでしょうか?

理由は、メインスレッドと合成スレッドのスケジュールが無理だからです。

無理なスケジュール設定の理由について詳しく説明します。

高さ、幅、マージン、パディングを遷移値として使用する場合、ブラウザのメインスレッドの負荷が高くなります。たとえば、margin-left: -20px から margin-left: 0 までレンダリングする場合、メインスレッドは margin-left: -19px、margin-left: -18px、そして margin-left: 0 までのスタイルを計算する必要があります。さらに、メインスレッドがスタイルを計算するたびに、合成プロセスはそれを GPU に描画してから画面にレンダリングする必要があります。合計 20 回のメインスレッドレンダリングと 20 回の合成スレッドレンダリングが 20 回 + 20 回実行され、合計 40 回の計算が行われます。

メインスレッドのレンダリング プロセスは、ブラウザーが Web ページをレンダリングするプロセスを指します。

  • HTML を使用したドキュメント オブジェクト モデル (DOM) の作成
  • CSS を使用して CSS オブジェクト モデル (CSSOM) を作成する
  • DOMとCSSOMに基づくスクリプトの実行
  • DOMとCSSOMをマージしてレンダリングツリーを形成する
  • レンダリングツリーを使用してすべての要素をレイアウトする
  • すべての要素をペイントする

つまり、メインスレッドはスクリプト、レンダーツリー、レイアウト、ペイントの 4 つの段階の計算を毎回実行する必要があります。

また、transform が使用される場合、たとえば、tranform:translate(-20px,0) から transform:translate(0,0) の場合、メイン スレッドは tranform:translate(-20px,0) から transform:translate(0,0) を 1 回実行するだけで済み、その後、合成スレッドは -20px を 0px に 1 回変換するため、合計計算は 1+20 になります。

これはたった 19 倍の改善で、どれほど優れたパフォーマンス改善があるのか​​と言う人もいるかもしれません。

一度に 10 ミリ秒と想定します。

これにより、時間の消費が約 190 ミリ秒短縮されます。

中には、それはひどい、たった 190 ミリ秒だから問題ない、と言う人もいるかもしれません。

では、margin-leftが-200pxから0まで、10msずつ、10msずつだとどうなるでしょうか?

199≈2秒。

それはゴミだ、たったの 2 秒だ、問題ない、と言う人もいるでしょう。

シングルスレッドを忘れましたか?

2 秒 = 6 秒なので、パフォーマンスが 6 秒向上することを意味します。

データは推測に基づくものであるため、その信憑性については現時点では考慮されていません。

この記事の説得力を高めるために、例を使って私の主張を証明したいと思います。一緒に見ていきましょう。

フロントエンドでは、アニメーションを使用して、H5 ページのホームページ アニメーション遷移を実装します。これは非常にシンプルな効果です。カスタマー サービス アバターがホームページに読み込まれ、最初に拡大され、700 ミリ秒間表示された後、上部に縮小されます。コードは次のとおりです。

<!DOCTYPE html>
<html>
<head lang="ja">
  <メタ文字セット="utf-8">
  <meta name="viewport" content="width=デバイス幅、初期スケール=1.0、最大スケール=1.0、ユーザースケーラブル=1" >
  <script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/2.1.1/jquery.min.js"></script>
  <title>ホームページ読み込みアニメーション</title>
  <ヘッド>
    <スタイル>
      .welcome-main{
        表示: なし;        
        パディング下部: 40px;      
      }
      .トップ情報{        
        幅: 100%;        
        位置: 絶対;        
        左: 0;        
        上: 93px;      
      }
      .wec-img{
        幅: 175ピクセル;        
        高さ: 175px;        
        位置: 相対的;        
        パディング: 23px;        
        ボックスのサイズ: 境界線ボックス;        
        マージン: 0 自動;      
       }
      .wec-img:前{        
        コンテンツ: '';        
        位置: 絶対;        
        左: 0;        
        上: 0;        
        幅: 100%;        
        高さ: 100%;        
        背景: url("./images/kf-welcome-loading.jpg");        
        背景サイズ: 100%;      
       }
      .wec-img .img-con{
        幅: 100%;        
        高さ: 100%;        
        境界線の半径: 50%;        
        /*ボックスサイズ: ボーダーボックス;*/
        背景: url("./images/kf_1.jpg");        
        背景サイズ: 100%;        
        パディング: 1px;      
      }
      .wec-img .img-con img{
        幅: 100%;        
        高さ: 100%;        
        境界線の半径: 50%;      
      }
      .ロード済み.wec-img{
        -webkit-transform-origin: 中央上;      
      }        
      .loading.welcome-main{
        表示: ブロック;
      }
      .wec-img を読み込んでいます{
        -webkit-animation:fadeIn .3s 両方を緩和します。
      }
      .wec-img:before{をロード中
        -webkit-animation:rotate .6s .2s linear 両方;      
      }
      .loaded .top-info{
        -webkit-animation:mainpadding 1s 0s 両方を緩和します。      
      }
      .ロード済み.wec-img{
        -webkit-animation:imgSmall 1s 0s 両方を緩和します。}
      @-webkit-keyframes メインパディング{
        0%{-webkit-transform:translateY(0)  
      }
        100%{-webkit-transform:translateY(-87px)   
        }
      }      
      @-webkit-keyframes imgSmall{
        0%{
          幅: 175ピクセル;          
          高さ: 175px;          
          パディング: 23px;        
        }
        100%{          
          幅: 60ピクセル;          
          高さ: 60px;          
          パディング: 0;        
        }
      }      
      @-webkit-keyframes フェードイン{
        0%{不透明度:0;-webkit-transform:scale(.3)}
        100%{不透明度:1;-webkit-transform:scale(1)}
      }      
      @-webkit-keyframes 回転{
        0%{不透明度:0;-webkit-transform:rotate(0deg);}
        50%{不透明度:1;-webkit-transform:rotate(180deg);}
        100%{不透明度:0;-webkit-transform:rotate(360deg);}
      }     
      </スタイル>
    <本文>
      <div class="welcome-main">
        <div class="top-info">
          <div class="wec-img"><p class="img-con"><img src="" alt=""></p></div>
        </div>
      </div>
      <スクリプト>
        $('.welcome-main').addClass('読み込み中');
        setTimeout(関数(){
          $('.hi.fst').removeClass('読み込み中');
          $('.welcome-main').addClass('ロードされました');
        },700);
      </スクリプト>
    </本文>
  </html>

Chrome ではテストは正常でしたが、QA にテストを送信したところ、Huawei (システム 4.2) や OPPO (システム 5.1) などの一部のモデルで遅延が発生していることが判明しました。

困惑したので、「CSSアニメーションとトランジションのブラウザパフォーマンス問題の徹底理解」の記事を参考に、画像スケーリングのアニメーション要素を次のように変形に変更しました。

@-webkit-keyframes imgSmall{
 0%{
   -webkit-transform:スケール(1);
 }
 100%{
   -webkit-transform:スケール(.465);
 }
}

案の定、ラグの問題は解決しました。

記事「CSS アニメーションとトランジションのブラウザ パフォーマンスの問題に関する詳細な理解」では、最新のブラウザには通常、Web ページをレンダリングするために連携して動作する 2 つの重要な実行スレッド (メイン スレッドと合成スレッド) があることが説明されています。

一般に、メイン スレッドは、JavaScript の実行、HTML 要素の CSS スタイルの計算、ページのレイアウト、1 つ以上のビットマップへの要素の描画、およびこれらのビットマップの合成スレッドへの受け渡しを担当します。

したがって、合成スレッドは、GPU を介してビットマップを画面に描画すること、ページの表示されている部分または間もなく表示される部分のビットマップを更新するようにメイン スレッドに通知すること、ページのどの部分が表示されているかを計算すること、ページをスクロールしたときにどの部分が表示されるかを計算すること、およびページをスクロールしたときに、対応する位置の要素を可視領域に移動する役割を担います。

次のように、要素の高さを 100 ピクセルから 200 ピクセルに変更するとします。

div {
  高さ: 100px;
  遷移: 高さ 1 秒線形;
}
  
div:ホバー{
  高さ: 200px;
}

メインスレッドと合成スレッドは、次のフローチャートに従って対応する操作を実行します。オレンジ色のボックス内の操作は時間がかかる場合がありますが、青色のボックス内の操作は高速であることに注意してください。

そして、transform:scaleを使用して

div {
  変換: スケール(0.5);
  遷移: 1 秒線形に変換します。
}
  
div:ホバー{
  変換: スケール(1.0);
}

プロセスは次のとおりです。

つまり、transform を使用すると、ブラウザは要素のビットマップを 1 回生成し、アニメーションの開始時にそれを GPU に送信して処理するだけで済みます。その後、ブラウザはレイアウト、描画、またはビットマップの送信操作を実行する必要がなくなります。したがって、ブラウザは GPU を最大限に活用して、さまざまな位置にビットマップをすばやく描画したり、回転やスケーリングを実行したりできます。

この理論を桁違いに検証するために、Chromeのタイムラインを開いてページFPSを表示した。

その中で、高さをアニメーション要素として使用する場合、切り替えプロセス中のFPSはわずか44です。毎秒60フレームが人間の目に最も適したインタラクションであることがわかっています。60未満の場合、人間の目はそれをはっきりと感じることができるため、フリーズが発生します。

レンダリングとペイントに費やされた時間は次のとおりです。

transform:scaleの使い方を見てみましょう

FPSは66に達し、レンダリングとペイントの時間は3分の1に短縮されました。

これまでのところ、問題は解決しました。数日後、Chrome アニメーションの「途切れ」問題を解決する方法についての記事を見ました。ハードウェア アクセラレーションをオンにすることでアニメーションを最適化できることがわかったので、もう一度試してみました。

webkit-transform: translate3d(0,0,0);
変換: translate3d(0,0,0);
-ms-transform: translate3d(0,0,0);
-o-変換: translate3d(0,0,0);
変換: translate3d(0,0,0);

驚くべきことが起こりました。FPS が 72 に達しました。

CSS3 アニメーションジャムの解決策の概要

アニメーションとして変換を使用するようにし、高さ、幅、余白、パディングなどの使用は避けてください。

要件がより高い場合は、ブラウザで GPU ハードウェア アクセラレーションを有効にすることができます。

以上がこの記事の全内容です。皆様の勉強のお役に立てれば幸いです。また、123WORDPRESS.COM を応援していただければ幸いです。

<<:  MySQL ジョイントインデックス(複合インデックス)の実装

>>:  Dockerコンテナ間の通信と外部ネットワーク通信の操作

推薦する

Vueはフィルターを使用して日付をフォーマットします

この記事では、フィルターを使用して日付をフォーマットするVueの具体的なコードを参考までに紹介します...

固定ボトムコンポーネントを実装した Vue の例

目次【効果】 【実施方法】 【効果】 【実施方法】 <テンプレート> <div i...

プロセスのすべての情報を表示するLinuxメソッドの例

サーバー上にタスク プロセスがあります。 ps -ef | grep task を使用して表示すると...

MySQL 8.0 アップグレード体験

目次序文1. まず、既存のバージョンの MySQL を完全にアンインストールします。 2. deb ...

MySQL テーブルにはどのくらいの量のデータを保存できますか?

プログラマーは MySQL を扱う機会が多く、毎日触れているとも言えますが、MySQL テーブルには...

Windows での MySQL 8.0.15 のインストールと設定方法のグラフィック チュートリアル

この記事では、参考までにMySQL 8.0.15のインストールと設定方法のグラフィックチュートリアル...

jsは徐々に増加するデジタルアニメーションを実現します

目次背景コンテナを固定し、数字を上にスクロールすることで、スクロールホイールと同様の効果を実現します...

Linux での rpm、yum、ソースコードの 3 つのインストール方法の詳細な紹介

第1章 ソースコードのインストールRPM パッケージは特定のシステムとプラットフォームに応じて指定さ...

React NativeプロジェクトでLottieアニメーションを使用する方法

Lottie は、Airbnb が開発した iOS、Android、React Native 向けの...

MySQL データベースのデータ テーブルの最適化、外部キーの分析、3 つのパラダイムの使用

この記事では、例を使用して、MySQL データベースのデータ テーブルの最適化、外部キーの使用、およ...

PHP スケジュールバックアップ MySQL および mysqldump 構文パラメータの詳細

まず、MySQL バックアップ コマンド mysqldump の一般的な操作例をいくつか紹介します。...

Intelli Idea で Tomcat 設定が見つからない問題の解決方法

2日前に新しい会社に入社しました。その会社ではIntelli Ideaを使っています。Eclipse...

正規表現に基づくあいまい文字列置換を実装するMySQLの方法の分析

この記事では、例を使用して、MySQL を使用して正規表現に基づくあいまい文字列置換を実装する方法を...

Docker5フル機能の港湾倉庫構築プロセス

Harbor は、Docker イメージを保存および配布するためのエンタープライズ レベルのレジスト...

MySQL 5.7.15 のインストールと設定方法のグラフィック チュートリアル (Windows)

MySQL をインストールする必要があるため、インストール手順を以下のように記録します。 自分なり...