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コンテナ間の通信と外部ネットワーク通信の操作

推薦する

Centos7 で keepalived ログを別のパスに設定する方法の詳細な説明

Keepalived のインストール: cd <keepalived_sourcecode_p...

プロジェクトにおける CSS グリッドシステムの柔軟な使用方法の詳細な説明

序文CSS グリッドは通常、さまざまなフレームワークにバンドルされていますが、実際のビジネス ニーズ...

MySQL 8.0.15 インストール グラフィック チュートリアルとデータベースの基礎

MySQLソフトウェアのインストールとデータベースの基礎は参考用です。具体的な内容は次のとおりです。...

vuexプロジェクトにおけるログインステータス管理の実践プロセス

目次道具:ログインシナリオ:練習する:シナリオ1: 思考と実践シナリオ2: 思考と実践要約する道具:...

CSS を使用してデータ ホットスポット効果を実現する方法

効果は以下のとおりです。 分析する1. ここでは、点を囲む 3 つの円がズームアニメーションを実行し...

react setStateの詳細な説明

目次setState は同期ですか、それとも非同期ですか?カスタム合成イベントと React フック...

JavaScriptにおけるPromiseの使い方と注意点について(推奨)

1. 約束の説明Promise は、非同期操作の最終状態 (失敗または正常完了) とその結果の値を...

VMware Workstation 15 Pro インストール ガイド (初心者向け)

01. VMware Workstation Pro 15 のダウンロードダウンロード: VMwa...

MySQL Index Pushdown (ICP) とは何かを理解するための記事

目次1. はじめに2. 原則III. 実践3.1 インデックスプッシュダウンを使用しない3.2 イン...

vue-router を遅延ロードする 3 つの方法のまとめ

遅延読み込みを使用しない 'vue' から Vue をインポートします。 '...

html.cssオーバーフローの包括的な理解

html.cssオーバーフローの包括的な理解XML/HTML コードコンテンツをクリップボードにコピ...

dl、dt、dd はいつ使用するのが適切ですか?

dl:定義一覧定義リストdt:定義タイトルタイトルを定義するdd:定義説明定義の説明dt は情報のタ...

Docker を使用して Spring Boot をデプロイする方法

Docker テクノロジの開発により、マイクロサービスの実装にさらに便利な環境が提供されます。Doc...

VMware仮想マシンにLinux(CentOS)をインストールするための詳細な構成手順

CentOS7をダウンロード私がダウンロードしたイメージはCentOS-7-x86_64-DVD-1...

Apache Spark 2.0ジョブは完了するまでに長い時間がかかります

現象Apache Spark 2.x を使用すると、Spark ジョブがすべて完了しているにもかかわ...