なぜ詰まっているのでしょうか? 言及しなければならない前提があります。フロントエンド開発者は皆、ブラウザが単一のスレッドで実行されることを知っています。ただし、シングル スレッド、メイン スレッド、合成スレッドという概念を明確にする必要があります。 ブラウザは 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 ページをレンダリングするプロセスを指します。
つまり、メインスレッドはスクリプト、レンダーツリー、レイアウト、ペイントの 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 に達しました。
アニメーションとして変換を使用するようにし、高さ、幅、余白、パディングなどの使用は避けてください。 要件がより高い場合は、ブラウザで GPU ハードウェア アクセラレーションを有効にすることができます。 以上がこの記事の全内容です。皆様の勉強のお役に立てれば幸いです。また、123WORDPRESS.COM を応援していただければ幸いです。 |
<<: MySQL ジョイントインデックス(複合インデックス)の実装
>>: Dockerコンテナ間の通信と外部ネットワーク通信の操作
<br />以下は開発中に遭遇した問題と、そこから得た経験です。デバッグに時間がかかりま...
1. システム環境[root@localhost ホーム]# cat /etc/redhat-re...
次のコードを index.html などのデフォルトのホームページ ファイルとして保存し、ルート デ...
目次- 序文 - - JVM クラスローダー - 1. JVMクラスローダー2. クラスローダーのソ...
<本文> <div id="ルート"> <h2&...
Docker を使用すると、外部からコンテナにアクセスしたり、コンテナを相互接続したりすることで、ネ...
この記事は主に、以前のインストール方法を使用して MySQL 5.7.14 をインストールするときに...
目次序文1. 現在のgccバージョン2. gccをインストールする3.gmpのインストール4.MPF...
方法1: SET PASSWORDコマンドを使用する mysql -u ルート mysql> ...
この記事では、アコーディオンを実装するためのjQueryの具体的なコードを参考までに紹介します。具体...
目次1. 現在のシステムにMySQLがインストールされているかどうかを確認する2. インストールされ...
コンセプトインデックスにクエリ要件を満たすすべてのデータが含まれている場合、それはカバーリング イン...
目次デモ1フラグメントの作成スヴェルトコンポーネント状態を変更できるデモSvelte は長い間存在し...
1. <body background=画像ファイル名 bgcolor=color text=...
ターミナルやコンソールで作業しているときは、メールを読むなど、もっと重要な作業があるかもしれないので...