フロントエンドパフォーマンスチェックリスト2021(PDF、Apple Pages、MS Word)

公開: 2022-03-10
簡単なまとめ↬2021を…速くしましょう! 毎年恒例のフロントエンドパフォーマンスチェックリスト(PDF、Apple Pages、MS Wordとして入手可能)。メトリックからツール、フロントエンドテクニックまで、今日のWebで高速なエクスペリエンスを作成するために知っておく必要のあるすべてが含まれています。 2016年から更新されています。ああ、メールマガジンで役立つフロントエンドのヒントを入手することもできます。

Webパフォーマンスはトリッキーな獣ですね。 パフォーマンスの観点から自分がどこに立っているかを実際にどのように知ることができますか?また、パフォーマンスのボトルネックは正確には何ですか? 高価なJavaScript、遅いWebフォントの配信、重い画像、または遅いレンダリングですか? ツリーシェーキング、スコープホイスト、コード分割、および交差オブザーバー、プログレッシブハイドレーション、クライアントヒント、HTTP / 3、サービスワーカー、およびエッジワーカーを使用したすべての派手な読み込みパターンで十分に最適化されましたか? そして、最も重要なことは、パフォーマンスの向上をどこから始めればよいのでしょうか。また、パフォーマンス文化を長期的に確立するにはどうすればよいのでしょうか。

当時、パフォーマンスは単なる後付けでした。 多くの場合、プロジェクトの最後まで延期され、縮小、連結、資産の最適化、およびサーバーのconfigファイルのいくつかの微調整に要約されます。 今振り返ると、物事はかなり大きく変わったようです。

パフォーマンスは技術的な問題だけではありません。アクセシビリティからユーザビリティ、検索エンジン最適化に至るまですべてに影響します。ワークフローに組み込む場合、設計上の決定はパフォーマンスへの影響によって通知される必要があります。 パフォーマンスは継続的に測定、監視、改善する必要があり、Webの複雑さが増すと、デバイス、ブラウザ、プロトコル、ネットワークタイプ、レイテンシによってデータが大幅に異なるため、メトリックの追跡が困難になる新しい課題が発生します( CDN、ISP、キャッシュ、プロキシ、ファイアウォール、ロードバランサー、サーバーはすべてパフォーマンスに影響します)。

したがって、プロジェクトの開始からWebサイトの最終リリースまで、パフォーマンスを向上させる際に留意しなければならないすべてのことの概要を作成した場合、それはどのようになりますか? 以下に、2021年の(できれば公平で客観的な)フロントエンドパフォーマンスチェックリストを示します。これは、応答時間が速く、ユーザーインタラクションがスムーズで、サイトがスムーズでないことを確認するために考慮する必要のある問題の最新の概要です。ユーザーの帯域幅を使い果たします。

目次

  • すべて別のページに
  • 準備:計画と指標
    パフォーマンス文化、コアWebバイタル、パフォーマンスプロファイル、CrUX、Lighthouse、FID、TTI、CLS、デバイス。
  • 現実的な目標の設定
    パフォーマンスバジェット、パフォーマンス目標、RAILフレームワーク、170KB / 30KBバジェット。
  • 環境の定義
    フレームワーク、ベースラインパフォーマンスコスト、Webpack、依存関係、CDN、フロントエンドアーキテクチャ、CSR、SSR、CSR + SSR、静的レンダリング、事前レンダリング、PRPLパターンの選択。
  • 資産の最適化
    Brotli、AVIF、WebP、レスポンシブ画像、AV1、アダプティブメディアローディング、ビデオ圧縮、Webフォント、Googleフォント。
  • ビルドの最適化
    JavaScriptモジュール、モジュール/モジュールなしパターン、ツリーシェイク、コード分割、スコープホイスト、Webpack、ディファレンシャルサービング、Webワーカー、WebAssembly、JavaScriptバンドル、React、SPA、部分的なハイドレーション、相互作用のインポート、サードパーティ、キャッシュ。
  • 配信の最適化
    遅延読み込み、交差オブザーバー、レンダリングとデコードの延期、重要なCSS、ストリーミング、リソースヒント、レイアウトシフト、サービスワーカー。
  • ネットワーキング、HTTP / 2、HTTP / 3
    OCSPステープリング、EV / DV証明書、パッケージング、IPv6、QUIC、HTTP / 3。
  • テストとモニタリング
    監査ワークフロー、プロキシブラウザ、404ページ、GDPR Cookie同意プロンプト、パフォーマンス診断CSS、アクセシビリティ。
  • クイックウィン
  • チェックリストをダウンロードする(PDF、Apple Pages、MS Word)
  • オフウィーゴー!

(チェックリストPDF(166 KB)をダウンロードするか、編集可能なApple Pagesファイル(275 KB)または.docxファイル(151 KB)をダウンロードすることもできます。

準備:計画と指標

マイクロ最適化はパフォーマンスを軌道に乗せるのに最適ですが、明確に定義された目標を念頭に置くことが重要です。これは、プロセス全体で行われる決定に影響を与える測定可能な目標です。 いくつかの異なるモデルがあり、以下で説明するモデルはかなり意見が分かれています。早い段階で独自の優先順位を設定してください。

  1. パフォーマンス文化を確立します。
    多くの組織では、フロントエンド開発者は、根本的な一般的な問題が何であるか、およびそれらを修正するためにどの戦略を使用する必要があるかを正確に知っています。 ただし、パフォーマンスカルチャーの確立された承認がない限り、各決定は部門の戦場になり、組織をサイロに分割します。 ビジネスの利害関係者の賛同が必要であり、それを取得するには、ケーススタディ、または速度(特に、後で詳しく説明するコアWebバイタル)がメトリックと主要業績評価指標にどのように役立つかについての概念実証を確立する必要があります。 ( KPI )彼らは気にします。

    たとえば、パフォーマンスをより具体的にするために、コンバージョン率とアプリケーションの負荷までの時間の相関関係、およびレンダリングパフォーマンスを示すことで、収益パフォーマンスへの影響を明らかにすることができます。 または、検索ボットのクロール率(PDF、27〜50ページ)。

    開発/設計チームとビジネス/マーケティングチームの間に強力な連携がなければ、パフォーマンスは長期的に維持されません。 カスタマーサービスとセールスチームに寄せられる一般的な苦情を調査し​​、高いバウンス率とコンバージョンの低下に関する分析を調査します。 パフォーマンスの向上がこれらの一般的な問題のいくつかを軽減するのにどのように役立つかを探ります。 話している利害関係者のグループに応じて、議論を調整します。

    モバイルとデスクトップの両方で(たとえば、Google Analyticsを使用して)パフォーマンス実験を実行し、結果を測定します。 これは、実際のデータを使用して会社に合わせたケーススタディを構築するのに役立ちます。 さらに、WPO Statsで公開されたケーススタディと実験のデータを使用すると、パフォーマンスが重要である理由、およびパフォーマンスがユーザーエクスペリエンスとビジネスメトリックにどのような影響を与えるかについて、ビジネスの感度を高めるのに役立ちます。 ただし、パフォーマンスだけが重要であると述べるだけでは不十分です。測定可能で追跡可能な目標を設定し、それらを長期にわたって観察する必要もあります。

    そこに着く方法? 長期的なパフォーマンスの構築に関する彼女の講演で、Allison McKnightは、Etsyでのパフォーマンス文化の確立にどのように貢献したかについての包括的なケーススタディを共有しています(スライド)。 最近では、タミー・エヴァーツが、小規模組織と大規模組織の両方で非常に効果的なパフォーマンスチームの習慣について話しました。

    組織でこれらの会話をしている間、UXがさまざまなエクスペリエンスであるように、Webパフォーマンスは分散であることに留意することが重要です。 Karolina Szczurが指摘したように、「単一の数値が目指すべき評価を提供できると期待することは、欠陥のある仮定です」。 したがって、パフォーマンスの目標は、きめ細かく、追跡可能で、具体的である必要があります。

モバイルでは、セッションごとに、読み込み時間が速いユーザーは平均より17%多くの収益をもたらします
モバイルでは、セッションごとに、読み込み時間が速いユーザーは平均より17%多くの収益をもたらします。 (Addy OsmaniによるWebパフォーマンスの影響)
単一の数値が目指すべき評価を提供できることを期待することは、欠陥のある仮定です
単一の数値が目指すべき評価を提供できると期待することは、欠陥のある仮定です。 (画像クレジット:パフォーマンスはKarolina Czczurによる配布です)
  1. 目標:最速の競合他社よりも少なくとも20%速くなります。
    心理学の調査によると、自分のWebサイトが競合他社のWebサイトよりも高速であるとユーザーに感じてもらいたい場合は、少なくとも20%高速である必要があります。 主な競合他社を調査し、モバイルとデスクトップでのパフォーマンスに関する指標を収集し、競合他社を上回るのに役立つしきい値を設定します。 ただし、正確な結果と目標を得るには、まず分析を調べて、ユーザーのエクスペリエンスの全体像を把握するようにしてください。 次に、90パーセンタイルのテストの経験を模倣できます。

    競合他社のパフォーマンスの第一印象を良くするために、Chrome UXレポート( CrUX 、既製のRUMデータセット、Ilya Grigorikによるビデオ紹介、Rick Viscomiによる詳細ガイド)、またはRUM監視ツールであるTreoを使用できます。 ChromeUXレポートを利用しています。 データはChromeブラウザのユーザーから収集されるため、レポートはChrome固有のものになりますが、さまざまな訪問者にパフォーマンス、最も重要なのはCore WebVitalsスコアをかなり完全に分散させることができます。 新しいCrUXデータセットは、毎月第2火曜日にリリースされることに注意してください。

    または、次を使用することもできます。

    • AddyOsmaniのChromeUXレポート比較ツール、
    • スピードスコアカード(収益への影響の見積もりも提供します)、
    • 実際のユーザーエクスペリエンステストの比較または
    • SiteSpeed CI(合成テストに基づく)。

    :Page SpeedInsightsまたはPageSpeed Insights APIを使用している場合(非推奨ではありません!)、集計だけでなく、特定のページのCrUXパフォーマンスデータを取得できます。 このデータは、「ランディングページ」や「商品リスト」などのアセットのパフォーマンス目標を設定するのに非常に役立ちます。 また、CIを使用して予算をテストしている場合、ターゲットの設定にCrUXを使用した場合は、テストした環境がCrUXと一致することを確認する必要があります( Patrick Meenanに感謝します)。

    速度の優先順位付けの背後にある理由を示すために何らかの支援が必要な場合、またはパフォーマンスの低下に伴うコンバージョン率の低下またはバウンス率の増加を視覚化したい場合、あるいは組織内のRUMソリューションを提唱する必要がある場合はSergey Chernyshevは、UX Speed Calculatorを構築しました。これは、データをシミュレートして視覚化し、ポイントを推進するのに役立つオープンソースツールです。

    CrUXは、Google Chromeユーザーから収集されたトラフィックを使用して、時間の経過に伴うパフォーマンス分布の概要を生成します
    CrUXは、Google Chromeユーザーから収集されたトラフィックを使用して、時間の経過に伴うパフォーマンス分布の概要を生成します。 ChromeUXダッシュボードで独自に作成できます。 (大プレビュー)
    ポイントを推進するためにパフォーマンスを主張する必要がある場合:UX Speed Calculatorは、実際のデータに基づいて、バウンス率、コンバージョン、総収益に対するパフォーマンスの影響を視覚化します
    ポイントを推進するためにパフォーマンスを主張する必要がある場合:UX Speed Calculatorは、実際のデータに基づいて、バウンス率、コンバージョン、総収益に対するパフォーマンスの影響を視覚化します。 (大プレビュー)

    CrUXからのデータを、速度低下、盲点、非効率性が存在する場所で、競合他社やプロジェクトのために、すでに迅速に解決する必要のある他のデータと組み合わせて、もう少し深く掘り下げたい場合があります。 彼の仕事では、ハリー・ロバーツはサイトスピード地形スプレッドシートを使用しており、これを使用して主要なページタイプごとにパフォーマンスを分類し、それらの間でさまざまな主要なメトリックがどのようにあるかを追跡しています。 スプレッドシートは、Googleスプレッドシート、Excel、OpenOfficeドキュメント、またはCSVとしてダウンロードできます。

    サイトの主要なページに表示される主要なメトリックを使用したサイト速度の地形
    サイトの主要なページに表される主要なメトリックを使用したサイト速度の地形。 (大プレビュー)

    また、最後までやりたい場合は、サイトのすべてのページで(Lightouse Paradeを介して)Lighthouseパフォーマンス監査を実行し、出力をCSVとして保存できます。 これは、競合他社のどの特定のページ(またはページの種類)のパフォーマンスが悪いか良いか、そして何に集中したいかを特定するのに役立ちます。 (自分のサイトの場合は、分析エンドポイントにデータを送信する方がおそらく良いでしょう!)

    Lighthouse Paradeを使用すると、サイトのすべてのページでLighthouseパフォーマンス監査を実行し、出力をCSVとして保存できます。
    Lighthouse Paradeを使用すると、サイトのすべてのページでLighthouseパフォーマンス監査を実行し、出力をCSVとして保存できます。 (大プレビュー)

    データを収集し、スプレッドシートを設定し、20%削減し、この方法で目標(パフォーマンス予算)を設定します。 これで、テストするための測定可能なものができました。 予算を念頭に置いて、対話するまでの時間を短縮するために最小限のペイロードだけを出荷しようとしている場合は、合理的な道を進んでいます。

    始めるためのリソースが必要ですか?

    • Addy Osmaniは、パフォーマンスの予算編成を開始する方法、新機能の影響を定量化する方法、および予算を超過した場合にどこから開始するかについて、非常に詳細な記事を書いています。
    • パフォーマンスバジェットを使用して設計にアプローチする方法に関するLaraHoganのガイドは、設計者に役立つ指針を提供します。
    • ハリーロバーツは、リクエストマップを使用して、パフォーマンスに対するサードパーティのスクリプトの影響を表示するGoogleスプレッドシートの設定に関するガイドを公開しました。
    • JonathanFieldingのPerformanceBudget Calculator、Katie Hempeniusのperf-budget-calculator、およびBrowser Caloriesは、予算の作成に役立ちます(Karolina Szczurの頭を上げてくれてありがとう)。
    • 多くの企業では、パフォーマンスの予算は野心的なものではなく、実際的なものである必要があり、特定のポイントを超えないようにするための保持の兆候として機能します。 その場合、過去2週間で最悪のデータポイントをしきい値として選択し、そこから取得することができます。 パフォーマンスバジェットは、それを達成するための戦略を実践的に示しています。
    • また、ビルドサイズを報告するグラフを使用してダッシュボードを設定することにより、パフォーマンスバジェットと現在のパフォーマンスの両方を表示します。 それを実現できるツールはたくさんあります。SiteSpeed.ioダッシュボード(オープンソース)、SpeedCurve、Calibreはそのほんの一部であり、perf.rocksでさらに多くのツールを見つけることができます。
    ブラウザのカロリーは、パフォーマンスの予算を設定し、ページがこれらの数値を超えているかどうかを測定するのに役立ちます。
    ブラウザのカロリーは、パフォーマンスの予算を設定し、ページがこれらの数値を超えているかどうかを測定するのに役立ちます。 (大プレビュー)

    予算を設定したら、Webpack Performance HintsとBundlesize、Lighthouse CI、PWMetrics、またはSitespeed CIを使用してビルドプロセスに組み込み、プルリクエストに予算を適用し、PRコメントでスコア履歴を提供します。

    チーム全体にパフォーマンスバジェットを公開するには、Lightwalletを介してLighthouseにパフォーマンスバジェットを統合するか、LHCIアクションを使用してGithubアクションをすばやく統合します。 また、カスタムが必要な場合は、エンドポイントのAPIであるwebpagetest-charts-apiを使用して、WebPagetestの結果からグラフを作成できます。

    ただし、パフォーマンスの認識は、パフォーマンスの予算だけから得られるべきではありません。 Pinterestと同じように、依存関係が多く、バンドルを肥大化させることがわかっているファイルやディレクトリからのインポートを禁止するカスタムeslintルールを作成できます。 チーム全体で共有できる「安全な」パッケージのリストを設定します。

    また、ビジネスにとって最も有益な重要な顧客タスクについて考えてください。 重要なアクションの許容可能な時間しきい値を調査、議論、定義し、組織全体が承認した「UX対応」のユーザータイミングマークを確立します。 多くの場合、ユーザージャーニーは多くの異なる部門の作業に影響を与えるため、許容可能なタイミングに関する調整は、今後のパフォーマンスに関する議論をサポートまたは防止するのに役立ちます。 追加されたリソースと機能の追加コストが表示され、理解されていることを確認してください。

    構築中の製品の新機能からリファクタリング、新しいグローバルオーディエンスへのリーチに至るまで、パフォーマンスへの取り組みを他の技術イニシアチブと連携させます。 したがって、さらなる開発についての会話が行われるたびに、パフォーマンスもその会話の一部になります。 コードベースが新しい場合、またはリファクタリングされている場合は、パフォーマンスの目標を達成するのがはるかに簡単です。

    また、Patrick Meenanが示唆したように、設計プロセス中にロードシーケンスとトレードオフを計画することは価値があります。 どの部分がより重要であるかを早期に優先し、それらが表示される順序を定義すると、何が遅れるかもわかります。 理想的には、その順序はCSSとJavaScriptのインポートの順序も反映するため、ビルドプロセス中のそれらの処理が容易になります。 また、ページがロードされている間(たとえば、Webフォントがまだロードされていないとき)の「中間」状態でのビジュアルエクスペリエンスを検討してください。

    組織で強力なパフォーマンス文化を確立したら、時間の経過とともに優先順位を維持するために、以前の自分よりも20%速くなることを目指します( Guy Podjarnyに感謝します)。 ただし、ボットのトラフィックと季節性の影響に加えて、顧客のさまざまなタイプと使用行動(Tobias Baldaufはケイデンスとコホートと呼んでいます)を考慮してください。

    計画、計画、計画。 早い段階でいくつかの迅速な「手に負えない果物」の最適化に取り掛かるのは魅力的かもしれません—そしてそれは迅速な勝利のための良い戦略かもしれません—しかし、現実的な会社を計画して設定することなしにパフォーマンスを優先することは非常に難しいでしょう-調整されたパフォーマンス目標。

Treo Sitesは、実際のデータに基づいた競合分析を提供します
Treoは、実際のデータに基づいた競合分析を提供します。 (大プレビュー)
2020年初頭にLighthousev6に導入された新しい指標
新しいメトリックは2020年の初めにLighthousev6に上陸しました。(大規模なプレビュー)
  1. 適切な指標を選択してください。
    すべてのメトリックが等しく重要であるわけではありません。 アプリケーションにとって最も重要なメトリックを調べます。通常、インターフェイスの最も重要なピクセルのレンダリングを開始できる速度と、レンダリングされたピクセルに入力応答性を提供できる速度によって定義されます。 この知識は、継続的な取り組みのための最良の最適化目標を提供します。 結局のところ、エクスペリエンスを定義するのはロードイベントやサーバーの応答時間ではなく、インターフェイスいかにスッキリしているのかという認識です。

    どういう意味ですか? (たとえば、 onLoadDOMContentLoadedのタイミングを介して)ページ全体の読み込み時間に焦点を合わせるのではなく、顧客が認識しているようにページの読み込みを優先します。 これは、わずかに異なる一連のメトリックに焦点を当てることを意味します。 実際、適切なメトリックを選択することは、明らかな勝者がいないプロセスです。

    TimKadlecの調査と彼の講演でのMarcosIglesiasのメモに基づいて、従来のメトリックはいくつかのセットにグループ化できます。 通常、パフォーマンスの全体像を把握するには、それらすべてが必要です。特定のケースでは、それらの一部が他よりも重要になります。

    • 数量ベースのメトリックは、リクエストの数、重み、およびパフォーマンススコアを測定します。 アラームを鳴らしたり、時間の経過とともに変化を監視したりするのには適していますが、ユーザーエクスペリエンスを理解するのにはあまり適していません。
    • マイルストーンメトリックは、読み込みプロセスの存続期間中の状態を使用します。たとえば、最初のバイトまでの時間やインタラクティブまでの時間などです。 ユーザーエクスペリエンスとモニタリングを説明するのには適していますが、マイルストーン間で何が起こっているのかを知るのにはあまり適していません。
    • レンダリングメトリックは、コンテンツのレンダリング速度の見積もりを提供します(たとえば、レンダリング開始時間、速度インデックス)。 レンダリングパフォーマンスの測定と調整には適していますが、重要なコンテンツが表示されて操作できるタイミングの測定にはあまり適していません。
    • カスタムメトリックは、ユーザーの特定のカスタムイベントを測定します。たとえば、Twitterの最初のツイートまでの時間やPinterestのPinnerWaitTimeなどです。 ユーザーエクスペリエンスを正確に説明するのには適していますが、指標をスケーリングしたり、競合他社と比較したりするのにはあまり適していません。

    全体像を完成させるために、私たちは通常、これらすべてのグループの中で有用な指標を探します。 通常、最も具体的で関連性のあるものは次のとおりです。

    • インタラクティブまでの時間(TTI)
      レイアウトが安定し、主要なWebフォントが表示され、ユーザー入力を処理するのに十分なメインスレッドが利用可能になるポイント(基本的には、ユーザーがUIを操作できる時間マーク)。 ユーザーがラグなしでサイトを使用するためにどれだけの待機を経験する必要があるかを理解するための主要なメトリック。 Boris Schapiraは、TTIを確実に測定する方法に関する詳細な投稿を書いています。
    • First Input Delay (FID) 、または入力応答性
      ユーザーが最初にサイトを操作してから、ブラウザーが実際にその操作に応答できるようになるまでの時間。 TTIを非常によく補完し、画像の欠落している部分、つまりユーザーが実際にサイトを操作したときに何が起こるかを説明します。 RUMメトリックとしてのみ意図されています。 ブラウザでFIDを測定するためのJavaScriptライブラリがあります。
    • 最大のコンテンツフルペイント(LCP)
      ページの重要なコンテンツが読み込まれた可能性が高い、ページの読み込みタイムラインのポイントをマークします。 ページの最も重要な要素は、ユーザーのビューポートに表示される最大の要素であると想定されています。 要素が折り目の上と下の両方にレンダリングされる場合、表示されている部分のみが関連性があると見なされます。
    • 合計ブロッキング時間( TBT
      ページが確実にインタラクティブになる前に、ページがどの程度非インタラクティブであるかを定量化するのに役立つメトリック(つまり、メインスレッドに50ミリ秒を超えるタスク(長いタスク)が少なくとも5秒間実行されていない)。 このメトリックは、最初のペイントから、入力の応答性を妨げるのに十分な時間メインスレッドがブロックされたInteractiveまでの時間(TTI)までの合計時間を測定します。 したがって、低いTBTが良好なパフォーマンスの良い指標であることは不思議ではありません。 (ありがとう、Artem、Phil)
    • 累積レイアウトシフト( CLS
      このメトリックは、ユーザーがサイトにアクセスするときに予期しないレイアウトシフトリフロー)を経験する頻度を強調しています。 不安定な要素と、それらが全体的なエクスペリエンスに与える影響を調べます。 スコアが低いほど良いです。
    • スピードインデックス
      ページコンテンツが視覚的に入力される速度を測定します。 スコアが低いほど良いです。 速度指数スコアは視覚的な進行速度に基づいて計算されますが、これは単なる計算値です。 また、ビューポートサイズにも影響されるため、ターゲットオーディエンスに一致するさまざまなテスト構成を定義する必要があります。 LCPがより適切なメトリックになるにつれて、重要性が低下していることに注意してください( Boris、Artemに感謝します)。
    • 費やしたCPU時間
      メインスレッドがブロックされ、ペイント、レンダリング、スクリプト作成、および読み込みに取り組んでいる頻度期間を示すメトリック。 CPU時間が長いことは、ユーザーエクスペリエンスが不安定であることを明確に示しています。つまり、ユーザーがアクションと応答の間に顕著な遅延を経験した場合です。 WebPageTestを使用すると、[Chrome]タブで[Capture Dev Tools Timeline]を選択して、WebPageTestを使用する任意のデバイスで実行されるメインスレッドの内訳を表示できます。
    • コンポーネントレベルのCPUコスト
      費やしたCPU時間と同様に、Stoyan Stefanovによって提案されたこのメトリックは、JavaScriptがCPUに与える影響を調査します。 アイデアは、コンポーネントごとのCPU命令数を使用して、全体的なエクスペリエンスへの影響を個別に理解することです。 PuppeteerとChromeを使用して実装できます。
    • FrustrationIndex
      上記の多くのメトリクスは特定のイベントがいつ発生するかを説明していますが、Tim VereeckeのFrustrationIndexは、メトリクスを個別に見るのではなく、メトリクス間のギャップを調べます。 タイトルが表示され、最初のコンテンツが表示され、視覚的に準備ができており、ページが準備ができているなど、エンドユーザーが認識した主要なマイルストーンを確認し、ページの読み込み中のフラストレーションのレベルを示すスコアを計算します。 ギャップが大きいほど、ユーザーがイライラする可能性が高くなります。 ユーザーエクスペリエンスに適したKPIになる可能性があります。 Timは、FrustrationIndexとその仕組みに関する詳細な投稿を公開しています。
    • 広告の重量への影響
      あなたのサイトが広告によって生み出された収入に依存しているなら、広告関連のコードの重みを追跡することは役に立ちます。 Paddy Gantiのスクリプトは2つのURL(1つは通常のURL、もう1つは広告をブロックする)を作成し、WebPageTestを介してビデオ比較の生成を促し、デルタを報告します。
    • 偏差メトリック
      ウィキペディアのエンジニアが指摘しているように、結果にどの程度の分散が存在するかというデータは、機器の信頼性、および偏差とアウトラーにどれだけ注意を払う必要があるかを示します。 大きな変動は、セットアップで必要な調整の指標です。 また、サードパーティのスクリプトが大幅な変動を引き起こしているなどの理由で、特定のページを確実に測定することがより困難であるかどうかを理解するのにも役立ちます。 また、新しいブラウザバージョンが公開されたときのパフォーマンスの向上を理解するために、ブラウザのバージョンを追跡することもお勧めします。
    • カスタムメトリック
      カスタムメトリックは、ビジネスニーズとカスタマーエクスペリエンスによって定義されます。 重要なピクセル、重要なスクリプト、必要なCSS、および関連するアセットを特定し、それらがユーザーに配信されるまでの時間を測定する必要があります。 その場合は、Hero Rendering Timesを監視するか、Performance APIを使用して、ビジネスにとって重要なイベントの特定のタイムスタンプをマークできます。 また、テストの最後に任意のJavaScriptを実行することで、WebPagetestを使用してカスタムメトリックを収集できます。

    First Meaningful Paint (FMP)は、上記の概要には表示されないことに注意してください。 これは、サーバーがデータを出力する速度についての洞察を提供するために使用されていました。 長いFMPは通常、JavaScriptがメインスレッドをブロックしていることを示していますが、バックエンド/サーバーの問題にも関連している可能性があります。 ただし、このメトリックは、約20%のケースで正確ではないように見えるため、最近非推奨になりました。 これは、より信頼性が高く、推論が容易なLCPに効果的に置き換えられました。 Lighthouseではサポートされなくなりました。 安全なページにいることを確認するために、最新のユーザー中心のパフォーマンスメトリックと推奨事項を再確認してください(ありがとう、Patrick Meenan )。

    Steve Soudersは、これらの指標の多くについて詳細に説明しています。 Time-To-Interactiveは、いわゆるラボ環境で自動監査を実行することによって測定されますが、First Input Delayは実際のユーザーエクスペリエンスを表し、実際のユーザーは顕著な遅延を経験していることに注意してください。 一般に、常に両方を測定して追跡することをお勧めします。

    アプリケーションのコンテキストに応じて、推奨されるメトリックは異なる場合があります。たとえば、Netflix TV UIの場合、キー入力の応答性、メモリ使用量、TTIがより重要であり、Wikipediaの場合、最初/最後の視覚的変更とCPU時間の消費メトリックがより重要です。

    :FIDとTTIはどちらも、スクロール動作を考慮していません。 スクロールはメインスレッドから外れているため、独立して発生する可能性があります。そのため、多くのコンテンツ消費サイトでは、これらのメトリックはそれほど重要ではない可能性があります(ありがとう、Patrick! )。

ユーザー中心のパフォーマンスメトリクスは、実際のユーザーエクスペリエンスへのより良い洞察を提供します
ユーザー中心のパフォーマンスメトリックは、実際のユーザーエクスペリエンスに対するより良い洞察を提供します。 First Input Delay(FID)は、まさにそれを達成しようとする新しいメトリックです。 (大プレビュー)
oveviewの新しいコアWebバイタル、LCP <2.5s、FID <100ms、CLS <0.1
oveviewの新しいコアWebバイタル、LCP <2.5s、FID <100ms、CLS <0.1。 (コアWebバイタル、Addy Osmani経由)
  1. Core WebVitalsを測定して最適化します
    長い間、パフォーマンスメトリックは非常に技術的であり、サーバーの応答速度とブラウザの読み込み速度のエンジニアリングビューに焦点を当てていました。 指標は何年にもわたって変化しており、サーバーのタイミングではなく、実際のユーザーエクスペリエンスをキャプチャする方法を見つけようとしています。 2020年5月、GoogleはCore Web Vitalsを発表しました。これは、ユーザーに焦点を当てた新しいパフォーマンス指標のセットであり、それぞれがユーザーエクスペリエンスの異なる側面を表しています。

    それぞれについて、Googleは許容可能な速度目標の範囲を推奨しています。 この評価に合格するには、すべてのページビューの少なくとも75%が適切な範囲を超えている必要があります。 これらの指標はすぐに注目を集め、2021年5月にコアウェブバイタルがGoogle検索のランキングシグナルになり(ページエクスペリエンスランキングアルゴリズムの更新)、多くの企業がパフォーマンススコアに注目しています。

    これらの指標を念頭に置いてエクスペリエンスを最適化するための便利なテクニックとツールとともに、各コアWebバイタルを1つずつ分解してみましょう。 (この記事の一般的なアドバイスに従うことで、Core Web Vitalsのスコアが向上することに注意してください。)

    • 最大のコンテンツフルペイントLCP )<2.5秒。
      ページの読み込みを測定し、ビューポート内に表示される最大の画像またはテキストブロックのレンダリング時間を報告します。 したがって、LCPは、サーバーの応答時間の遅延、CSSのブロック、実行中のJavaScript(ファーストパーティまたはサードパーティ)、Webフォントの読み込み、高価なレンダリングまたはペイント操作、遅延など、重要な情報のレンダリングを延期するすべての影響を受けます。 -ロードされた画像、スケルトン画面、またはクライアント側のレンダリング。

      良い経験のために、LCPはページが最初にロードを開始したときから2.5秒以内に発生するはずです。 つまり、ページの最初に表示される部分をできるだけ早くレンダリングする必要があります。 そのためには、テンプレートごとに調整された重要なCSSが必要になり、 <head>の順序を調整し、重要なアセットをプリフェッチします(後で説明します)。

      LCPスコアが低い主な理由は、通常、画像です。 十分に最適化されたサーバーでホストされ、クライアント側のレンダリングなしですべて静的で、専用の画像CDNからの画像を使用して、Fast 3Gで2.5秒未満でLCPを配信するには、理論上の最大画像サイズが約144KBにすぎないことを意味します。 そのため、レスポンシブ画像が重要であり、重要な画像を早期にプリロードします( preloadを使用)。

      クイックヒント:ページ上でLCPと見なされるものを見つけるには、DevToolsで、パフォーマンスパネルの[タイミング]の下にあるLCPバッジにカーソルを合わせることができます(ありがとう、Tim Kadlec !)。

    • 最初の入力遅延FID )<100ms。
      UIの応答性を測定します。つまり、ブラウザがタップやクリックなどの個別のユーザー入力イベントに反応する前に、他のタスクでビジー状態だった時間を測定します。 これは、特にページのロード中にメインスレッドがビジーであることに起因する遅延をキャプチャするように設計されています。

      目標は、すべてのインタラクションで50〜100ミリ秒以内にとどまることです。 そこに到達するには、長いタスクを特定し(メインスレッドを50ミリ秒以上ブロックする)、それらを分割し、バンドルを複数のチャンクにコード分割し、JavaScriptの実行時間を短縮し、データフェッチを最適化し、サードパーティのスクリプト実行を延期する必要があります、JavaScriptをWebワーカーのバックグラウンドスレッドに移動し、プログレッシブハイドレーションを使用してSPAのリハイドレーションコストを削減します。

      クイックヒント:一般に、より良いFIDスコアを取得するための信頼できる戦略は、大きなバンドルを小さなバンドルに分割し、ユーザーが必要なときに必要なものを提供することでメインスレッドの作業を最小限に抑えることです。これにより、ユーザーの操作が遅れることはありません。 。 これについては、以下で詳しく説明します。

    • 累積レイアウトシフトCLS )<0.1。
      UIの視覚的な安定性を測定して、スムーズで自然な相互作用を保証します。つまり、ページの存続期間中に発生するすべての予期しないレイアウトシフトのすべての個々のレイアウトシフトスコアの合計です。 個々のレイアウトシフトは、すでに表示されている要素がページ上の位置を変更するたびに発生します。 コンテンツのサイズと移動距離に基づいてスコアが付けられます。

      したがって、シフトが表示されるたびに(たとえば、フォールバックフォントとWebフォントのフォントメトリックが異なる場合、広告、埋め込み、iframeが遅れる場合、画像/動画のサイズが予約されていない場合、CSSが遅れて再描画を強制する場合、または変更が挿入される場合)後期JavaScript—CLSスコアに影響を与えます。 優れたエクスペリエンスの推奨値は、CLS <0.1です。

    Core Web Vitalsは、予測可能な年間サイクルで、時間の経過とともに進化することになっていることに注意してください。 初年度のアップデートでは、First ContentfulPaintがCoreWeb Vitalsに昇格し、FIDしきい値が低くなり、シングルページアプリケーションのサポートが向上することを期待している可能性があります。 また、セキュリティ、プライバシー、およびアクセシビリティ(!)の考慮事項とともに、負荷が増加した後のユーザー入力への応答が表示される場合があります。

    Related to Core Web Vitals, there are plenty of useful resources and articles that are worth looking into:

    • Web Vitals Leaderboard allows you to compare your scores against competition on mobile, tablet, desktop, and on 3G and 4G.
    • Core SERP Vitals, a Chrome extension that shows the Core Web Vitals from CrUX in the Google Search Results.
    • Layout Shift GIF Generator that visualizes CLS with a simple GIF (also available from the command line).
    • web-vitals library can collect and send Core Web Vitals to Google Analytics, Google Tag Manager or any other analytics endpoint.
    • Analyzing Web Vitals with WebPageTest, in which Patrick Meenan explores how WebPageTest exposes data about Core Web Vitals.
    • Optimizing with Core Web Vitals, a 50-min video with Addy Osmani, in which he highlights how to improve Core Web Vitals in an eCommerce case-study.
    • Cumulative Layout Shift in Practice and Cumulative Layout Shift in the Real World are comprehensive articles by Nic Jansma, which cover pretty much everything about CLS and how it correlates with key metrics such as Bounce Rate, Session Time or Rage Clicks.
    • What Forces Reflow, with an overview of properties or methods, when requested/called in JavaScript, that will trigger the browser to synchronously calculate the style and layout.
    • CSS Triggers shows which CSS properties trigger Layout, Paint and Composite.
    • Fixing Layout Instability is a walkthrough of using WebPageTest to identify and fix layout instability issues.
    • Cumulative Layout Shift, The Layout Instability Metric, another very detailed guide by Boris Schapira on CLS, how it's calcualted, how to measure and how to optimize for it.
    • How To Improve Core Web Vitals, a detailed guide by Simon Hearne on each of the metrics (including other Web Vitals, such as FCP, TTI, TBT), when they occur and how they are measured.

    So, are Core Web Vitals the ultimate metrics to follow ? 完全ではありません。 They are indeed exposed in most RUM solutions and platforms already, including Cloudflare, Treo, SpeedCurve, Calibre, WebPageTest (in the filmstrip view already), Newrelic, Shopify, Next.js, all Google tools (PageSpeed Insights, Lighthouse + CI, Search Console etc.) and many others.

    However, as Katie Sylor-Miller explains, some of the main problems with Core Web Vitals are the lack of cross-browser support, we don't really measure the full lifecycle of a user's experience, plus it's difficult to correlate changes in FID and CLS with business outcomes.

    As we should be expecting Core Web Vitals to evolve, it seems only reasonable to always combine Web Vitals with your custom-tailored metrics to get a better understanding of where you stand in terms of performance.

  2. Gather data on a device representative of your audience.
    To gather accurate data, we need to thoroughly choose devices to test on. In most companies, that means looking into analytics and creating user profiles based on most common device types. Yet often, analytics alone doesn't provide a complete picture. A significant portion of the target audience might be abandoning the site (and not returning back) just because their experience is too slow, and their devices are unlikely to show up as the most popular devices in analytics for that reason. So, additionally conducting research on common devices in your target group might be a good idea.

    Globally in 2020, according to the IDC, 84.8% of all shipped mobile phones are Android devices. An average consumer upgrades their phone every 2 years, and in the US phone replacement cycle is 33 months. Average bestselling phones around the world will cost under $200.

    A representative device, then, is an Android device that is at least 24 months old , costing $200 or less, running on slow 3G, 400ms RTT and 400kbps transfer, just to be slightly more pessimistic. This might be very different for your company, of course, but that's a close enough approximation of a majority of customers out there. In fact, it might be a good idea to look into current Amazon Best Sellers for your target market. ( Thanks to Tim Kadlec, Henri Helvetica and Alex Russell for the pointers! ).

    When building a new site or app, always check current Amazon Best Sellers for your target market first
    When building a new site or app, always check current Amazon Best Sellers for your target market first. (大プレビュー)

    What test devices to choose then? The ones that fit well with the profile outlined above. It's a good option to choose a slightly older Moto G4/G5 Plus, a mid-range Samsung device (Galaxy A50, S8), a good middle-of-the-road device like a Nexus 5X, Xiaomi Mi A3 or Xiaomi Redmi Note 7 and a slow device like Alcatel 1X or Cubot X19, perhaps in an open device lab. For testing on slower thermal-throttled devices, you could also get a Nexus 4, which costs just around $100.

    Also, check the chipsets used in each device and do not over-represent one chipset : a few generations of Snapdragon and Apple as well as low-end Rockchip, Mediatek would be enough (thanks, Patrick!) .

    If you don't have a device at hand, emulate mobile experience on desktop by testing on a throttled 3G network (eg 300ms RTT, 1.6 Mbps down, 0.8 Mbps up) with a throttled CPU (5× slowdown). Eventually switch over to regular 3G, slow 4G (eg 170ms RTT, 9 Mbps down, 9Mbps up), and Wi-Fi. To make the performance impact more visible, you could even introduce 2G Tuesdays or set up a throttled 3G/4G network in your office for faster testing.

    Keep in mind that on a mobile device, we should be expecting a 4×–5× slowdown compared to desktop machines. Mobile devices have different GPUs, CPU, memory and different battery characteristics. That's why it's important to have a good profile of an average device and always test on such a device.

  3. Introducing the slowest day of the week
    Introducing the slowest day of the week. Facebook has introduced 2G Tuesdays to increase visibility and sensitivity of slow connections. ( Image source)

    Luckily, there are many great options that help you automate the collection of data and measure how your website performs over time according to these metrics. Keep in mind that a good performance picture covers a set of performance metrics, lab data and field data:

    • Synthetic testing tools collect lab data in a reproducible environment with predefined device and network settings (eg Lighthouse , Calibre , WebPageTest ) and
    • Real User Monitoring ( RUM ) tools evaluate user interactions continuously and collect field data (eg SpeedCurve , New Relic — the tools provide synthetic testing, too).

    The former is particularly useful during development as it will help you identify, isolate and fix performance issues while working on the product. The latter is useful for long-term maintenance as it will help you understand your performance bottlenecks as they are happening live — when users actually access the site.

    By tapping into built-in RUM APIs such as Navigation Timing, Resource Timing, Paint Timing, Long Tasks, etc., synthetic testing tools and RUM together provide a complete picture of performance in your application. You could use Calibre, Treo, SpeedCurve, mPulse and Boomerang, Sitespeed.io, which all are great options for performance monitoring. Furthermore, with Server Timing header, you could even monitor back-end and front-end performance all in one place.

    Note : It's always a safer bet to choose network-level throttlers, external to the browser, as, for example, DevTools has issues interacting with HTTP/2 push, due to the way it's implemented ( thanks, Yoav, Patrick !). For Mac OS, we can use Network Link Conditioner, for Windows Windows Traffic Shaper, for Linux netem, and for FreeBSD dummynet.

    As it's likely that you'll be testing in Lighthouse, keep in mind that you can:

    • use Lighthouse CI to track Lighthouse scores over time (it's quite impressive),
    • run Lighthouse in GitHub Actions to get a Lighthouse report alongside every PR,
    • run a Lighthouse performance audit on every page of a site (via Lightouse Parade), with an output saved as CSV,
    • use Lighthouse Scores Calculator and Lighthouse metric weights if you need to dive into more detail.
    • Lighthouse is available for Firefox as well, but under the hood it uses the PageSpeed Insights API and generates a report based on a headless Chrome 79 User-Agent.
Lighthouse CI is quite remarkable: a suite of tools to continuously run, save, retrieve, and assert against Lighthouse results
Lighthouse CI is quite remarkable: a suite of tools to continuously run, save, retrieve, and assert against Lighthouse results. (大プレビュー)
  1. Set up "clean" and "customer" profiles for testing.
    While running tests in passive monitoring tools, it's a common strategy to turn off anti-virus and background CPU tasks, remove background bandwidth transfers and test with a clean user profile without browser extensions to avoid skewed results (in Firefox, and in Chrome).
    DebugBear's report highlights 20 slowest extensions, including password managers, ad-blockers and popular applications like Evernote and Grammarly
    DebugBear's report highlights 20 slowest extensions, including password managers, ad-blockers and popular applications like Evernote and Grammarly. (大プレビュー)

    However, it's also a good idea to study which browser extensions your customers use frequently, and test with dedicated "customer" profiles as well. In fact, some extensions might have a profound performance impact (2020 Chrome Extension Performance Report) on your application, and if your users use them a lot, you might want to account for it up front. Hence, "clean" profile results alone are overly optimistic and can be crushed in real-life scenarios.

  2. パフォーマンスの目標を同僚と共有します。
    今後の誤解を避けるために、パフォーマンスの目標がチームのすべてのメンバーによく知られていることを確認してください。 設計、マーケティング、またはその間のすべての決定にはパフォーマンスへの影響があり、チーム全体に責任と所有権を分散させることで、後でパフォーマンスに焦点を当てた決定を合理化できます。 パフォーマンスバジェットおよび初期に定義された優先順位に対して設計上の決定をマップします。

現実的な目標の設定

  1. 100ミリ秒の応答時間、60fps。
    インタラクションをスムーズに感じるために、インターフェースにはユーザーの入力に応答するための100ミリ秒があります。 それより長くなると、ユーザーはアプリが遅れていると認識します。 ユーザー中心のパフォーマンスモデルであるRAILは、健全なターゲットを提供します。100ミリ秒未満の応答を可能にするには、ページは遅くとも50ミリ秒ごとに制御をメインスレッドに戻す必要があります。 推定入力遅延は、そのしきい値に達しているかどうかを示します。理想的には、50ミリ秒未満である必要があります。 アニメーションのような高圧のポイントについては、できる限り何もしないのが最善であり、できない場合は絶対的な最小値を設定します。

    ユーザー中心のパフォーマンスモデルであるRAIL。
    ユーザー中心のパフォーマンスモデルであるRAIL。

    また、アニメーションの各フレームは16ミリ秒未満で完了する必要があります。これにより、1秒あたり60フレーム(1秒÷60 = 16.6ミリ秒)、できれば10ミリ秒未満で完了します。 ブラウザは新しいフレームを画面にペイントするのに時間がかかるため、16.6ミリ秒のマークに達する前にコードの実行を終了する必要があります。 私たちは120fpsについての会話を始めており(たとえば、iPad Proの画面は120Hzで動作します)、Surmaは120fpsのレンダリングパフォーマンスソリューションをいくつかカバーしていますが、それはおそらくまだ私たちが見ているターゲットではありません

    パフォーマンスの期待については悲観的ですが、インターフェイスデザインについては楽観的であり、アイドル時間を賢く使用してください(idlize、idle-until-urgent、react-idleを確認してください)。 明らかに、これらのターゲットは、ロードパフォーマンスではなく、ランタイムパフォーマンスに適用されます。

  2. FID <100ms、LCP <2.5s、3GでTTI <5​​s、クリティカルファイルサイズバジェット<170KB(gzip圧縮)。
    達成するのは非常に難しいかもしれませんが、最終的な目標は5秒未満のインタラクティブ時間であり、繰り返し訪問する場合は2秒未満を目標とします(サービスワーカーでのみ達成可能)。 2.5秒未満の最大のコンテンツフルペイントを目指し、合計ブロッキング時間累積レイアウトシフトを最小限に抑えます。 許容可能な最初の入力遅延は100ms〜70ms未満です。 上記のように、ベースラインは、400msのRTTと400kbpsの転送速度でエミュレートされた低速の3Gネットワ​​ーク上の200ドルのAndroid携帯電話(Moto G4など)であると考えています。

    Web上でコンテンツを迅速に配信するための合理的な目標を効果的に形作る2つの主要な制約があります。 一方では、TCPスロースタートによるネットワーク配信の制約があります。 HTMLの最初の14KB(10 TCPパケット、各1460バイト、約14.25 KBになりますが、文字通りとは言えません)は、最も重要なペイロードチャンクであり、最初のラウンドトリップで提供できる予算の唯一の部分です(これは、モバイルウェイクアップ時間のために400msRTTで1秒で取得するすべてです)。

    IlyaGrigorikによる高性能ブラウザネットワーキング
    TCP接続では、小さな輻輳ウィンドウから始めて、ラウンドトリップごとに2倍にします。 最初の往復では、14KBを収めることができます。 From:IlyaGrigorikによる高性能ブラウザネットワーキング。 (大プレビュー)

    :TCPは一般にネットワーク接続をかなり活用していないため、GoogleはTCPボトルネック帯域幅とRRT( BBR )、TCP遅延制御TCPフロー制御アルゴリズムを開発しました。最新のWeb用に設計されており、実際の輻輳に対応します。 TCPのようにパケット損失が発生するのではなく、はるかに高速で、スループットが高く、待ち時間が短くなります。また、アルゴリズムの動作も異なります(ありがとう、Victor、Barry! )。

    一方、JavaScriptの解析と実行時間のために、メモリとCPUにハードウェアの制約があります(これらについては後で詳しく説明します)。 最初の段落で述べた目標を達成するには、JavaScriptの重要なファイルサイズの予算を考慮する必要があります。 意見はその予算がどうあるべきかによって異なります(そしてそれはプロジェクトの性質に大きく依存します)が、170KBのJavaScriptをgzipで圧縮した予算は、ミッドレンジの電話で解析およびコンパイルするのに最大1秒かかります。 170KBが解凍時にそのサイズの3倍(0.7MB)に拡張すると仮定すると、それはすでにMoto G4 / G5Plusでの「まともな」ユーザーエクスペリエンスの死の秘訣である可能性があります。

    ウィキペディアのウェブサイトの場合、2020年には、世界中で、コードの実行がウィキペディアのユーザーにとって19%高速になりました。 したがって、前年比のWebパフォーマンスメトリックが安定している場合、環境が改善し続けるにつれて実際に後退しているため、通常は警告サインになります(詳細はGilles Dubucによるブログ投稿にあります)。

    東南アジア、アフリカ、インドなどの成長市場をターゲットにする場合は、非常に異なる一連の制約を調べる必要があります。 Addy Osmaniは、低コストで高品質のデバイスの数が少ない、高品質のネットワークが利用できない、高価なモバイルデータなど、主要なフィーチャーフォンの制約に加えて、これらの環境のPRPL-30予算と開発ガイドラインをカバーしています。

    Addy Osmaniによると、遅延読み込みルートの推奨サイズも35KB未満です。
    Addy Osmaniによると、遅延読み込みルートの推奨サイズも35KB未満です。 (大プレビュー)
    Addy Osmaniは、フィーチャーフォンをターゲットにする場合、PRPL-30のパフォーマンスバジェット(30KB gzip圧縮+最小化された初期バンドル)を提案します
    Addy Osmaniは、フィーチャーフォンをターゲットにする場合、PRPL-30のパフォーマンスバジェット(30KB gzip圧縮+最小化された初期バンドル)を提案しています。 (大プレビュー)

    実際、GoogleのAlex Russellは、妥当な上限として130〜170KBのgzip圧縮を目指すことを推奨しています。 実際のシナリオでは、ほとんどの製品は近くにありません。今日のバンドルサイズの中央値は約452KBで、2015年の初めと比較して53.6%増加しています。中流階級のモバイルデバイスでは、時間の12〜20秒を占めます-To-Interactive

    2019年に世界で最も売れているスマートフォンのGeekbenchCPUパフォーマンスベンチマーク。JavaScriptはシングルコアパフォーマンスを強調し、CPUに依存します
    2019年に世界で最も売れているスマートフォンのGeekbenchCPUパフォーマンスベンチマーク。JavaScriptはシングルコアパフォーマンスを強調し(他のWebプラットフォームよりも本質的にシングルスレッドであることを忘れないでください)、CPUに依存します。 Addyの記事「20ドルのフィーチャーフォンでWebページを高速にロードする」から。 (大プレビュー)

    ただし、バンドルサイズの予算を超えることもできます。 たとえば、ブラウザのメインスレッドのアクティビティ、つまりレンダリングを開始する前のペイント時間に基づいてパフォーマンスバジェットを設定したり、フロントエンドのCPUホッグを追跡したりできます。 Calibre、SpeedCurve、Bundlesizeなどのツールは、予算を抑えるのに役立ち、ビルドプロセスに統合できます。

    最後に、パフォーマンスバジェットはおそらく固定値であってはなりません。 ネットワーク接続に応じて、パフォーマンスバジェットを調整する必要がありますが、低速接続のペイロードは、使用方法に関係なく、はるかに「高価」です。

    :HTTP / 2、今後の5GおよびHTTP / 3、急速に進化する携帯電話、繁栄するSPAの時代に、このような厳格な予算を設定するのは奇妙に聞こえるかもしれません。 ただし、混雑したネットワークからゆっくりと開発されているインフラストラクチャ、データキャップ、プロキシブラウザ、データ保存モード、卑劣なローミング料金など、ネットワークとハードウェアの予測不可能な性質に対処する場合は、合理的に聞こえます。

AddyOsmaniによる「FastByDefault:ModernLoadingBestPractices」から
Fast By Defaultから:Addy Osmaniによる最新の読み込みのベストプラクティス(スライド19)
パフォーマンスバジェットは、平均的なモバイルデバイスのネットワーク条件に応じて調整する必要があります
パフォーマンスバジェットは、平均的なモバイルデバイスのネットワーク条件に応じて調整する必要があります。 (画像ソース:Katie Hempenius)(大プレビュー)

環境の定義

  1. ビルドツールを選択して設定します。
    最近クールだと思われるものにはあまり注意を払わないでください。 Grunt、Gulp、Webpack、Parcel、またはツールの組み合わせなど、構築する環境に固執します。 必要な結果が得られ、ビルドプロセスの維持に問題がない限り、問題なく実行できます。

    ビルドツールの中で、Rollupは勢いを増し続けており、Snowpackも同様ですが、Webpackは最も確立されたツールのようで、ビルドのサイズを最適化するために文字通り何百ものプラグインを利用できます。 Webpackロードマップ2021に注意してください。

    最近登場した最も注目すべき戦略の1つは、重複コードを最小限に抑えるためのNext.jsとGatsbyのWebpackを使用したグラニュラーチャンクです。 デフォルトでは、すべてのエントリポイントで共有されていないモジュールは、それを使用しないルートに対して要求できます。 これは、必要以上に多くのコードがダウンロードされるため、オーバーヘッドになることになります。 Next.jsの詳細なチャンクでは、サーバー側のビルドマニフェストファイルを使用して、出力されたチャンクがさまざまなエントリポイントで使用されているかどうかを判断できます。

    Webpackプロジェクトで重複するコードを減らすために、Next.jsとGatsbyでデフォルトで有効になっているきめ細かいチャンクを使用できます
    Webpackプロジェクトで重複するコードを減らすために、Next.jsとGatsbyでデフォルトで有効になっているきめ細かいチャンクを使用できます。 画像クレジット:Addy Osmani (大プレビュー)

    SplitChunksPluginを使用すると、複数のルート間で重複したコードをフェッチしないように、いくつかの条件に応じて複数の分割チャンクが作成されます。 これにより、ナビゲーション中のページの読み込み時間とキャッシュが改善されます。 Next.js9.2およびGatsbyv2.20.7で出荷されます。

    ただし、Webpackの使用を開始するのは難しい場合があります。 したがって、Webpackに飛び込みたい場合は、いくつかの優れたリソースがあります。

    • Webpackのドキュメント—明らかに—は良い出発点であり、Webpack — RajaRaoによる紛らわしいビットとAndrewWelchによる注釈付きWebpackConfigも同様です。
    • Sean LarkinはWebpackに関する無料のコースを持っています:CoreConceptsとJeffreyWayは、Webpackに関する素晴らしい無料のコースをすべての人にリリースしました。 どちらもWebpackに飛び込むための素晴らしい入門書です。
    • Webpack Fundamentalsは、FrontendMastersからリリースされたSeanLarkinによる非常に包括的な4時間コースです。
    • Webpackの例には、トピックと目的によって分類された、すぐに使用できる何百ものWebpack構成があります。 ボーナス:基本的な構成ファイルを生成するWebpack構成コンフィギュレーターもあります。
    • awesome-webpackは、Angular、React、フレームワークに依存しないプロジェクトの記事、ビデオ、コース、書籍、例など、便利なWebpackリソース、ライブラリ、ツールの厳選されたリストです。
    • Webpackを使用した本番アセットビルドの高速化への道のりは、チームがRequireJSベースのJavaScriptビルドシステムの使用からWebpackの使用に切り替えた方法と、ビルドを最適化し、平均4分で13,200を超えるアセットを管理する方法に関するEtsyのケーススタディです。
    • Webpackのパフォーマンスのヒントは、Ivan Akulovによる金鉱のスレッドであり、特にWebpackに焦点を当てたものを含め、パフォーマンスに焦点を当てた多くのヒントを備えています。
    • awesome-webpack-perfは、パフォーマンスのための便利なWebpackツールとプラグインを備えた金鉱のGitHubリポジトリです。 IvanAkulovによっても維持されています。
Webpackを使用した高速プロダクションビルドへのEtsyの旅の視覚化
Webpackを使用した高速プロダクションビルドへのEtsyの旅(Addy Osmani経由)(大プレビュー)
  1. デフォルトとしてプログレッシブエンハンスメントを使用します。
    それでも、これらすべての年月を経て、フロントエンドのアーキテクチャと展開の指針としてプログレッシブエンハンスメントを維持することは安全な策です。 最初にコアエクスペリエンスを設計および構築してから、対応するブラウザーの高度な機能でエクスペリエンスを強化し、復元力のあるエクスペリエンスを作成します。 あなたのウェブサイトが最適ではないネットワーク上の貧弱なブラウザで貧弱な画面を備えた遅いマシンで高速に実行される場合、それはまともなネットワーク上の優れたブラウザを備えた高速マシンでのみ高速に実行されます。

    実際、アダプティブモジュールサービングでは、プログレッシブエンハンスメントを別のレベルに引き上げ、ローエンドデバイスに「ライト」コアエクスペリエンスを提供し、ハイエンドデバイス向けのより高度な機能でエンハンスメントしているようです。 プログレッシブエンハンスメントがすぐに消えていく可能性はほとんどありません。

  2. 強力なパフォーマンスベースラインを選択します。
    ネットワーク、サーマルスロットリング、キャッシュエビクション、サードパーティスクリプト、パーサーブロッキングパターン、ディスクI / O、IPCレイテンシ、インストールされた拡張機能、ウイルス対策ソフトウェアとファイアウォール、バックグラウンドCPUタスク、ハードウェアとメモリの制約など、読み込みに影響を与える未知数が非常に多いL2 / L3キャッシング、RTTSの違い— JavaScriptは、デフォルトでレンダリングをブロックするWebフォントと、多くの場合メモリを消費しすぎる画像の次に、エクスペリエンスのコストが最も高くなります。 パフォーマンスのボトルネックがサーバーからクライアントに移行するにつれ、開発者として、これらの未知のすべてをより詳細に検討する必要があります。

    クリティカルパスHTML / CSS / JavaScript、ルーター、状態管理、ユーティリティ、フレームワーク、およびアプリケーションロジックがすでに含まれている170KBの予算では、ネットワーク転送コスト、解析/コンパイル時間、およびランタイムコストを徹底的に調査する必要があります私たちの選択のフレームワークの。 幸いなことに、ここ数年で、ブラウザがスクリプトを解析およびコンパイルする速度が大幅に向上しました。 それでも、JavaScriptの実行は依然として主要なボトルネックであるため、スクリプトの実行時間とネットワークに細心の注意を払うことは影響を与える可能性があります。

    Tim Kadlecは、最新のフレームワークのパフォーマンスについて素晴らしい調査を実施し、「JavaScriptフレームワークにはコストがかかる」という記事にまとめました。 スタンドアロンフレームワークの影響についてよく話しますが、Timが指摘しているように、実際には、複数のフレームワークを使用することも珍しくありません。 おそらく、古いバージョンのAngularを使用するいくつかのレガシーアプリケーションとともに、最新のフレームワークにゆっくりと移行されている古いバージョンのjQueryです。 したがって、ハイエンドデバイスでも、ユーザーエクスペリエンスをほとんど使用できないようにする、JavaScriptバイトとCPU実行時間の累積コストを調査する方が合理的です。

    一般に、最新のフレームワークはそれほど強力でないデバイスを優先していないため、電話とデスクトップでのエクスペリエンスは、パフォーマンスの点で劇的に異なることがよくあります。 調査によると、ReactまたはAngularを使用しているサイトは、他のサイトよりもCPUに多くの時間を費やしています(もちろん、ReactがVue.jsよりもCPUで高価であるとは限りません)。

    ティムによれば、明らかなことが1つあります。「フレームワークを使用してサイトを構築している場合、最良のシナリオであっても、初期パフォーマンスの点でトレードオフが発生します。」

フレームワークのコスト、JavaScriptのCPU時間:SPAサイトのパフォーマンスが低い
フレームワークのコスト、JavaScriptバイ:SPAサイトは(まだ)パフォーマンスが悪い
モバイルデバイスのスクリプト関連のCPU時間とdesktopvデバイスのJavaScriptバイト。 一般に、ReactまたはAngularを使用するサイトは、他のサイトよりもCPUに多くの時間を費やします。 ただし、サイトの構築方法によって異なります。 ティム・カドレックによる調査。 (大プレビュー)
  1. フレームワークと依存関係を評価します。
    現在、すべてのプロジェクトにフレームワークが必要なわけではなく、シングルページアプリケーションのすべてのページにフレームワークをロードする必要があるわけでもありません。 Netflixの場合、「React、いくつかのライブラリ、および対応するアプリコードをクライアント側から削除すると、JavaScriptの総量が200 KB以上削減され、ログアウトしたホームページのNetflixの双方向性が50%以上短縮されました。 。」 次に、チームは、ユーザーがランディングページで費やした時間を利用して、ユーザーがランディングする可能性が高い後続のページのReactをプリフェッチしました(詳細については、以下をお読みください)。

    では、重要なページの既存のフレームワークを完全に削除するとどうなるでしょうか。 Gatsbyを使用すると、静的HTMLファイルからGatsbyによって作成されたすべてのJavaScriptファイルを削除するgatsby-plugin-no-javascriptを確認できます。 Vercelでは、特定のページの本番環境でランタイムJavaScriptを無効にすることもできます(実験的)。

    フレームワークが選択されると、少なくとも数年間はそのフレームワークを使用し続けるため、フレームワークを使用する必要がある場合は、選択内容が十分に考慮されていることを確認する必要があります。これは、特に主要なパフォーマンス指標に当てはまります。気に。

    データによると、デフォルトでは、フレームワークは非常に高価です。Reactページの58.6%が1 MBを超えるJavaScriptを出荷し、Vue.jsページの読み込みの36%が1.5秒未満のFirst ContentfulPaintを持っています。 Ankur Sethiの調査によると、「Reactアプリケーションは、最適化しても、インドの平均的な電話で約1.1秒より速く読み込まれることはありません。Angularアプリの起動には常に少なくとも2.7秒かかります。 Vueアプリのユーザーは、使用を開始する前に少なくとも1秒待つ必要があります。」 とにかくプライマリーマーケットとしてインドをターゲットにしていないかもしれませんが、最適ではないネットワーク条件でサイトにアクセスするユーザーは、同等のエクスペリエンスを得ることができます。

    もちろん、SPAを高速化すること可能ですが、すぐに使用できる高速ではないため、SPAを高速化して維持するために必要な時間と労力を考慮する必要があります。 早い段階で軽量のベースラインパフォーマンスコストを選択することで、おそらく簡単になるでしょう。

    では、どのようにフレームワークを選択するのでしょうか? オプションを選択する前に、少なくともサイズの合計コスト+初期実行時間を考慮することをお勧めします。 Preact、Inferno、Vue、Svelte、Alpine、Polymerなどの軽量オプションを使用すると、問題なく作業を行うことができます。 ベースラインのサイズは、アプリケーションのコードの制約を定義します。

    Seb Markbageが指摘しているように、フレームワークの起動コストを測定する良い方法は、最初にビューをレンダリングし、次にそれを削除してから、フレームワークがどのようにスケーリングするかを示すことができるので、もう一度レンダリングすることです。 最初のレンダリングは、レイジーにコンパイルされたコードの束をウォームアップする傾向があります。これは、より大きなツリーがスケーリングするときに恩恵を受けることができます。 2番目のレンダリングは、基本的に、ページが複雑になるにつれて、ページでのコードの再利用がパフォーマンス特性にどのように影響するかをエミュレーションしたものです。

    機能、アクセシビリティ、安定性、パフォーマンス、パッケージエコシステム、コミュニティ、学習曲線、ドキュメント、ツール、実績を調査することで、Sacha Greifの12ポイントスケールスコアリングシステムで候補者(または一般的なJavaScriptライブラリ)を評価することができます。 、チーム、互換性、セキュリティなど。

    Perf Trackは、フレームワークのパフォーマンスを大規模に追跡します
    Perf Trackは、フレームワークのパフォーマンスを大規模に追跡します。 (大プレビュー)

    また、長期間にわたってWeb上で収集されたデータに依存することもできます。 たとえば、Perf Trackはフレームワークのパフォーマンスを大規模に追跡し、Angular、React、Vue、Polymer、Preact、Ember、Svelte、およびAMPで構築されたWebサイトのオリジン集約コアWebバイタルスコアを示します。 Gatsby、Next.js、またはCreate React Appで構築されたWebサイト、およびNuxt.js(Vue)またはSapper(Svelte)で構築されたWebサイトを指定して比較することもできます。

    良い出発点は、アプリケーションに適したデフォルトのスタックを選択することです。 Gatsby(React)、Next.js(React)、Vuepress(Vue)、Preact CLI、およびPWA Starter Kitは、平均的なモバイルハードウェアで箱から出してすぐにロードするための妥当なデフォルトを提供します。 また、ReactとAngularのweb.devフレームワーク固有のパフォーマンスガイダンスもご覧ください(ありがとう、Phillip! )。

    そして、おそらく、シングルページアプリケーションを構築するためにもう少し新鮮なアプローチを取ることができます— Turbolinks、JSONの代わりにHTMLを使用してビューをレンダリングする15KBのJavaScriptライブラリ。 したがって、リンクをたどると、Turbolinksは自動的にページをフェッチし、その<body>をスワップインし、その<head>をマージします。すべて、ページ全体の読み込みのコストは発生しません。 スタック(Hotwire)に関する簡単な詳細と完全なドキュメントを確認できます。

売れ筋の携帯電話の計算パフォーマンスを示すヒストグラムのようなグラフ
売れ筋の携帯電話のCPUとコンピューティングパフォーマンス(画像クレジット:Addy Osmani)(大プレビュー)
  1. クライアント側のレンダリングまたはサーバー側のレンダリング? 両方!
    それは非常に熱心な会話です。 究極のアプローチは、ある種のプログレッシブブートを設定することです。サーバー側のレンダリングを使用して、First Contenful Paintをすばやく取得しますが、インタラクティブまでの時間をFirst Contentful Paintに近づけるために、必要最小限のJavaScriptも含めます。 FCPの後にJavaScriptが遅すぎる場合、ブラウザーは、検出が遅れたJavaScriptの解析、コンパイル、および実行中にメインスレッドをロックし、サイトまたはアプリケーションの対話性を手に負えなくなります。

    これを回避するには、関数の実行を常に個別の非同期タスクに分割し、可能な場合はrequestIdleCallbackを使用します。 WebPackの動的import()サポートを使用してUIの遅延読み込み部分を検討し、ユーザーが本当に必要とするまで読み込み、解析、およびコンパイルのコストを回避します( Addyに感謝します)。

    上記のように、Time to Interactive(TTI)は、ナビゲーションと対話性の間の時間を示します。 詳細には、最初のコンテンツがレンダリングされた後の最初の5秒のウィンドウを確認することでメトリックが定義されます。このウィンドウでは、JavaScriptタスクに50ミリ秒以上かかることはありません( Long Tasks )。 50ミリ秒を超えるタスクが発生した場合、5秒のウィンドウの検索が最初からやり直されます。 その結果、ブラウザは最初にInteractiveに到達したと見なし、 Frozenに切り替えるだけで、最終的にInteractiveに戻ります。

    Interactiveに到達すると、オンデマンドまたは時間の許す限り、アプリの重要でない部分を起動できます。 残念ながら、Paul Lewisが気付いたように、フレームワークには通常、開発者に提示できる優先順位の単純な概念がないため、ほとんどのライブラリとフレームワークでプログレッシブブートを実装するのは簡単ではありません。

    それでも、私たちはそこに到達しています。 最近、私たちが探求できる選択肢がいくつかあります。HousseinDjirdehとJason Millerは、Webでのレンダリングに関する講演と、JasonとAddyによる最新のフロントエンドアーキテクチャに関する記事で、これらのオプションの優れた概要を示しています。 以下の概要は、彼らの優れた業績に基づいています。

    • フルサーバーサイドレンダリング(SSR)
      WordPressなどの従来のSSRでは、すべてのリクエストはサーバー上で完全に処理されます。 要求されたコンテンツは完成したHTMLページとして返され、ブラウザはすぐにそれをレンダリングできます。 したがって、たとえば、SSRアプリは実際にはDOMAPIを利用できません。 First ContentfulPaintとTimeto Interactiveの間のギャップは通常小さく、HTMLがブラウザにストリーミングされているときにページをすぐにレンダリングできます。

      これにより、ブラウザが応答を受け取る前に処理されるため、クライアントでのデータのフェッチとテンプレート作成のための追加のラウンドトリップが回避されます。 ただし、サーバーの思考時間が長くなり、その結果、最初のバイトまでの時間が長くなり、最新のアプリケーションの応答性の高い豊富な機能を利用できなくなります。

    • 静的レンダリング
      製品をシングルページアプリケーションとしてビルドしますが、すべてのページは、ビルドステップとして最小限のJavaScriptを使用して静的HTMLに事前レンダリングされます。 つまり、静的レンダリングでは、可能なURLごとに個別のHTMLファイルを事前に作成します。これは、多くのアプリケーションでは実現できないものです。 ただし、ページのHTMLをその場で生成する必要がないため、一貫して高速な最初のバイトまでの時間を実現できます。 したがって、ランディングページをすばやく表示してから、後続のページのSPAフレームワークをプリフェッチできます。 Netflixはこのアプローチを採用しており、読み込みと対話までの時間を50%削減しています。

    • (再)ハイドレーションを使用したサーバー側レンダリング(ユニバーサルレンダリング、SSR + CSR)
      SSRとCSRの両方の長所を活用することができます。 水分補給が混ざり合っているため、サーバーから返されるHTMLページには、本格的なクライアント側アプリケーションをロードするスクリプトも含まれています。 理想的には、高速のFirst Contentful Paint(SSRなど)を実現してから、(再)ハイドレーションでレンダリングを続行します。 残念ながら、そうなることはめったにありません。 多くの場合、ページは準備ができているように見えますが、ユーザーの入力に応答できず、怒りのクリックや放棄が発生します。

      Reactを使用すると、ExpressなどのノードサーバーでReactDOMServerモジュールを使用してから、 renderToStringメソッドを呼び出して、最上位のコンポーネントを静的なHTML文字列としてレンダリングできます。

      Vue.jsでは、vue-server-rendererを使用して、 renderToStringを使用してVueインスタンスをHTMLにレンダリングできます。 Angularでは、 @nguniversalを使用して、クライアントリクエストを完全にサーバーでレンダリングされたHTMLページに変換できます。 Next.js(React)またはNuxt.js(Vue)を使用すると、サーバーで完全にレンダリングされたエクスペリエンスをすぐに実現することもできます。

      このアプローチには欠点があります。 その結果、より高速なサーバー側レンダリングを提供しながら、クライアント側アプリの完全な柔軟性を得ることができますが、First ContentfulPaintとTimeTo Interactiveの間のギャップが長くなり、First InputDelayが増加します。 水分補給は非常に費用がかかります。通常、この戦略だけでは、インタラクティブ時間の大幅な遅延が発生するため、十分ではありません。

    • プログレッシブハイドレーション(SSR + CSR)を使用したスト​​リーミングサーバーサイドレンダリング
      Time ToInteractiveとFirstContentful Paintの間のギャップを最小限に抑えるために、一度に複数のリクエストをレンダリングし、コンテンツが生成されるときにコンテンツをチャンクで送信します。 したがって、コンテンツをブラウザに送信する前にHTMLの完全な文字列を待つ必要がないため、最初のバイトまでの時間が短縮されます。

      Reactでは、renderToString()の代わりに、 renderToString()を使用して応答をパイプ処理し、HTMLをチャンクで送信できます。 Vueでは、パイプとストリーミングが可能なrenderToStream()を使用できます。 React Suspenseを使用すると、その目的で非同期レンダリングを使用することもできます。

      クライアント側では、アプリケーション全体を一度に起動するのではなく、コンポーネントを段階的に起動します。 アプリケーションのセクションは、最初にコード分割を使用してスタンドアロンスクリプトに分割され、次に徐々に(優先順位に従って)ハイドレイトされます。 実際、重要なコンポーネントを最初に水和し、残りを後で水和することができます。 クライアント側とサーバー側のレンダリングの役割は、コンポーネントごとに異なる方法で定義できます。 次に、一部のコンポーネントが表示されるまで、またはユーザーインタラクションに必要になるまで、またはブラウザがアイドル状態になるまで、一部のコンポーネントのハイドレーションを延期することもできます。

      Vueの場合、Markus Oberlehnerは、ユーザーインタラクションのハイドレーションと、可視性または特定のユーザーインタラクションのコンポーネントハイドレーションを可能にする初期段階のプラグインであるvue-lazy-hydrationを使用して、SSRアプリのインタラクティブ時間の短縮に関するガイドを公開しました。 Angularチームは、IvyUniversalを使用してプログレッシブハイドレーションに取り組んでいます。 PreactとNext.jsを使用して部分的なハイドレーションを実装することもできます。

    • トリソモルフィックレンダリング
      サービスワーカーを配置すると、初期/非JSナビゲーションにストリーミングサーバーレンダリングを使用し、インストール後にサービスワーカーにナビゲーション用のHTMLのレンダリングを実行させることができます。 その場合、Service Workerはコンテンツを事前レンダリングし、同じセッションで新しいビューをレンダリングするためのSPAスタイルのナビゲーションを有効にします。 サーバー、クライアントページ、およびServiceWorker間で同じテンプレートコードとルーティングコードを共有できる場合にうまく機能します。

    DOMレンダリング、サービスワーカーの事前レンダリング、サーバー側のレンダリングなど、3か所でトリソモーフィックレンダリングがどのように機能するかを示す図
    サーバー、DOM、またはServiceWorkerの3か所で同じコードレンダリングを使用するTrisomorphicレンダリング。 (画像ソース:Google Developers)(大プレビュー)
    • 事前レンダリングによるCSR
      事前レンダリングはサーバー側のレンダリングに似ていますが、サーバー上のページを動的にレンダリングするのではなく、ビルド時にアプリケーションを静的HTMLにレンダリングします。 静的ページはクライアント側のJavaScriptがあまりなくても完全にインタラクティブですが、事前レンダリングの動作は異なります。 基本的に、ビルド時にクライアント側アプリケーションの初期状態を静的HTMLとしてキャプチャしますが、ページをインタラクティブにするには、事前レンダリングを使用してアプリケーションをクライアントで起動する必要があります。

      Next.jsを使用すると、アプリを静的HTMLに事前レンダリングすることで、静的HTMLエクスポートを使用できます。 Gatsbyでは、Reactを使用するオープンソースの静的サイトジェネレーターは、ビルド中にrenderToStaticMarkupメソッドの代わりにrenderToStringメソッドを使用し、メインのJSチャンクがプリロードされ、将来のルートがプリフェッチされます。単純な静的ページには必要のないDOM属性はありません。

      Vueの場合、Vuepressを使用して同じ目標を達成できます。 Webpackでprerender-loaderを使用することもできます。 Naviは静的レンダリングも提供します。

      その結果、最初のバイトまでの時間と最初の満足のいくペイントが改善され、インタラクティブな時間と最初の満足のいくペイントの間のギャップが減少します。 コンテンツが大幅に変更されることが予想される場合、このアプローチを使用することはできません。 さらに、すべてのページを生成するには、すべてのURLを事前に知っておく必要があります。 そのため、一部のコンポーネントは事前レンダリングを使用してレンダリングされる場合がありますが、動的なものが必要な場合は、アプリに依存してコンテンツをフェッチする必要があります。

    • フルクライアントサイドレンダリング(CSR)
      すべてのロジック、レンダリング、および起動はクライアントで実行されます。 その結果、通常、Time ToInteractiveとFirstContentfulPaintの間に大きなギャップが生じます。 その結果、何かをレンダリングするにはアプリ全体をクライアントで起動する必要があるため、アプリケーションの動作が遅くなることがよくあります。

      JavaScriptにはパフォーマンスコストがかかるため、アプリケーションとともにJavaScriptの量が増えるにつれて、JavaScriptの積極的なコード分割と延期は、JavaScriptの影響を抑えるために絶対に必要になります。 このような場合、対話性があまり必要ない場合は、通常、サーバー側のレンダリングの方が適しています。 オプションでない場合は、App ShellModelの使用を検討してください。

      一般的に、SSRはCSRよりも高速です。 それでもなお、これは多くのアプリで非常に頻繁に実装されています。

    では、クライアント側ですか、それともサーバー側ですか? 一般に、完全にクライアント側のフレームワークの使用を、それらを絶対に必要とするページに制限することをお勧めします。 高度なアプリケーションの場合、サーバー側のレンダリングだけに依存することもお勧めできません。 サーバーレンダリングとクライアントレンダリングはどちらも、うまく行かないと大惨事になります。

    CSRまたはSSRのどちらに傾倒している場合でも、重要なピクセルをできるだけ早くレンダリングし、そのレンダリングとインタラクティブ時間のギャップを最小限に抑えるようにしてください。 ページがあまり変更されない場合は事前レンダリングを検討し、可能であればフレームワークの起動を延期します。 サーバー側のレンダリングを使用してHTMLをチャンクでストリーミングし、クライアント側のレンダリングにプログレッシブハイドレーションを実装します。また、可視性、対話、またはアイドル時間中にハイドレイトして、両方の世界を最大限に活用します。

クライアント側とサーバー側のレンダリングのオプションを比較した表
クライアント側とサーバー側のレンダリングのオプションの範囲。 また、アプリケーションアーキテクチャのパフォーマンスへの影響に関するGoogle I / OでのJasonとHousseinの講演も確認してください。 (画像ソース:Jason Miller)(大プレビュー)
左側にプログレッシブハイドレーションなし、右側にプログレッシブハイドレーションがあるAirBnBのウェブサイトの例
AirBnBは漸進的な水分補給を実験してきました。 それらは、不要なコンポーネントを延期し、ユーザーの操作(スクロール)またはアイドル時間中に負荷をかけ、テストにより、TTIを改善できることが示されています。 (大プレビュー)
  1. 静的にいくらサービスを提供できますか?
    大規模なアプリケーションで作業している場合でも、小規模なサイトで作業している場合でも、オンザフライで動的に生成するのではなく、CDN(つまり、JAMスタック)から静的に提供できるコンテンツを検討する価値があります。 パーソナライズオプションが豊富な数千の製品と数百のフィルターがある場合でも、重要なランディングページを静的に提供し、これらのページを選択したフレームワークから切り離したい場合があります。

    静的サイトジェネレーターはたくさんあり、それらが生成するページは非常に高速であることがよくあります。 The more content we can pre-build ahead of time instead of generating page views on a server or client at request time, the better performance we will achieve.

    In Building Partially Hydrated, Progressively Enhanced Static Websites, Markus Oberlehner shows how to build out websites with a static site generator and an SPA, while achieving progressive enhancement and a minimal JavaScript bundle size. Markus uses Eleventy and Preact as his tools, and shows how to set up the tools, add partial hydration, lazy hydration, client entry file, configure Babel for Preact and bundle Preact with Rollup — from start to finish.

    With JAMStack used on large sites these days, a new performance consideration appeared: the build time . In fact, building out even thousands of pages with every new deploy can take minutes, so it's promising to see incremental builds in Gatsby which improve build times by 60 times , with an integration into popular CMS solutions like WordPress, Contentful, Drupal, Netlify CMS and others.

    A flow chart showing User 1 on the top left and User 2 on the bottom left showing the process of incremental status re-generation
    Incremental static regeneration with Next.js. (Image credit: Prisma.io) (Large preview)

    Also, Next.js announced ahead-of-time and incremental static generation, which allows us to add new static pages at runtime and update existing pages after they've been already built, by re-rendering them in the background as traffic comes in.

    Need an even more lightweight approach? In his talk on Eleventy, Alpine and Tailwind: towards a lightweight Jamstack, Nicola Goutay explains the differences between CSR, SSR and everything-in-between, and shows how to use a more lightweight approach — along with a GitHub repo that shows the approach in practice.

  2. Consider using PRPL pattern and app shell architecture.
    Different frameworks will have different effects on performance and will require different strategies of optimization, so you have to clearly understand all of the nuts and bolts of the framework you'll be relying on. When building a web app, look into the PRPL pattern and application shell architecture. The idea is quite straightforward: Push the minimal code needed to get interactive for the initial route to render quickly, then use service worker for caching and pre-caching resources and then lazy-load routes that you need, asynchronously.
PRPL Pattern in the application shell architecture
PRPL stands for Pushing critical resource, Rendering initial route, Pre-caching remaining routes and Lazy-loading remaining routes on demand.
Application shell architecture
An application shell is the minimal HTML, CSS, and JavaScript powering a user interface.
  1. Have you optimized the performance of your APIs?
    APIs are communication channels for an application to expose data to internal and third-party applications via endpoints . When designing and building an API, we need a reasonable protocol to enable the communication between the server and third-party requests. Representational State Transfer ( REST ) is a well-established, logical choice: it defines a set of constraints that developers follow to make content accessible in a performant, reliable and scalable fashion. Web services that conform to the REST constraints, are called RESTful web services .

    As with good ol' HTTP requests, when data is retrieved from an API, any delay in server response will propagate to the end user, hence delaying rendering . When a resource wants to retrieve some data from an API, it will need to request the data from the corresponding endpoint. A component that renders data from several resources, such as an article with comments and author photos in each comment, may need several roundtrips to the server to fetch all the data before it can be rendered. Furthermore, the amount of data returned through REST is often more than what is needed to render that component.

    If many resources require data from an API, the API might become a performance bottleneck. GraphQL provides a performant solution to these issues. Per se, GraphQL is a query language for your API, and a server-side runtime for executing queries by using a type system you define for your data. Unlike REST, GraphQL can retrieve all data in a single request , and the response will be exactly what is required, without over or under -fetching data as it typically happens with REST.

    In addition, because GraphQL is using schema (metadata that tells how the data is structured), it can already organize data into the preferred structure, so, for example, with GraphQL, we could remove JavaScript code used for dealing with state management, producing a cleaner application code that runs faster on the client.

    If you want to get started with GraphQL or encounter performance issues, these articles might be quite helpful:

    • A GraphQL Primer: Why We Need A New Kind Of API by Eric Baer,
    • A GraphQL Primer: The Evolution Of API Design by Eric Baer,
    • Designing a GraphQL server for optimal performance by Leonardo Losoviz,
    • GraphQL performance explained by Wojciech Trocki.
Two examples of mobile interfaces for messages while using Redux/REST (left) and Apollo/GraphQL (right)
A difference between REST and GraphQL, illustrated via a conversation between Redux + REST on the left, an Apollo + GraphQL on the right. (Image source: Hacker Noon) (Large preview)
  1. Will you be using AMP or Instant Articles?
    Depending on the priorities and strategy of your organization, you might want to consider using Google's AMP or Facebook's Instant Articles or Apple's Apple News. You can achieve good performance without them, but AMP does provide a solid performance framework with a free content delivery network (CDN), while Instant Articles will boost your visibility and performance on Facebook.

    The seemingly obvious benefit of these technologies for users is guaranteed performance , so at times they might even prefer AMP-/Apple News/Instant Pages-links over "regular" and potentially bloated pages. For content-heavy websites that are dealing with a lot of third-party content, these options could potentially help speed up render times dramatically.

    Unless they don't. According to Tim Kadlec, for example, "AMP documents tend to be faster than their counterparts, but they don't necessarily mean a page is performant. AMP is not what makes the biggest difference from a performance perspective."

    A benefit for the website owner is obvious: discoverability of these formats on their respective platforms and increased visibility in search engines.

    Well, at least that's how it used to be. As AMP is no longer a requirement for Top Stories , publishers might be moving away from AMP to a traditional stack instead ( thanks, Barry! ).

    Still, you could build progressive web AMPs, too, by reusing AMPs as a data source for your PWA. Downside? Obviously, a presence in a walled garden places developers in a position to produce and maintain a separate version of their content, and in case of Instant Articles and Apple News without actual URLs (thanks Addy, Jeremy!) .

  2. Choose your CDN wisely.
    As mentioned above, depending on how much dynamic data you have, you might be able to "outsource" some part of the content to a static site generator, pushing it to a CDN and serving a static version from it, thus avoiding requests to the server. In fact, some of those generators are actually website compilers with many automated optimizations provided out of the box. As compilers add optimizations over time, the compiled output gets smaller and faster over time.

    Notice that CDNs can serve (and offload) dynamic content as well. So, restricting your CDN to static assets is not necessary. Double-check whether your CDN performs compression and conversion (eg image optimization and resizing at the edge), whether they provide support for servers workers, A/B testing, as well as edge-side includes, which assemble static and dynamic parts of pages at the CDN's edge (ie the server closest to the user), and other tasks. Also, check if your CDN supports HTTP over QUIC (HTTP/3).

    Katie Hempenius has written a fantastic guide to CDNs that provides insights on how to choose a good CDN , how to finetune it and all the little things to keep in mind when evaluating one. In general, it's a good idea to cache content as aggressively as possible and enable CDN performance features like Brotli, TLS 1.3, HTTP/2, and HTTP/3.

    Note : based on research by Patrick Meenan and Andy Davies, HTTP/2 prioritization is effectively broken on many CDNs, so be careful when choosing a CDN. Patrick has more details in his talk on HTTP/2 Prioritization ( thanks, Barry! ).

    CDNPerf preview of CDN names and query speed in ms
    CDNPerf measures query speed for CDNs by gathering and analyzing 300 million tests every day. (大プレビュー)

    When choosing a CDN, you can use these comparison sites with a detailed overview of their features:

    • CDN比較、Cloudfront、Aazure、KeyCDN、Fastly、Verizon、Stackpach、AkamaiなどのCDN比較マトリックス。
    • CDN Perfは、毎日3億件のテストを収集して分析することにより、CDNのクエリ速度を測定します。すべての結果は、世界中のユーザーからのRUMデータに基づいています。 DNSパフォーマンスの比較とクラウドパフォーマンスの比較も確認してください。
    • CDN Planet Guidesは、Serve Stale、Purge、Origin Shield、Prefetch、Compressionなどの特定のトピックに関するCDNの概要を提供します。
    • Webアルマナック:CDNの採用と使用法は、トップCDNプロバイダー、それらのRTTおよびTLS管理、TLSネゴシエーション時間、HTTP / 2採用などに関する洞察を提供します。 (残念ながら、データは2019年のもののみです)。

資産の最適化

  1. プレーンテキストの圧縮にはBrotliを使用します。
    2015年、Googleは新しいオープンソースのロスレスデータ形式であるBrotliを導入しました。これは、現在すべての最新のブラウザでサポートされています。 Brotli用のエンコーダーとデコーダーを実装するオープンソースのBrotliライブラリには、エンコーダー用に11の事前定義された品質レベルがあり、品質レベルが高いほど、より良い圧縮率と引き換えにより多くのCPUが必要になります。 圧縮が遅いと、最終的には圧縮率が高くなりますが、それでもBrotliは高速に解凍します。 圧縮レベル4のBrotliは、Gzipよりも小さく、圧縮速度も速いことに注意してください。

    実際には、BrotliはGzipよりもはるかに効果的であるように見えます。 意見や経験は異なりますが、サイトがすでにGzipで最適化されている場合は、サイズの縮小とFCPのタイミングで少なくとも1桁の改善、せいぜい2桁の改善が期待できます。 また、サイトのBrotli圧縮の節約を見積もることもできます。

    ブラウザは、ユーザーがHTTPS経由でWebサイトにアクセスしている場合にのみBrotliを受け入れます。 Brotliは広くサポートされており、多くのCDN(Akamai、Netlify Edge、AWS、KeyCDN、Fastly(現在はパススルーとしてのみ)、Cloudflare、CDN77)をサポートしており、まだサポートしていないCDNでもBrotliを有効にできます(サービスワーカーと)。

    欠点は、Brotliを使用してすべてのアセットを高圧縮レベルで圧縮するのはコストがかかるため、多くのホスティングプロバイダーは、コストのオーバーヘッドが大きいという理由だけで、Brotliをフルスケールで使用できないことです。 実際、最高レベルの圧縮では、Brotliは非常に遅いため、サーバーがアセットを動的に圧縮するのを待機するときにサーバーが応答の送信を開始するのにかかる時間によって、ファイルサイズの潜在的な増加が無効になる可能性があります。 (ただし、ビルド時間中に静的圧縮を使用する時間がある場合は、もちろん、より高い圧縮設定が推奨されます。)

    最小、平均、および90パーセンタイルの3つの異なるバックエンド時間にわたるさまざまな圧縮方法を示すウィスカチャートとして示される比較
    さまざまな圧縮方法のバックエンド時間の比較。 当然のことながら、Brotliはgzipよりも低速です(今のところ)。 (大プレビュー)

    ただし、これは変更される可能性があります。 Brotliファイル形式には、組み込みの静的辞書が含まれており、複数の言語のさまざまな文字列を含むことに加えて、それらの単語に複数の変換を適用するオプションもサポートしているため、汎用性が向上します。 彼の研究で、Felix Hanauは、「デフォルトよりも特殊な辞書のサブセット」を使用し、 Content-Typeヘッダーを使用してコンプレッサーに、 HTML、JavaScriptまたはCSSの辞書。 その結果、「辞書の使用を制限したアプローチを使用して、高圧縮レベルでWebコンテンツを圧縮した場合、パフォーマンスへの影響はごくわずかです(通常の12%に比べてCPUが1%から3%多くなります)」。

    レベル5でBrotli削減辞書を使用した圧縮ゲインを示す棒グラフ
    改善された辞書アプローチにより、1%から3%多くのCPUを使用しながら、より高い圧縮レベルでアセットをより高速に圧縮できます。 通常、圧縮レベル6が5を超えると、CPU使用率が最大12%増加します。 (大プレビュー)

    さらに、Elena Kirilenkoの調査により、以前の圧縮アーティファクトを使用して、高速で効率的なBrotli再圧縮を実現できます。 Elena氏によると、「Brotliを介してアセットを圧縮し、動的コンテンツをオンザフライで圧縮しようとすると、コンテンツが事前に利用可能なコンテンツに似ているため、圧縮時間の大幅な改善を実現できます。 「」

    どのくらいの頻度でそうですか? たとえば、 JavaScriptバンドルサブセットの配信(たとえば、コードの一部がクライアントにすでにキャッシュされている場合、またはWebBundleで提供される動的バンドルを使用する場合)。 または、既知の高度なテンプレートに基づくダイナミックHTML、または動的にサブセット化されたWOFF2フォントを使用します。 Elenaによると、コンテンツの10%を削除すると、圧縮率が5.3%向上し、圧縮速度が39%向上します。また、コンテンツの50%を削除すると、圧縮率が3.2%向上し、圧縮率が26%向上します。

    Brotliの圧縮は向上しているため、静的アセットを動的に圧縮するコストを回避できれば、努力する価値は間違いありません。 言うまでもなく、Brotliは、HTML、CSS、SVG、JavaScript、JSONなどの任意のプレーンテキストペイロードに使用できます。

    :2021年初頭の時点で、HTTP応答の約60%がテキストベースの圧縮なしで配信され、30.82%がGzipで圧縮され、9.1%がBrotliで圧縮されています(モバイルとデスクトップの両方)。 たとえば、Angularページの23.4%は圧縮されていません(gzipまたはBrotliを介して)。 しかし、多くの場合、圧縮をオンにすることは、スイッチを押すだけでパフォーマンスを向上させる最も簡単な方法の1つです。

    戦略は? 静的アセットを最高レベルのBrotli + Gzipで事前圧縮し、(動的)HTMLをレベル4〜6のBrotliでオンザフライで圧縮します。 サーバーがBrotliまたはGzipのコンテンツネゴシエーションを適切に処理することを確認してください。

Web Almanax2020レポートによるHTTPリクエストの圧縮アルゴリズムを示す棒グラフ
2020年に圧縮されて提供されるリソースのうち、22.59%がBrotliで圧縮されています。 約77.39%がgzipで圧縮されています。 (画像ソース:Webアルマナック:圧縮)(大プレビュー)
  1. アダプティブメディアローディングとクライアントヒントを使用していますか?
    これは古いニュースの世界から来ていますが、 srcsetsizes 、および<picture>要素を含むレスポンシブ画像を使用することを常にお勧めします。 特にメディアフットプリントが大きいサイトの場合、アダプティブメディアローディング(この例ではReact + Next.js)を使用してさらに一歩進め、低速のネットワークと低メモリデバイスに軽いエクスペリエンスを提供し、高速のネットワークと高速に完全なエクスペリエンスを提供できます-メモリデバイス。 Reactのコンテキストでは、サーバー上のクライアントヒントとクライアント上のreact-adaptive-hooksを使用してこれを実現できます。

    レスポンシブ画像の未来は、クライアントヒントの採用が広がるにつれて劇的に変わる可能性があります。 クライアントヒントは、HTTPリクエストヘッダーフィールドです。たとえば、 DPRViewport-WidthWidthSave-DataAccept (画像形式の設定を指定するため)などです。 それらは、ユーザーのブラウザ、画面、接続などの詳細についてサーバーに通知することになっています。

    その結果、サーバーは適切なサイズの画像をレイアウトに入力する方法を決定し、これらの画像のみを目的の形式で提供できます。 クライアントヒントを使用して、リソースの選択をHTMLマークアップから、クライアントとサーバー間の要求/応答ネゴシエーションに移動します。

    ネットワーク機能に応じてユーザーに異なる解像度を送信することにより、アダプティブメディアサービングをどのように使用できるかを示す図
    使用中のアダプティブメディア。 オフラインのユーザーにはテキスト、2Gユーザーには低解像度の画像、3Gユーザーには高解像度の画像、4GユーザーにはHDビデオを含むプレースホルダーを送信します。 20ドルのフィーチャーフォンでウェブページをすばやく読み込む。 (大プレビュー)

    Ilya Grigorikがしばらく前に指摘したように、クライアントのヒントが全体像を完成させます。これらはレスポンシブ画像に代わるものではありません。 「 <picture>要素は、HTMLマークアップで必要なアートディレクションコントロールを提供します。クライアントヒントは、リソース選択の自動化を可能にする結果の画像リクエストに注釈を提供します。ServiceWorkerは、クライアントに完全なリクエストおよびレスポンス管理機能を提供します。」

    たとえば、サービスワーカーは、リクエストに新しいクライアントヒントヘッダー値を追加したり、URLを書き換えて画像リクエストをCDNにポイントしたり、接続性やユーザー設定に基づいて応答を調整したりできます。これは、画像アセットだけでなく、他のほとんどすべてのリクエストについても同様です。

    クライアントヒントをサポートするクライアントの場合、画像で42%のバイト節約、70パーセンタイル以上で1MB以上のバイト削減を測定できます。 Smashing Magazineでは、19〜32%の改善も測定できました。 クライアントヒントはChromiumベースのブラウザでサポートされていますが、Firefoxではまだ検討中です。

    ただし、クライアントヒントに通常のレスポンシブ画像マークアップと<meta>タグの両方を指定すると、サポートするブラウザがレスポンシブ画像マークアップを評価し、クライアントヒントHTTPヘッダーを使用して適切な画像ソースを要求します。

  2. 背景画像にレスポンシブ画像を使用していますか?
    きっと! Safari 14およびFirefoxを除くほとんどの最新ブラウザでサポートされるようになったimage-setを使用すると、レスポンシブな背景画像も提供できます。

    background-image: url("fallback.jpg"); background-image: image-set( "photo-small.jpg" 1x, "photo-large.jpg" 2x, "photo-print.jpg" 600dpi);

    基本的に、 1x記述子を使用した低解像度の背景画像、 2x記述子を使用した高解像度画像、さらには600dpi記述子を使用した印刷品質の画像を条件付きで提供できます。 ただし、注意してください。ブラウザは支援技術に背景画像に関する特別な情報を提供しないため、理想的にはこれらの写真は単なる装飾にすぎません。

  3. WebPを使用していますか?
    多くの場合、画像圧縮はすぐに成功すると考えられていますが、実際にはまだ十分に活用されていません。 もちろん、画像はレンダリングをブロックしませんが、LCPスコアの低下に大きく影響します。また、多くの場合、画像は、使用しているデバイスに対して重すぎたり大きすぎたりします。

    したがって、少なくとも、画像にWebP形式を使用して探索することができます。 実際、WebPの物語は、AppleがSafari 14でWebPのサポートを追加することで、昨年終わりに近づいています。したがって、長年の議論と議論の末、今日の時点で、WebPはすべての最新ブラウザーでサポートされています。 したがって、必要に応じて<picture>要素とJPEGフォールバックを使用して(Andreas Bovensのコードスニペットを参照)、またはコンテンツネゴシエーションを使用して( Acceptヘッダーを使用して)WebP画像を提供できます。

    ただし、WebPには欠点があります。 WebP画像のファイルサイズは同等のGuetzliやZopfliと比較されますが、この形式はJPEGのようなプログレッシブレンダリングをサポートしていません。そのため、WebP画像はネットワークを介して高速化される可能性がありますが、ユーザーは古き良きJPEGで完成した画像をより速く表示できます。 JPEGを使用すると、WebPの場合のように半分空の画像を表示するのではなく、データの半分または4分の1で「まともな」ユーザーエクスペリエンスを提供し、残りを後で読み込むことができます。

    決定は、何を求めているかによって異なります。WebPを使用するとペイロードが減り、JPEGを使用すると知覚されるパフォーマンスが向上します。 WebPの詳細については、GoogleのPascalMassiminoによるWebPRewindトークをご覧ください。

    WebPへの変換には、WebP Converter、cwebp、またはlibwebpを使用できます。 Ire Aderinokunには、画像をWebPに変換するための非常に詳細なチュートリアルもあります。また、最新の画像形式を採用することについてのJoshComeauも同様です。

    PascalMassiminoの講演「Imageready:webprewind」に使用されたスライド
    WebPについての徹底的な話:PascalMassiminoによるWebP巻き戻し。 (大プレビュー)

    SketchはネイティブにWebPをサポートしており、Photoshop用のWebPプラグインを使用してWebP画像をPhotoshopからエクスポートできます。 ただし、他のオプションも利用できます。

    WordPressまたはJoomlaを使用している場合は、WordPress用のOptimusやCache Enabler、Joomla独自のサポートされている拡張機能(Cody Arsenault経由)など、WebPのサポートを簡単に実装するのに役立つ拡張機能があります。 <picture>要素をReact、スタイル付きコンポーネント、またはgatsby-imageで抽象化することもできます。

    ああ—恥知らずなプラグ! — Jeremy Wagnerは、WebPに関するSmashingの本を出版しました。これは、WebPに関するすべてのことに興味があるかどうかを確認することをお勧めします。

  4. AVIFを使用していますか?
    あなたは大きなニュースを聞いたことがあるかもしれません:AVIFが上陸しました。 これは、AV1ビデオのキーフレームから派生した新しい画像形式です。 これは、非可逆および可逆圧縮、アニメーション、非可逆アルファチャネルをサポートし、シャープな線と単色(JPEGの問題でした)を処理できると同時に、両方でより良い結果を提供する、オープンでロイヤリティフリーの形式です。

    実際、WebPやJPEGと比較して、AVIFのパフォーマンスは大幅に向上し、同じDSSIMでファイルサイズの中央値を最大50%節約できます(人間の視覚に近いアルゴリズムを使用した2つ以上の画像間の(非)類似性)。 実際、Malte Ublは、画像の読み込みの最適化に関する徹底的な投稿で、AVIFは「非常に一貫して非常に重要な点でJPEGを上回っています。これは、常にJPEGよりも小さい画像を生成するわけではなく、実際にはネットである可能性があるWebPとは異なります。プログレッシブローディングのサポートの欠如による損失。」

    プログレッシブエンハンスメントとしてAVIFを示すコードスニペット
    AVIFをプログレッシブエンハンスメントとして使用して、WebP、JPEG、またはPNGを古いブラウザーに配信できます。 (大きなプレビュー)。 以下のプレーンテキストビューを参照してください。

    皮肉なことに、AVIFは大規模なSVGよりも優れたパフォーマンスを発揮しますが、もちろんSVGの代わりと見なすべきではありません。 また、HDRカラーサポートをサポートする最初の画像形式の1つです。 より高い輝度、カラービット深度、および色域を提供します。 唯一の欠点は、現在AVIFがプログレッシブ画像のデコードをサポートしていないことです(まだ?)。Brotliと同様に、デコードは高速ですが、高圧縮率のエンコードは現在非常に低速です。

    AVIFは現在Chrome、Firefox、Operaでサポートされており、Safariでのサポートは間もなく開始される予定です(AppleはAV1を作成したグループのメンバーであるため)。

    最近の画像を提供するための最良の方法は何ですか? イラストやベクター画像の場合、(圧縮された)SVGが間違いなく最良の選択です。 写真の場合、 picture要素を使用したコンテンツネゴシエーションメソッドを使用します。 AVIFがサポートされている場合は、AVIFイメージを送信します。 そうでない場合は、最初にWebPにフォールバックし、WebPもサポートされていない場合は、フォールバックとしてJPEGまたはPNGに切り替えます(必要に応じて@media条件を適用します)。

    <picture> <source type="image/avif"> <source type="image/webp"> <img src="image.jpg" alt="Photo" width="450" height="350"> </picture>

    率直に言って、 picture要素内でいくつかの条件を使用する可能性が高くなります。

    <picture> <source type="image/avif" /> <source type="image/webp" /> <source type="image/jpeg" /> <img src="fallback-image.jpg" alt="Photo" width="450" height="350"> </picture>
    <picture> <source type="image/avif" /> <source type="image/webp" /> <source type="image/jpeg" /> <img src="fallback-image.jpg" alt="Photo" width="450" height="350"> </picture>

    動きを少なくすることを選択し、 prefers-reduced-motionを使用する顧客のために、アニメーション画像を静止画像と交換することで、さらに先に進むことができます。

    <picture> <source media="(prefers-reduced-motion: reduce)" type="image/avif"></source> <source media="(prefers-reduced-motion: reduce)" type="image/jpeg"></source> <source type="image/avif"></source> <img src="motion.jpg" alt="Animated AVIF"> </picture>
    <picture> <source media="(prefers-reduced-motion: reduce)" type="image/avif"></source> <source media="(prefers-reduced-motion: reduce)" type="image/jpeg"></source> <source type="image/avif"></source> <img src="motion.jpg" alt="Animated AVIF"> </picture>

    数か月の間に、AVIFはかなりの牽引力を獲得しました。

    • DevToolsの[レンダリング]パネルでWebP / AVIFフォールバックをテストできます。
    • Squoosh、AVIF.io、libavifを使用して、AVIFファイルのエンコード、デコード、圧縮、変換を行うことができます。
    • ワーカーでAVIFファイルをデコードし、結果をキャンバスに表示するJakeArchibaldのAVIFPreactコンポーネントを使用できます。
    • サポートしているブラウザにのみAVIFを配信するために、PostCSSプラグインと315Bスクリプトを使用して、CSS宣言でAVIFを使用できます。
    • CSSとCloudlareWorkersを使用して新しい画像形式を段階的に提供し、返されたHTMLドキュメントを動的に変更し、 acceptヘッダーから情報を推測して、必要に応じてwebp/avifなどのクラスを追加できます。
    • AVIFはすでにCloudinaryで利用可能であり(使用制限あり)、Cloudflareは画像のサイズ変更でAVIFをサポートしており、NetlifyのカスタムAVIFヘッダーでAVIFを有効にすることができます。
    • アニメーションに関しては、AVIFはSafariの<img src=mp4>と同様に機能し、GIFやWebP全体を上回っていますが、MP4の方が優れています。
    • 一般に、アニメーションの場合、Chromiumベースのブラウザが<img src=mp4>をサポートすると仮定すると、AVC1(h264)> HVC1> WebP> AVIF> GIFです。
    • AVIFの詳細については、NetflixのAdityaMavlankarによるAVIFfor Next Generation Image Codingトーク、およびCloudflareのKornelLesinskiによるAVIFImageFormatトークをご覧ください。
    • すべてのAVIFの優れたリファレンス:AVIFに関するJakeArchibaldの包括的な投稿が上陸しました。

    では、将来のAVIFはそうですか? Jon Sneyersは同意しません。AVIFのパフォーマンスは、GoogleとCloudinaryによって開発されたもう1つの無料のオープンフォーマットであるJPEG XLよりも60%劣っています。 実際、JPEGXLのパフォーマンスは全体的にはるかに優れているようです。 ただし、JPEG XLはまだ標準化の最終段階にあり、どのブラウザでもまだ機能していません。 (古き良きInternet Explorerから9回提供されているMicrosoftのJPEG-XRと混同しないでください)。

レスポンシブ画像ブレークポイントジェネレータ
Responsive Image Breakpoints Generatorは、画像とマークアップの生成を自動化します。
  1. JPEG / PNG / SVGは適切に最適化されていますか?
    ヒーロー画像が非常に高速に読み込まれることが重要なランディングページで作業している場合は、JPEGがプログレッシブであり、mozJPEG(スキャンレベルを操作することでレンダリング開始時間を改善する)またはGoogleのオープンソースであるGuetzliで圧縮されていることを確認してください知覚パフォーマンスに焦点を当て、ZopfliとWebPからの学習を利用するエンコーダー。 唯一の欠点:処理時間が遅い(メガピクセルあたり1分のCPU)。

    PNGの場合はPingoを使用でき、SVGの場合はSVGOまたはSVGOMGを使用できます。 また、WebサイトからすべてのSVGアセットをすばやくプレビューしてコピーまたはダウンロードする必要がある場合は、svg-grabberでもそれを実行できます。

    すべての画像最適化の記事でそれが述べられていますが、ベクターアセットをクリーンでタイトに保つことは常に言及する価値があります。 未使用のアセットをクリーンアップし、不要なメタデータを削除し、アートワーク(したがってSVGコード)のパスポイントの数を減らしてください。 (ありがとう、ジェレミー!

    ただし、便利なオンラインツールもあります。

    • Squooshを使用して、最適な圧縮レベル(非可逆または可逆)で画像を圧縮、サイズ変更、および操作します。
    • Guetzli.itを使用して、GuetzliでJPEG画像を圧縮および最適化します。これは、シャープなエッジと単色の画像に適しています(ただし、かなり遅くなる可能性があります))。
    • Responsive Image Breakpoints GeneratorまたはCloudinaryやImgixなどのサービスを使用して、画像の最適化を自動化します。 また、多くの場合、 srcsetsizesだけを使用すると、大きなメリットが得られます。
    • レスポンシブマークアップの効率を確認するには、ビューポートサイズとデバイスのピクセル比全体の効率を測定するコマンドラインツールであるイメージングヒープを使用できます。
    • GitHubワークフローに自動画像圧縮を追加できるため、圧縮されていない状態で画像が本番環境に到達することはありません。 このアクションでは、PNGおよびJPGで機能するmozjpegおよびlibvipsを使用します。
    • ストレージを内部的に最適化するには、Dropboxの新しいLepton形式を使用して、JPEGを平均22%ロスレスで圧縮できます。
    • プレースホルダー画像を早く表示したい場合は、BlurHashを使用してください。 BlurHashは画像を取得し、この画像のプレースホルダーを表す短い文字列(20〜30文字のみ!)を提供します。 文字列は十分に短いため、JSONオブジェクトのフィールドとして簡単に追加できます。
    左側に画像プレースホルダーがない場合と右側にプレースホルダーがある場合のインターフェイスの比較
    BlurHashは、画像のプレースホルダーを小さくコンパクトに表現したものです。 (大プレビュー)

    画像を最適化するだけではうまくいかない場合があります。 重要な画像のレンダリングを開始するために必要な時間を改善するには、重要度の低い画像を遅延ロードし、重要な画像が既にレンダリングされた後にロードするスクリプトを延期します。 最も防弾の方法は、ハイブリッド遅延読み込みです。ネイティブの遅延読み込みとlazyloadを利用する場合、ユーザーの操作によってトリガーされる可視性の変化を検出するライブラリです(IntersectionObserverについては後で説明します)。 さらに:

    • 重要な画像をプリロードすることを検討してください。そうすれば、ブラウザはそれらを遅すぎて検出しません。 背景画像の場合、それよりもさらに積極的にしたい場合は、 <img src>を使用して画像を通常の画像として追加し、画面から非表示にすることができます。
    • メディアクエリに応じて異なる画像表示サイズを指定して、サイズ属性で画像を交換することを検討してください。たとえば、拡大鏡コンポーネントでソースを交換するためにsizesを操作します。
    • 前景画像と背景画像の予期しないダウンロードを防ぐために、画像のダウンロードの不整合を確認してください。 デフォルトで読み込まれるが、表示されない可能性のある画像(カルーセル、アコーディオン、画像ギャラリーなど)に注意してください。
    • 画像のwidthheightは必ず設定してください。 CSSのaspect-ratioプロパティとintrinsicsize属性に注意してください。これにより、画像のアスペクト比とサイズを設定できるため、ブラウザは事前定義されたレイアウトスロットを早期に予約して、ページの読み込み中にレイアウトがジャンプしないようにすることができます。
    エディターで使用されているパディングトップ要素とアスペクト比要素を示すコードのスクリーンショット
    ブラウザにアスペクト比が表示されるようになり、今では数週間または数か月の問題になるはずです。 Safariテクニカルプレビュー118ではすでに。 現在、FirefoxとChromeのフラグの背後にあります。 (大プレビュー)

    冒険心があれば、Edgeワーカー(基本的にはCDNにあるリアルタイムフィルター)を使用してHTTP / 2ストリームを切り刻み、再配置して、ネットワーク経由で画像をより高速に送信できます。 エッジワーカーは、制御可能なチャンクを使用するJavaScriptストリームを使用するため(基本的には、ストリーミング応答を変更できるCDNエッジで実行されるJavaScriptです)、画像の配信を制御できます。

    サービスワーカーの場合、ネットワーク上にあるものを制御できないため手遅れになりますが、エッジワーカーでは機能します。 したがって、特定のランディングページ用に段階的に保存された静的JPEGの上でそれらを使用できます。

    さまざまなビューポートサイズとデバイスのピクセル比の表を示すイメージングヒープコマンドラインツールのスクリーンショット
    ビューポートサイズとデバイスのピクセル比全体の効率を測定するコマンドラインツールであるイメージングヒープによるサンプル出力。 (画像ソース)(大きなプレビュー)

    十分じゃない? また、複数の背景画像の手法を使用して、画像の知覚パフォーマンスを向上させることもできます。 コントラストで遊んだり、不要な詳細をぼかしたり(または色を削除したり)すると、ファイルサイズも小さくなる可能性があることに注意してください。 ああ、品質を落とさずに小さな写真を拡大する必要がありますか? Letsenhance.ioの使用を検討してください。

    これまでのところ、これらの最適化は基本的なことだけをカバーしています。 Addy Osmaniは、画像圧縮とカラーマネジメントの詳細を深く掘り下げたEssential ImageOptimizationに関する非常に詳細なガイドを公開しています。 たとえば、画像の不要な部分を(ガウスぼかしフィルターを適用して)ぼかしてファイルサイズを小さくしたり、最終的には色を削除したり、画像を白黒に変えてサイズをさらに小さくしたりすることができます。 。 背景画像の場合、Photoshopから0〜10%の品質で写真をエクスポートすることも絶対に許容できます。

    Smashing Magazineでは、画像名に接尾辞-optを使用します—たとえば、 brotli-compression-opt.png ; 画像にその接尾辞が含まれている場合は常に、チームの全員が画像がすでに最適化されていることを知っています。

    ああ、WebでJPEG-XRを使用しないでください—「CPUでソフトウェア側のJPEG-XRをデコードする処理は無効になり、特にSPAのコンテキストでは、バイトサイズの節約による潜在的なプラスの影響を上回ります」( Cloudinary / GoogleのJPEGXLと混同することもあります)。

アニメーションGIFをビデオ要素に置き換えて80%以上節約
Addy Osmaniは、アニメーションGIFをループインラインビデオに置き換えることをお勧めします。 ファイルサイズの違いは顕著です(80%の節約)。 (大プレビュー)
  1. ビデオは適切に最適化されていますか?
    これまで画像について説明してきましたが、古き良きGIFについての会話は避けました。 私たちがGIFを愛しているにもかかわらず、(少なくとも私たちのWebサイトやアプリでは)GIFを永久に放棄する時が来ました。 レンダリングパフォーマンスと帯域幅の両方に影響を与える重いアニメーションGIFをロードする代わりに、アニメーションWebP(GIFはフォールバック)に切り替えるか、ループHTML5ビデオに完全に置き換えることをお勧めします。

    画像とは異なり、ブラウザは<video>コンテンツをプリロードしませんが、HTML5ビデオはGIFよりもはるかに軽量で小さい傾向があります。 オプションではありませんか? 少なくとも、不可逆GIF、gifsicle、またはgiflossyを使用してGIFに不可逆圧縮を追加できます。

    Colin Bendellによるテストでは、Safari Technology Previewのimgタグ内のインラインビデオは、ファイルサイズの一部であることに加えて、同等のGIFよりも少なくとも20倍速く、7倍速くデコードされることが示されています。 ただし、他のブラウザではサポートされていません。

    良いニュースの地では、ビデオフォーマットは何年にもわたって大幅に進歩しています。 長い間、WebMがそれらすべてを支配するフォーマットになり、WebP(基本的にはWebMビデオコンテナ内の1つの静止画像)が古い画像フォーマットの代わりになることを望んでいました。 確かに、Safariは現在WebPをサポートしていますが、最近WebPとWebMがサポートを獲得しているにもかかわらず、ブレークスルーは実際には起こりませんでした。

    それでも、最新のブラウザのほとんどにWebMを使用できます。

    <!-- By Houssein Djirdeh. https://web.dev/replace-gifs-with-videos/ --> <!-- A common scenartio: MP4 with a WEBM fallback. --> <video autoplay loop muted playsinline> <source src="my-animation.webm" type="video/webm"> <source src="my-animation.mp4" type="video/mp4"> </video>

    しかし、おそらく私たちはそれを完全に再考することができます。 2018年、Alliance of Open Mediaは、 AV1と呼ばれる新しい有望なビデオ形式をリリースしました。 AV1はH.265コーデック(H.264の進化形)と同様の圧縮を備えていますが、後者とは異なり、AV1は無料です。 H.265ライセンスの価格設定により、ブラウザベンダーは、代わりに同等のパフォーマンスを発揮するAV1を採用するようになりました。AV1(H.265と同様)は、WebMの2倍の圧縮率を実現します。

    AV1ロゴ2018
    AV1は、Web上のビデオの究極の標準になる可能性が高いです。 (画像クレジット:Wikimedia.org)(大プレビュー)

    実際、Appleは現在HEIF形式とHEVC(H.265)を使用しており、最新のiOSのすべての写真とビデオはJPEGではなくこれらの形式で保存されます。 HEIFとHEVC(H.265)は(まだ?)Webに適切に公開されていませんが、AV1は公開されており、ブラウザーのサポートを受けています。 したがって、すべてのブラウザベンダーが参加しているように見えるため、 <video>タグにAV1ソースを追加することは合理的です。

    現在、最も広く使用され、サポートされているエンコーディングはH.264であり、MP4ファイルによって提供されます。したがって、ファイルを提供する前に、MP4がマルチパスエンコーディングで処理され、frei0r iirblur効果(該当する場合)でぼやけていることを確認してください。サーバーがバイトサービングを受け入れている間、moovアトムメタデータはファイルの先頭に移動されます。 Boris Schapiraは、FFmpegがビデオを最大限に最適化するための正確な手順を提供します。 もちろん、代わりにWebM形式を提供することも役立ちます。

    ビデオのレンダリングをより速く開始する必要がありますが、ビデオファイルはまだ大きすぎますか? たとえば、ランディングページに大きな背景動画があるときはいつでも? 使用する一般的な手法は、最初に静止画像として最初のフレームを表示するか、ビデオの一部として解釈できる高度に最適化された短いループセグメントを表示してから、ビデオが十分にバッファリングされるたびに再生を開始することです。実際のビデオ。 Doug Sillarsは、その場合に役立つ可能性のあるバックグラウンドビデオパフォーマンスの詳細なガイドを作成しました。 (ありがとう、Guy Podjarny! )。

    上記のシナリオでは、レスポンシブポスター画像を提供することをお勧めします。 デフォルトでは、 video要素はポスターとして1つの画像のみを許可しますが、これは必ずしも最適ではありません。 レスポンシブビデオポスターを使用できます。これは、さまざまな画面にさまざまなポスター画像を使用できるJavaScriptライブラリであり、ビデオプレースホルダーのトランジションオーバーレイと完全なスタイリングコントロールも追加できます。

    調査によると、ビデオストリームの品質は視聴者の行動に影響を与えます。 実際、起動遅延が約2秒を超えると、視聴者は動画を放棄し始めます。 そのポイントを超えると、遅延が1秒増加すると、放棄率が約5.8%増加します。 したがって、ビデオの開始時間の中央値が12.8秒であり、ビデオの40%に少なくとも1つのストールがあり、20%に少なくとも2秒のビデオ再生が停止していることは驚くべきことではありません。 実際、ネットワークがコンテンツを提供できるよりも速くビデオが再生されるため、3Gではビデオのストールは避けられません。

    それで、解決策は何ですか? 通常、小さな画面のデバイスは、デスクトップに提供している720pと1080pを処理できません。 Doug Sillarsによると、ビデオの小さいバージョンを作成し、Javascriptを使用して小さい画面のソースを検出して、これらのデバイスでの高速でスムーズな再生を保証することができます。 または、ストリーミングビデオを使用することもできます。 HLSビデオストリームは、適切なサイズのビデオをデバイスに配信します。これにより、画面ごとに異なるビデオを作成する必要がなくなります。 また、ネットワーク速度をネゴシエートし、使用しているネットワークの速度に合わせてビデオビットレートを調整します。

    帯域幅の浪費を避けるために、実際にビデオをうまく再生できるデバイスのビデオソースのみを追加することができました。 または、 videoタグからautoplay属性を完全に削除し、JavaScriptを使用してより大きな画面のautoplayを挿入することもできます。 さらに、 videopreload="none"を追加して、実際にファイルが必要になるまでビデオファイルをダウンロードしないようにブラウザに指示する必要があります。

    <!-- Based on Doug Sillars's post. https://dougsillars.com/2020/01/06/hiding-videos-on-the-mbile-web/ --> <video preload="none" playsinline muted loop width="1920" height="1080" poster="poster.jpg"> <source src="video.webm" type="video/webm"> <source src="video.mp4" type="video/mp4"> </video>

    次に、AV1を実際にサポートするブラウザを具体的にターゲットにできます。

    <!-- Based on Doug Sillars's post. https://dougsillars.com/2020/01/06/hiding-videos-on-the-mbile-web/ --> <video preload="none" playsinline muted loop width="1920" height="1080" poster="poster.jpg"> <source src="video.av1.mp4" type="video/mp4; codecs=av01.0.05M.08"> <source src="video.hevc.mp4" type="video/mp4; codecs=hevc"> <source src="video.webm" type="video/webm"> <source src="video.mp4" type="video/mp4"> </video>

    次に、特定のしきい値( autoplayなど)を超えて自動再生を再度追加できます。

    /* By Doug Sillars. https://dougsillars.com/2020/01/06/hiding-videos-on-the-mbile-web/ */ <script> window.onload = addAutoplay(); var videoLocation = document.getElementById("hero-video"); function addAutoplay() { if(window.innerWidth > 1000){ videoLocation.setAttribute("autoplay",""); }; } </script>
    Alcatel 1X、Moto G、Moto G4、MotoE、Nexus 5、OnePlus 5の3G、ケーブル、LTE、ネイティブなど、デバイスとネットワークの速度ごとの小さなtme(ms)を示す棒グラフ
    デバイスおよびネットワーク速度ごとのストールの数。 より高速なネットワーク上のより高速なデバイスには、実質的にストールがありません。 ダグシラーズの調査によると。 (大プレビュー)

    ビデオ再生パフォーマンスはそれ自体がストーリーです。詳細を知りたい場合は、ビデオ配信メトリックの詳細を含む、ビデオおよびビデオ配信のベストプラクティスの現状に関する別のダグシラーズのシリーズをご覧ください。 、ビデオのプリロード、圧縮、ストリーミング。 最後に、StreamまたはNotを使用して、ビデオストリーミングがどの程度遅くなるかまたは速くなるかを確認できます。

マインドマップグラフとして表示されるZachLeathermanのフォント読み込み戦略に関する包括的なガイド
Zach Leathermanのフォント読み込み戦略に関する包括的なガイドには、Webフォントの配信を改善するための多数のオプションが用意されています。
  1. Webフォントの配信は最適化されていますか?
    The first question that's worth asking is if we can get away with using UI system fonts in the first place — we just need to make sure to double check that they appear correctly on various platforms. If it's not the case, chances are high that the web fonts we are serving include glyphs and extra features and weights that aren't being used. We can ask our type foundry to subset web fonts or if we are using open-source fonts, subset them on our own with Glyphhanger or Fontsquirrel. We can even automate our entire workflow with Peter Muller's subfont, a command line tool that statically analyses your page in order to generate the most optimal web font subsets, and then inject them into our pages.

    WOFF2 support is great, and we can use WOFF as fallback for browsers that don't support it — or perhaps legacy browsers could be served system fonts. There are many, many, many options for web font loading, and we can choose one of the strategies from Zach Leatherman's "Comprehensive Guide to Font-Loading Strategies," (code snippets also available as Web font loading recipes).

    Probably the better options to consider today are Critical FOFT with preload and "The Compromise" method. Both of them use a two-stage render for delivering web fonts in steps — first a small supersubset required to render the page fast and accurately with the web font, and then load the rest of the family async. The difference is that "The Compromise" technique loads polyfill asynchronously only if font load events are not supported, so you don't need to load the polyfill by default. Need a quick win? Zach Leatherman has a quick 23-min tutorial and case study to get your fonts in order.

    In general, it might be a good idea to use the preload resource hint to preload fonts, but in your markup include the hints after the link to critical CSS and JavaScript. With preload , there is a puzzle of priorities, so consider injecting rel="preload" elements into the DOM just before the external blocking scripts. According to Andy Davies, "resources injected using a script are hidden from the browser until the script executes, and we can use this behaviour to delay when the browser discovers the preload hint." Otherwise, font loading will cost you in the first render time.

    A screenshot of slide 93 showing two example of images with a title next to them saying ‘Metrics prioritization: preload one of each family’
    When everything is critical, nothing is critical. preload only one or a maximum of two fonts of each family. (Image credit: Zach Leatherman – slide 93) (Large preview)

    It's a good idea to be selective and choose files that matter most, eg the ones that are critical for rendering or that would help you avoiding visible and disruptive text reflows. In general, Zach advises to preload one or two fonts of each family — it also makes sense to delay some font loading if they are less critical.

    It has become quite common to use local() value (which refers to a local font by name) when defining a font-family in the @font-face rule:

     /* Warning! Not a good idea! */ @font-face { font-family: Open Sans; src: local('Open Sans Regular'), local('OpenSans-Regular'), url('opensans.woff2') format ('woff2'), url('opensans.woff') format('woff'); }

    The idea is reasonable: some popular open-source fonts such as Open Sans are coming pre-installed with some drivers or apps, so if the font is available locally, the browser doesn't need to download the web font and can display the local font immediately. As Bram Stein noted, "though a local font matches the name of a web font, it most likely isn't the same font . Many web fonts differ from their "desktop" version. The text might be rendered differently, some characters may fall back to other fonts, OpenType features can be missing entirely, or the line height may be different."

    Also, as typefaces evolve over time, the locally installed version might be very different from the web font, with characters looking very different. So, according to Bram, it's better to never mix locally installed fonts and web fonts in @font-face rules. Google Fonts has followed suit by disabling local() on the CSS results for all users, other than Android requests for Roboto.

    Nobody likes waiting for the content to be displayed. With the font-display CSS descriptor, we can control the font loading behavior and enable content to be readable immediately (with font-display: optional ) or almost immediately (with a timeout of 3s, as long as the font gets successfully downloaded — with font-display: swap ). (Well, it's a bit more complicated than that.)

    However, if you want to minimize the impact of text reflows, we could use the Font Loading API (supported in all modern browsers). Specifically that means for every font, we'd creata a FontFace object, then try to fetch them all, and only then apply them to the page. This way, we group all repaints by loading all fonts asynchronously, and then switch from fallback fonts to the web font exactly once. Take a look at Zach's explanation, starting at 32:15, and the code snippet):

    /* Load two web fonts using JavaScript */ /* Zach Leatherman: https://noti.st/zachleat/KNaZEg/the-five-whys-of-web-font-loading-performance#sWkN4u4 */ // Remove existing @font-face blocks // Create two let font = new FontFace("Noto Serif", /* ... */); let fontBold = new FontFace("Noto Serif, /* ... */); // Load two fonts let fonts = await Promise.all([ font.load(), fontBold.load() ]) // Group repaints and render both fonts at the same time! fonts.forEach(font => documents.fonts.add(font));
    /* Load two web fonts using JavaScript */ /* Zach Leatherman: https://noti.st/zachleat/KNaZEg/the-five-whys-of-web-font-loading-performance#sWkN4u4 */ // Remove existing @font-face blocks // Create two let font = new FontFace("Noto Serif", /* ... */); let fontBold = new FontFace("Noto Serif, /* ... */); // Load two fonts let fonts = await Promise.all([ font.load(), fontBold.load() ]) // Group repaints and render both fonts at the same time! fonts.forEach(font => documents.fonts.add(font));

    To initiate a very early fetch of the fonts with Font Loading API in use, Adrian Bece suggests to add a non-breaking space nbsp; at the top of the body , and hide it visually with aria-visibility: hidden and a .hidden class:

    <body class="no-js"> <!-- ... Website content ... --> <div aria-visibility="hidden" class="hidden"> <!-- There is a non-breaking space here --> </div> <script> document.getElementsByTagName("body")[0].classList.remove("no-js"); </script> </body>
    <body class="no-js"> <!-- ... Website content ... --> <div aria-visibility="hidden" class="hidden"> <!-- There is a non-breaking space here --> </div> <script> document.getElementsByTagName("body")[0].classList.remove("no-js"); </script> </body>

    This goes along with CSS that has different font families declared for different states of loading, with the change triggered by Font Loading API once the fonts have successfully loaded:

    body:not(.wf-merriweather--loaded):not(.no-js) { font-family: [fallback-system-font]; /* Fallback font styles */ } .wf-merriweather--loaded, .no-js { font-family: "[web-font-name]"; /* Webfont styles */ } /* Accessible hiding */ .hidden { position: absolute; overflow: hidden; clip: rect(0 0 0 0); height: 1px; width: 1px; margin: -1px; padding: 0; border: 0; }
    body:not(.wf-merriweather--loaded):not(.no-js) { font-family: [fallback-system-font]; /* Fallback font styles */ } .wf-merriweather--loaded, .no-js { font-family: "[web-font-name]"; /* Webfont styles */ } /* Accessible hiding */ .hidden { position: absolute; overflow: hidden; clip: rect(0 0 0 0); height: 1px; width: 1px; margin: -1px; padding: 0; border: 0; }

    If you ever wondered why despite all your optimizations, Lighthouse still suggests to eliminate render-blocking resources (fonts), in the same article Adrian Bece provides a few techniques to make Lighthouse happy, along with a Gatsby Omni Font Loader, a performant asynchronous font loading and Flash Of Unstyled Text (FOUT) handling plugin for Gatsby.

    Now, many of us might be using a CDN or a third-party host to load web fonts from. In general, it's always better to self-host all your static assets if you can, so consider using google-webfonts-helper, a hassle-free way to self-host Google Fonts. And if it's not possible, you can perhaps proxy the Google Font files through the page origin.

    It's worth noting though that Google is doing quite a bit of work out of the box, so a server might need a bit of tweaking to avoid delays ( thanks, Barry! )

    This is quite important especially as since Chrome v86 (released October 2020), cross-site resources like fonts can't be shared on the same CDN anymore — due to the partitioned browser cache. This behavior was a default in Safari for years.

    But if it's not possible at all, there is a way to get to the fastest possible Google Fonts with Harry Roberts' snippet:

    <!-- By Harry Roberts. https://csswizardry.com/2020/05/the-fastest-google-fonts/ - 1. Preemptively warm up the fonts' origin. - 2. Initiate a high-priority, asynchronous fetch for the CSS file. Works in - most modern browsers. - 3. Initiate a low-priority, asynchronous fetch that gets applied to the page - only after it's arrived. Works in all browsers with JavaScript enabled. - 4. In the unlikely event that a visitor has intentionally disabled - JavaScript, fall back to the original method. The good news is that, - although this is a render-blocking request, it can still make use of the - preconnect which makes it marginally faster than the default. --> <!-- [1] --> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <!-- [2] --> <link rel="preload" as="style" href="$CSS&display=swap" /> <!-- [3] --> <link rel="stylesheet" href="$CSS&display=swap" media="print" onload="this.media='all'" /> <!-- [4] --> <noscript> <link rel="stylesheet" href="$CSS&display=swap" /> </noscript>

    Harry's strategy is to pre-emptively warm up the fonts' origin first. Then we initiate a high-priority, asynchronous fetch for the CSS file. Afterwards, we initiate a low-priority, asynchronous fetch that gets applied to the page only after it's arrived (with a print stylesheet trick). Finally, if JavaScript isn't supported, we fall back to the original method.

    Ah, talking about Google Fonts: you can shave up to 90% of the size of Google Fonts requests by declaring only characters you need with &text . Plus, the support for font-display was added recently to Google Fonts as well, so we can use it out of the box.

    ただし、簡単に注意してください。 font-display: optionalを使用する場合、 preloadを使用すると、そのWebフォント要求が早期にトリガーされるため、最適ではない可能性があります(フェッチする必要のある他のクリティカルパスリソースがある場合、ネットワークの輻輳が発生します)。 クロスオリジンフォントリクエストを高速化するにはpreconnectを使用しますが、異なるオリジンwlllからフォントをpreloadするとネットワークの競合が発生するため、プリロードには注意してください。 これらのテクニックはすべて、ZachのWebフォント読み込みレシピでカバーされています。

    一方、ユーザーがユーザー補助設定で[モーションの削減]を有効にしている場合、またはデータセーバーモードを選択している場合は、Webフォント(または少なくとも第2段階のレンダリング)をオプトアウトすることをお勧めします([ Save-Data ]ヘッダーを参照)。 、またはユーザーの接続が遅い場合(Network Information API経由)。

    ユーザーがデータ保存モードを選択した場合は、 prefers-reduced-data CSSメディアクエリを使用してフォント宣言を定義しないこともできます(他のユースケースもあります)。 メディアクエリは基本的に、CSSでの使用を可能にするためにクライアントヒントHTTP拡張機能からのSave-Dataリクエストヘッダーがオン/オフであるかどうかを公開します。 現在、フラグの背後にあるChromeとEdgeでのみサポートされています。

    指標? Webフォントの読み込みパフォーマンスを測定するには、 All Text Visibleメトリック(すべてのフォントが読み込まれ、すべてのコンテンツがWebフォントで表示される瞬間)、Real Italicsまでの時間、および最初のレンダリング後のWebフォントのリフローカウントを考慮します。 明らかに、両方のメトリックが低いほど、パフォーマンスは向上します。

    可変フォントについてはどうですか? 可変フォントでは、パフォーマンスを大幅に考慮する必要がある場合があることに注意してください。 それらは活版印刷の選択のためのはるかに広いデザインスペースを私たちに与えます、しかしそれは多くの個々のファイル要求とは対照的に単一のシリアル要求の代償を伴います。

    可変フォントはフォントファイルの全体的な合計ファイルサイズを大幅に削減しますが、その単一の要求は遅く、ページ上のすべてのコンテンツのレンダリングをブロックする可能性があります。 したがって、フォントをサブセット化して文字セットに分割することは依然として重要です。 ただし、良い面としては、可変フォントを使用すると、デフォルトでリフローが1つだけ取得されるため、再描画をグループ化するためにJavaScriptは必要ありません。

    では、防弾Webフォントの読み込み戦略を立てるにはどうすればよいでしょうか。 フォントをサブセット化して2段階レンダリング用に準備し、 font-display記述子で宣言し、Font Loading APIを使用して再描画をグループ化し、永続的なServiceWorkerのキャッシュにフォントを保存します。 最初の訪問時に、ブロックする外部スクリプトの直前にスクリプトのプリロードを挿入します。 必要に応じて、BramSteinのFontFaceObserverにフォールバックできます。 また、フォント読み込みのパフォーマンスの測定に関心がある場合は、AndreasMarschkeがFontAPIとUserTimingAPIを使用したパフォーマンス追跡について説明します。

    最後に、 unicode-rangeを含めて、大きなフォントを小さな言語固有のフォントに分解し、Monica Dinculescuのfont-style-matcherを使用して、フォールバックとWebフォント。

    または、フォールバックフォントのWebフォントをエミュレートするには、@ font-face記述子を使用してフォントメトリックをオーバーライドします(デモ、Chrome 87で有効)。 (ただし、複雑なフォントスタックでは調整が複雑になることに注意してください。)

    未来は明るく見えますか? プログレッシブフォントエンリッチメントを使用すると、最終的には「任意のページでフォントの必要な部分のみをダウンロードし、その後のリクエストで、後続のページで必要に応じて元のダウンロードに追加のグリフセットを動的に「パッチ」することができるようになります。ジェイソン・パメンタルが説明しているように。 インクリメンタル転送デモはすでに利用可能であり、進行中です。

ビルドの最適化

  1. 優先順位を定義しましたか?
    最初に何を扱っているかを知っておくことをお勧めします。 すべてのアセット(JavaScript、画像、フォント、サードパーティスクリプト、およびカルーセル、複雑なインフォグラフィック、マルチメディアコンテンツなど、ページ上の「高価な」モジュール)のインベントリを実行し、それらをグループに分類します。

    スプレッドシートを設定します。 レガシーブラウザの基本的なコアエクスペリエンス(つまり、完全にアクセス可能なコアコンテンツ)、対応するブラウザの拡張エクスペリエンス(つまり、充実した完全なエクスペリエンス)、および追加機能(絶対に必要ではなく、遅延読み込みが可能なアセットなど)を定義します。 Webフォント、不要なスタイル、カルーセルスクリプト、ビデオプレーヤー、ソーシャルメディアウィジェット、大きな画像)。 数年前、このアプローチを詳細に説明した「SmashingMagazineのパフォーマンスの向上」に関する記事を公開しました。

    パフォーマンスを最適化するときは、優先順位を反映する必要があります。 コアエクスペリエンスをすぐにロードし、次に拡張機能、次に追加機能をロードします。

  2. 本番環境でネイティブJavaScriptモジュールを使用していますか?
    コアエクスペリエンスをレガシーブラウザに送信し、拡張エクスペリエンスを最新のブラウザに送信するための古き良きマスタードテクニックを覚えていますか? この手法の更新されたバリアントは、ES2017 + <script type="module">を使用できます。これは、module / nomoduleパターンとも呼ばれます(Jeremy Wagnerによって差分サービングとしても導入されています)。

    アイデアは、 2つの別々のJavaScriptバンドルをコンパイルして提供することです。「通常の」ビルド、Babel変換とポリフィルを使用して、実際にそれらを必要とするレガシーブラウザーにのみ提供するものと、変換または変換を持たない別のバンドル(同じ機能)です。ポリフィル。

    その結果、ブラウザが処理する必要のあるスクリプトの量を減らすことで、メインスレッドのブロックを減らすことができます。 Jeremy Wagnerは、ディファレンシャルサービングと、Babelのセットアップから、Webpackで行う必要のある微調整まで、ビルドパイプラインでのセットアップ方法、およびこれらすべての作業を行うことの利点に関する包括的な記事を公開しています。

    ネイティブJavaScriptモジュールスクリプトはデフォルトで延期されているため、HTML解析が行われている間、ブラウザはメインモジュールをダウンロードします。

    ネイティブJavaScriptモジュールがデフォルトでどのように延期されるかを示す例
    ネイティブJavaScriptモジュールはデフォルトで延期されます。 ネイティブJavaScriptモジュールに関するほとんどすべて。 (大プレビュー)

    ただし、警告の1つの注意: module / nomoduleパターンは一部のクライアントで逆効果になる可能性があるため、回避策を検討することをお勧めします:Jeremyのリスクの低い差動サービングパターン。ただし、プリロードスキャナーを回避し、パフォーマンスに影響を与える可能性があります。予想。 (ありがとう、ジェレミー!

    実際、Rollupは出力形式としてモジュールをサポートしているため、コードをバンドルすることも、本番環境にモジュールをデプロイすることもできます。 ParcelはParcel2でモジュールをサポートしています。Webpackの場合、module-nomodule-pluginはmodule / nomoduleスクリプトの生成を自動化します。

    :機能の検出だけでは、そのブラウザーに出荷するペイロードについて十分な情報に基づいた決定を下すのに十分ではないことを述べる価値があります。 それ自体では、ブラウザのバージョンからデバイスの機能を推測することはできません。 たとえば、発展途上国の安価なAndroidスマートフォンは、ほとんどがChromeを実行しており、メモリとCPUの機能が限られているにもかかわらず、マスタードを削減します。

    最終的には、デバイスメモリクライアントヒントヘッダーを使用して、ローエンドデバイスをより確実にターゲティングできるようになります。 執筆時点では、ヘッダーはBlinkでのみサポートされています(一般的にクライアントヒントに使用されます)。 デバイスメモリにはChromeで利用可能なJavaScriptAPIもあるため、1つのオプションは、APIに基づいて機能を検出し、サポートされていない場合はmodule / nomoduleパターンにフォールバックすることです(ありがとう、Yoav! )。

  3. ツリーシェイク、スコープホイスト、コード分割を使用していますか?
    ツリーシェーキングは、本番環境で実際に使用されるコードのみを含めてビルドプロセスをクリーンアップし、Webpackで未使用のインポートを排除する方法です。 WebpackとRollupを使用すると、コードを危険にさらすことなく、両方のツールでimportチェーンをフラット化して1つのインライン関数に変換できる場所を検出できるスコープホイストも利用できます。 Webpackでは、JSONツリーシェイクも使用できます。

    コード分​​割は、コードベースをオンデマンドでロードされる「チャンク」に分割するもう1つのWebpack機能です。 すべてのJavaScriptをすぐにダウンロード、解析、コンパイルする必要はありません。 コードで分割点を定義すると、Webpackは依存関係と出力されたファイルを処理できます。 これにより、最初のダウンロードを小さく保ち、アプリケーションから要求されたときにオンデマンドでコードを要求できます。 Alexander Kondrovが、WebpackとReactを使用したコード分割のすばらしい紹介をしています。

    コード分​​割したルートを取得し、 <link rel="preload">または<link rel="prefetch">を使用してルートをプリロードするようにブラウザに指示するpreload-webpack-pluginの使用を検討してください。 Webpackインラインディレクティブは、 preload / prefetchをある程度制御することもできます。 (ただし、優先順位の問題には注意してください。)

    分割点をどこで定義しますか? CSS / JavaScriptのどのチャンクが使用され、どのチャンクが使用されていないかを追跡する。 Umar Hansaが、Devtoolsのコードカバレッジを使用してそれを実現する方法について説明します。

    シングルページアプリケーションを扱う場合、ページをレンダリングする前にアプリを初期化するのに少し時間がかかります。 設定にはカスタムソリューションが必要ですが、初期レンダリング時間を短縮するためのモジュールとテクニックに注意することができます。 たとえば、Reactのパフォーマンスをデバッグし、一般的なReactのパフォーマンスの問題を排除する方法と、Angularのパフォーマンスを向上させる方法を次に示します。 一般に、ほとんどのパフォーマンスの問題は、アプリをブートストラップする最初の時間から発生します。

    では、積極的にコード分割するが、あまり積極的にしないための最良の方法は何でしょうか? Phil Waltonによると、「動的インポートによるコード分割に加えて、パッケージレベルでコード分割を使用することもできます。この場合、インポートされた各ノードモジュールは、パッケージの名前に基づいてチャンクに入れられます。」 Philは、それを構築する方法についてのチュートリアルも提供しています。

  4. Webpackの出力を改善できますか?
    Webpackは不思議なものと見なされることが多いため、Webpackの出力をさらに削減するのに役立つWebpackプラグインがたくさんあります。 以下は、もう少し注意が必要な、よりあいまいなもののいくつかです。

    興味深いものの1つは、IvanAkulovのスレッドからのものです。 一度呼び出した関数があり、その結果を変数に格納してから、その変数を使用しないと想像してください。 ツリーシェイクは変数を削除しますが、他の方法で使用される可能性があるため、関数は削除されませ。 ただし、この関数がどこにも使用されていない場合は、削除することをお勧めします。 これを行うには、関数呼び出しの前に/*#__PURE__*/を追加します。これは、UglifyとTerserでサポートされています—完了です。

    PURE関数の使用方法を示すエディター内のJSコードのスクリーンショット
    結果が使用されていないときにそのような関数を削除するには、関数呼び出しの前に/*#__PURE__*/を付けます。 Ivan Akulov経由(大プレビュー)

    Ivanが推奨するその他のツールのいくつかを次に示します。

    • 特にBootstrapまたはTailwindを使用している場合、purgecss-webpack-pluginは未使用のクラスを削除します。
    • 最適化を有効にしoptimization.splitChunks: 'all' withsplit-chunks-plugin。 これにより、webpackはエントリバンドルを自動的にコード分割して、キャッシュを改善します。
    • 設定optimization.runtimeChunk: true 。 これにより、webpackのランタイムが別のチャンクに移動し、キャッシュも改善されます。
    • google-fonts-webpack-pluginはフォントファイルをダウンロードするので、サーバーからそれらを提供できます。
    • workbox-webpack-pluginを使用すると、すべてのwebpackアセットの事前キャッシュ設定を使用してServiceWorkerを生成できます。 また、すぐに適用できるモジュールの包括的なガイドであるService WorkerPackagesも確認してください。 または、preload-webpack-pluginを使用して、すべてのJavaScriptチャンクのpreload / prefetchを生成します。
    • speed-measure-webpack-pluginは、webpackのビルド速度を測定し、ビルドプロセスのどのステップに最も時間がかかるかについての洞察を提供します。
    • バンドルに同じパッケージの複数のバージョンが含まれている場合、duplicate-package-checker-webpack-pluginは警告します。
    • スコープの分離を使用し、コンパイル時にCSSクラス名を動的に短縮します。

レスポンシブローダーという名前のウェブパックローダーを使用して、箱から出してレスポンシブ画像を生成する方法を示す端末のスクリーンショット
画像の速度を上げるには、小さい画面に小さい画像を表示します。 レスポンシブローダー付き。 IvanAkulov経由。 (大プレビュー)
  1. JavaScriptをWebワーカーにオフロードできますか?
    Time-to-Interactiveへの悪影響を減らすために、重いJavaScriptをWebワーカーにオフロードすることを検討することをお勧めします。

    コードベースが成長し続けると、UIパフォーマンスのボトルネックが発生し、ユーザーエクスペリエンスが低下します。 これは、DOM操作がメインスレッドでJavaScriptと並行して実行されているためです。 Webワーカーを使用すると、これらの高価な操作を、別のスレッドで実行されているバックグラウンドプロセスに移動できます。 Webワーカーの一般的な使用例は、データのプリフェッチとプログレッシブWebアプリで、必要なときに後で使用できるように、事前にデータを読み込んで保存します。 また、Comlinkを使用して、メインページとワーカー間の通信を合理化できます。 まだやるべきことがいくつかありますが、私たちはそこに到達しています。

    フレームワークとアプリロジックをWebワーカーに移動するさまざまなアプローチを示す、Webワーカーに関する興味深いケーススタディがいくつかあります。 結論:一般的に、まだいくつかの課題がありますが、すでにいくつかの良いユースケースがあります(ありがとう、Ivan Akulov! )。

    Chrome 80から、JavaScriptモジュールのパフォーマンス上の利点を備えたWebワーカー用の新しいモードが出荷されました。これはモジュールワーカーと呼ばれます。 スクリプトの読み込みと実行をscript type="module"に一致するように変更できます。さらに、ワーカーの実行をブロックせずに、遅延読み込みコードに動的インポートを使用することもできます。

    どうやって始めるのか? 調べる価値のあるいくつかのリソースを次に示します。

    • Surmaは、ブラウザーのメインスレッドからJavaScriptを実行する方法と、Webワーカーをいつ使用する必要があるかについての優れたガイドを公開しています。
    • また、メインスレッドアーキテクチャから離れたSurmaの話を確認してください。
    • ShubhiePanickerとJasonMillerによる応答性を保証するためのクエストは、Webワーカーの使用方法と、それらを回避するタイミングについての詳細な洞察を提供します。
    • ユーザーの邪魔にならないようにする:Webワーカーのジャンクを減らすWebワーカーを操作するための便利なパターン、ワーカー間の通信、メインスレッドからの複雑なデータ処理の処理、テストとデバッグの効果的な方法を紹介します。
    • Workerizeを使用すると、モジュールをWebワーカーに移動して、エクスポートされた関数を非同期プロキシとして自動的に反映できます。
    • Webpackを使用している場合は、workerize-loaderを使用できます。 または、worker-pluginを使用することもできます。
    Webワーカーを使用するときに使用するものと避けるべきものの例として左側に示されているDOMのコード
    コードが長時間ブロックされる場合はWebワーカーを使用しますが、DOMに依存し、入力応答を処理し、遅延を最小限に抑える必要がある場合は、Webワーカーを使用しないでください。 (Addy Osmani経由)(大プレビュー)

    DOMは「スレッドセーフ」ではないため、WebワーカーはDOMにアクセスできず、実行するコードは別のファイルに含める必要があることに注意してください。

  2. 「ホットパス」をWebAssemblyにオフロードできますか?
    計算量の多いタスクをWebAssembly( WASM )にオフロードできます。これは、C / C ++ / Rustなどの高級言語をコンパイルするためのポータブルターゲットとして設計されたバイナリ命令フォーマットです。 そのブラウザのサポートは注目に値し、JavaScriptとWASM間の関数呼び出しが高速化するにつれて、最近実行可能になりました。 さらに、Fastlyのエッジクラウドでもサポートされています。

    もちろん、WebAssemblyはJavaScriptに取って代わるものではありませんが、CPUの占有に気付いた場合にJavaScriptを補完することができます。 ほとんどのWebアプリでは、JavaScriptの方が適しています。また、WebAssemblyは、ゲームなどの計算量の多いWebアプリに最適です。

    WebAssemblyについて詳しく知りたい場合は、次のようにします。

    • Lin ClarkはWebAssemblyに徹底的なシリーズを書き、Milica Mihajlijaは、ブラウザーでネイティブコードを実行する方法、それを実行する理由、JavaScriptとWeb開発の将来にとってそれが何を意味するかについての一般的な概要を説明します。
    • WebAssemblyを使用してWebアプリを20倍高速化する方法(ケーススタディ)では、JavaScriptの計算がコンパイルされたWebAssemblyに置き換えられ、パフォーマンスが大幅に向上したケーススタディを紹介しています。
    • Patrick Hamannは、WebAssemblyの役割の拡大について語っています。彼は、WebAssemblyに関するいくつかの神話を暴き、その課題を探り、今日のアプリケーションで実際に使用できるようにしています。
    • Google Codelabsは、WebAssemblyの概要を提供します。このコースでは、ネイティブコードをCで取得し、WebAssemblyにコンパイルして、JavaScriptから直接呼び出す方法を学習します。
    • Alex Daniloは、WebAssemblyと、それがGoogle I / Oトークでどのように機能するかを説明しました。 また、Benedek Gagyiは、WebAssemblyに関する実用的なケーススタディ、具体的には、チームがiOS、Android、およびWebサイトへのC ++コードベースの出力形式としてWebAssemblyをどのように使用するかを共有しました。

    GPUにアクセスするためにWebワーカー、Webアセンブリ、ストリーム、またはおそらくWebGL JavaScript APIをいつ使用するかについてまだわかりませんか? JavaScriptの高速化は、何をいつ使用するのか、そしてその理由を説明する短いが役立つガイドです。また、便利なフローチャートと豊富な有用なリソースが含まれています。

左側に示されているC ++、C、またはRustの図で、JavaScript、CSS、およびHTMLに追加されたWASMバイナリを含むブラウザーを示す矢印が付いています。
Milica Mihajlijaが、WebAssemblyの仕組みとその有用性の概要を説明します。 (大プレビュー)
  1. レガシーコードをレガシーブラウザにのみ提供しますか?
    ES2017は最新のブラウザーで非常によくサポートされているため、 babelEsmPluginを使用して、対象の最新のブラウザーでサポートされていないES2017 +機能のみをトランスパイルできます。

    HousseinDjirdehとJasonMillerは最近、最新およびレガシーのJavaScriptをトランスパイルして提供する方法、WebpackとRollupで動作させる方法、および必要なツールに関する包括的なガイドを公開しました。 また、サイトまたはアプリバンドルで削減できるJavaScriptの量を見積もることもできます。

    JavaScriptモジュールはすべての主要なブラウザでサポートされているため、 script type="module"を使用して、ESモジュールをサポートするブラウザがファイルをロードできるようにします。古いブラウザはscript nomoduleを使用してレガシービルドをロードできます。

    最近では、トランスパイラーやバンドラーを使用せずに、ブラウザーでネイティブに実行されるモジュールベースのJavaScriptを作成できます。 <link rel="modulepreload">ヘッダーは、モジュールスクリプトの早期(および優先度の高い)ロードを開始する方法を提供します。 基本的に、これは帯域幅の使用量を最大化するのに役立つ便利な方法です。ブラウザにフェッチする必要があるものを通知して、長いラウンドトリップ中に何もする必要がないようにします。 また、Jake Archibaldは、ESモジュールで覚えておくべき落とし穴や注意事項を含む詳細な記事を公開しています。これは読む価値があります。

インラインスクリプトは、外部スクリプトをブロックしてインラインスクリプトが実行されるまで延期されます
Jake Archibaldは、ESモジュールで注意すべき点と注意事項を含む詳細な記事を公開しました。たとえば、インラインスクリプトは、外部スクリプトとインラインスクリプトが実行されるまで延期されます。 (大プレビュー)
  1. インクリメンタルデカップリングを使用してレガシーコードを特定して書き直します
    長期にわたるプロジェクトは、ほこりや古いコードを収集する傾向があります。 依存関係を再検討し、最近問題を引き起こしているレガシーコードをリファクタリングまたはリライトするために必要な時間を評価します。 もちろん、それは常に大きな仕事ですが、レガシーコードの影響を理解したら、インクリメンタルデカップリングから始めることができます。

    まず、レガシーコード呼び出しの比率が一定のままであるか、上昇ではなく下降しているかを追跡するメトリックを設定します。 チームがライブラリを使用することを公に阻止し、ライブラリがプルリクエストで使用されている場合はCIが開発者に警告するようにします。 ポリフィルは、レガシーコードから標準のブラウザ機能を使用する書き直されたコードベースへの移行に役立つ可能性があります。

  2. 未使用のCSS / JSを特定して削除します。
    ChromeのCSSおよびJavaScriptコードカバレッジにより、実行/適用されたコードと実行されていないコードを知ることができます。 カバレッジの記録を開始し、ページでアクションを実行してから、コードカバレッジの結果を調べることができます。 未使用のコードを検出したら、 import()を使用してそれらのモジュールと遅延読み込みを見つけます(スレッド全体を参照)。 次に、カバレッジプロファイルを繰り返し、初期ロードで出荷されるコードが少なくなっていることを確認します。

    Puppeteerを使用して、プログラムでコードカバレッジを収集できます。 Chromeでは、コードカバレッジの結果をエクスポートすることもできます。 Andy Daviesが指摘したように、最新のブラウザと従来のブラウザの両方のコードカバレッジを収集することをお勧めします。

    もう少し露出が必要なPuppetterのユースケースとツールは他にもたくさんあります。

    • Puppeteerのユースケース。たとえば、自動視覚的差分や、ビルドごとの未使用のCSSの監視など。
    • Puppeteerを使用したWebパフォーマンスレシピ、
    • PupeeteerおよびPlaywrightスクリプトを記録および生成するための便利なツール、
    • さらに、DevToolsでテストを直接記録することもできます。
    • Nitay NeemanによるPuppeteerの包括的な概要と、例と使用例。
    左側にPupeteerRecorderのスクリーンショット、右側にPuppeteerSandboxのスクリーンショットを示します。
    PuppeteerRecorderとPuppeteerSandboxを使用して、ブラウザーの操作を記録し、PuppeteerとPlaywrightのスクリプトを生成できます。 (大プレビュー)

    さらに、purgecss、UnCSS、およびHeliumは、CSSから未使用のスタイルを削除するのに役立ちます。 また、疑わしいコードがどこかで使用されているかどうかわからない場合は、ハリーロバーツのアドバイスに従うことができます。特定のクラス用に1×1pxの透明なGIFを作成し、それをdead/ディレクトリ(例: /assets/img/dead/comments.gif )にドロップします。 /assets/img/dead/comments.gif

    その後、その特定の画像をCSSの対応するセレクターの背景として設定し、ファイルがログに表示される場合は、数か月待ってください。 エントリがない場合、そのレガシーコンポーネントが画面に表示されることはありません。おそらく、先に進んですべてを削除することができます。

    I-feel-adventurous -departmentの場合、DevToolsを使用してDevToolsを監視することにより、一連のページから未使用のCSSの収集を自動化することもできます。

Webpack比較表
彼の記事で、Benedikt Rotschは、Moment.jsからdate-fnsに切り替えると、3Gおよびローエンドの携帯電話のFirstpaintで約300ms短縮できることを示しました。 (大プレビュー)
  1. JavaScriptバンドルのサイズをトリミングします。
    Addy Osmaniが指摘したように、必要なのがほんの一部である場合に完全なJavaScriptライブラリを出荷する可能性が高く、それらを必要としないブラウザ用の古いポリフィル、または単にコードを複製するだけです。 オーバーヘッドを回避するには、ビルドプロセス中に未使用のメソッドとポリフィルを削除するwebpack-libs-optimizationsの使用を検討してください。

    従来のブラウザーと最新のブラウザーに送信しているポリフィルを確認して確認し、それらについてより戦略的にします。 polyfill.ioを見てください。これは、一連のブラウザー機能の要求を受け入れ、要求しているブラウザーに必要なポリフィルのみを返すサービスです。

    バンドル監査を通常のワークフローにも追加します。 数年前に追加した重いライブラリに代わる軽量の代替手段があるかもしれません。たとえば、Moment.js(現在は廃止されています)を次のように置き換えることができます。

    • ネイティブ国際化API、
    • おなじみのMoment.jsAPIとパターンを備えたDay.js、
    • date-fnsまたは
    • ルクソン。
    • 人間がレビューしたパッケージの推奨事項と品質重視の検索を組み合わせたSkypackDiscoverを使用することもできます。

    Benedikt Rotschの調査によると、Moment.jsからdate-fnsに切り替えると、3Gおよびローエンドの携帯電話のFirstpaintで約300ミリ秒短縮できることがわかりました。

    バンドル監査の場合、Bundlephobiaはnpmパッケージをバンドルに追加するコストを見つけるのに役立ちます。 size-limitは、JavaScriptの実行時間の詳細を使用して、基本的なバンドルサイズチェックを拡張します。 これらのコストをLighthouseCustomAuditと統合することもできます。 これはフレームワークにも当てはまります。 Vue MDCアダプター(Vueのマテリアルコンポーネント)を削除またはトリミングすることにより、スタイルは194KBから10KBに低下します。

    依存関係と実行可能な代替案の影響について情報に基づいた決定を下すのに役立つ、さらに多くのツールがあります。

    • webpack-bundle-analyzer
    • ソースマップエクスプローラー
    • バンドルバディ
    • バンドル恐怖症
    • Webpackの分析は、特定のモジュールがバンドルに含まれている理由を示しています。
    • bundle-wizardは、ページ全体の依存関係のマップも作成します。
    • Webpackサイズ-プラグイン
    • VisualCodeのインポートコスト

    フレームワーク全体を出荷する代わりに、フレームワークをトリミングして、追加のコードを必要としない生のJavaScriptバンドルにコンパイルすることもできます。 Svelteはそれを実行し、ビルド時にReact.jsコンポーネントをネイティブDOM操作に変換するRawactBabelプラグインも実行します。 なんで? メンテナが説明するように、「react-domには、インクリメンタルレンダリング、スケジューリング、イベント処理などのコードを含む、レンダリング可能なすべてのコンポーネント/ HTMLElementのコードが含まれています。ただし、これらすべての機能を必要としないアプリケーションがあります(最初はページの読み込み)。このようなアプリケーションの場合、ネイティブDOM操作を使用してインタラクティブなユーザーインターフェイスを構築するのが理にかなっている場合があります。」

size-limitは、JavaScriptの実行時間の詳細を含む基本的なバンドルサイズチェックを提供します
size-limitは、JavaScriptの実行時間の詳細を含む基本的なバンドルサイズチェックを提供します。 (大プレビュー)
  1. 部分的な水分補給を使用しますか?
    アプリケーションで使用されるJavaScriptの量を考えると、クライアントへの送信をできるだけ少なくする方法を見つける必要があります。 そのための1つの方法は、部分的な水和を使用することです。 考え方は非常に単純です。SSRを実行してからアプリ全体をクライアントに送信する代わりに、アプリのJavaScriptのごく一部だけをクライアントに送信してからハイドレイトします。 それは、静的なWebサイト上に複数のレンダリングルートを持つ複数の小さなReactアプリと考えることができます。

    「部分的な水分補給の場合(NextとPreactを使用)」の記事で、Lukas Bombachは、ドイツの報道機関の1つであるWelt.deの背後にあるチームが部分的な水分補給でより良いパフォーマンスを達成した方法を説明しています。 説明とコードスニペットを使用して、次の超高性能GitHubリポジトリを確認することもできます。

    別のオプションを検討することもできます。

    • Preactと11による部分的な水分補給、
    • React GitHubリポジトリでのプログレッシブハイドレーション、
    • Vue.js(GitHubリポジトリ)での怠惰な水分補給、
    • インタラクションパターンをインポートして、ユーザーがそれを必要とするUIとインタラクションするときに、重要ではないリソース(コンポーネント、埋め込みなど)を遅延ロードします。

    Jason Millerは、Reactを使用してプログレッシブハイドレーションを実装する方法に関する実用的なデモを公開しているため、すぐに使用できます:デモ1、デモ2、デモ3(GitHubでも入手可能)。 さらに、react-prerendered-componentライブラリを調べることができます。

    Googleドキュメントのloadshare()で+ 485KBのJavaScript
    ファーストパーティコードのインポートオンインタラクションは、インタラクションの前にリソースをプリフェッチできない場合にのみ実行する必要があります。 (大プレビュー)
  2. React / SPAの戦略を最適化しましたか?
    シングルページアプリケーションアプリケーションのパフォーマンスに苦労していますか? Jeremy Wagnerは、クライアント側のフレームワークのパフォーマンスがさまざまなデバイスに与える影響を調査し、使用するときに知っておく必要のある影響とガイドラインのいくつかを強調しました。

    その結果、JeremyがReactフレームワークに使用することを提案しているSPA戦略は次のとおりです(ただし、他のフレームワークでは大幅に変更されるべきではありません)。

    • 可能な限り、ステートフルコンポーネントをステートレスコンポーネントとしてリファクタリングします。
    • サーバーの応答時間を最小限に抑えるために、可能な場合はステートレスコンポーネントを事前レンダリングします。 サーバー上でのみレンダリングします。
    • 単純な対話性を持つステートフルコンポーネントの場合、そのコンポーネントを事前レンダリングまたはサーバーレンダリングすることを検討し、その対話性をフレームワークに依存しないイベントリスナーに置き換えます。
    • クライアントでステートフルコンポーネントをハイドレイトする必要がある場合は、可視性または相互作用にレイジーハイドレーションを使用します。
    • 遅延水和コンポーネントの場合、 requestIdleCallbackを使用して、メインスレッドのアイドル時間中に水和をスケジュールします。

    あなたが追求またはレビューしたいと思うかもしれない他のいくつかの戦略があります:

    • ReactアプリでのCSS-in-JSのパフォーマンスに関する考慮事項
    • 動的インポートと遅延ハイドレーションを使用して、必要な場合にのみポリフィルをロードすることにより、Next.jsバンドルサイズを減らします。
    • JavaScriptの秘密:React、パフォーマンスの最適化、マルチスレッドの物語、Reactによるユーザーインターフェイスの課題の改善に関する7部構成の長いシリーズ、
    • Reactのパフォーマンスを測定する方法とReactアプリケーションをプロファイリングする方法。
    • ReactでモバイルファーストのWebアニメーションを構築します。これは、Alex Holachekによる素晴らしい講演であり、スライドとGitHubリポジトリも含まれています(ヒントをありがとう、Addy! )。
    • webpack-libs-optimizationsは、Webpack固有のパフォーマンス関連の最適化が豊富に用意された素晴らしいGitHubリポジトリです。 IvanAkulovによって維持されています。
    • NotionでのReactパフォーマンスの向上、Reactでのパフォーマンスを向上させる方法に関するIvan Akulovによるガイド、アプリを約30%高速化するための便利なポインターがたくさんあります。
    • React Refresh Webpackプラグイン(実験的)は、コンポーネントの状態を保持し、フックと関数コンポーネントをサポートするホットリロードを可能にします。
    • バンドルサイズに影響を与えない、新しく提案された種類のコンポーネントである、バンドルサイズがゼロのReactサーバーコンポーネントに注意してください。 プロジェクトは現在開発中ですが、コミュニティからのフィードバックは大歓迎です(ソフィーアルパートによる素晴らしい説明者)。
  3. JavaScriptチャンクに予測プリフェッチを使用していますか?
    ヒューリスティックを使用して、JavaScriptチャンクをプリロードするタイミングを決定できます。 Guess.jsは、Google Analyticsデータを使用して、ユーザーが特定のページから次にアクセスする可能性が最も高いページを判別するツールとライブラリのセットです。 Guess.jsは、Google Analyticsまたはその他のソースから収集されたユーザーナビゲーションパターンに基づいて、後続の各ページで必要となるJavaScriptを予測およびプリフェッチするための機械学習モデルを構築します。

    したがって、すべてのインタラクティブ要素はエンゲージメントの確率スコアを受け取り、そのスコアに基づいて、クライアント側のスクリプトは事前にリソースをプリフェッチすることを決定します。 この手法をNext.jsアプリケーションであるAngularとReactに統合できます。また、セットアッププロセスを自動化するWebpackプラグインもあります。

    明らかに、不要なデータを消費して望ましくないページをプリフェッチするようにブラウザに促す可能性があるため、プリフェッチされるリクエストの数をかなり控えめにすることをお勧めします。 良い使用例は、チェックアウトに必要な検証スクリプトのプリフェッチ、または重要な召喚状がビューポートに入ったときの投機的なプリフェッチです。

    より洗練されていないものが必要ですか? DNStradamusは、ビューポートに表示されるアウトバウンドリンクのDNSプリフェッチを実行します。 Quicklink、InstantClick、Instant.pageは、次のページのナビゲーションの読み込みを高速化するために、アイドル時にビューポートのリンクを自動的にプリフェッチする小さなライブラリです。 クイックリンクを使用すると、ReactルーターのルートとJavascriptをプリフェッチできます。 さらに、データを考慮しているため、2Gでプリフェッチしたり、 Data-Saverがオンになっている場合はプリフェッチしません。 モードがビューポートプリフェッチ(デフォルト)を使用するように設定されている場合、Instant.pageも同様です。

    予測プリフェッチの科学を詳細に調べたい場合は、Divya Tagtachianが、The Art of Predictive Prefetchについて、最初から最後まですべてのオプションをカバーする素晴らしい講演を行っています。

  4. ターゲットJavaScriptエンジンの最適化を利用します。
    ユーザーベースでJavaScriptエンジンが支配的であるものを調べてから、それらを最適化する方法を探ります。 たとえば、Blink-browsers、Node.jsランタイム、Electronで使用されるV8を最適化する場合は、モノリシックスクリプトのスクリプトストリーミングを利用します。

    スクリプトストリーミングを使用すると、ダウンロードが開始されると、 asyncまたはdefer scriptsを別のバックグラウンドスレッドで解析できるため、場合によっては、ページの読み込み時間が最大10%向上します。 Practically, use <script defer> in the <head> , so that the browsers can discover the resource early and then parse it on the background thread.

    Caveat : Opera Mini doesn't support script deferment, so if you are developing for India or Africa, defer will be ignored, resulting in blocking rendering until the script has been evaluated (thanks Jeremy!) .

    You could also hook into V8's code caching as well, by splitting out libraries from code using them, or the other way around, merge libraries and their uses into a single script, group small files together and avoid inline scripts. Or perhaps even use v8-compile-cache.

    When it comes to JavaScript in general, there are also some practices that are worth keeping in mind:

    • Clean Code concepts for JavaScript, a large collection of patterns for writing readable, reusable, and refactorable code.
    • You can Compress data from JavaScript with the CompressionStream API, eg to gzip before uploading data (Chrome 80+).
    • Detached window memory leaks and Fixing memory leaks in web apps are detailed guides on how to find and fix tricky JavaScript memory leaks. Plus, you can use queryObjects(SomeConstructor) from the DevTools Console ( thanks, Mathias! ).
    • Reexports are bad for loading and runtime performance, and avoiding them can help reduce the bundle size significantly.
    • We can improve scroll performance with passive event listeners by setting a flag in the options parameter. So browsers can scroll the page immediately, rather than after the listener has finished. (via Kayce Basques).
    • If you have any scroll or touch* listeners, pass passive: true to addEventListener. This tells the browser you're not planning to call event.preventDefault() inside, so it can optimize the way it handles these events. (via Ivan Akulov)
    • We can achieve better JavaScript scheduling with isInputPending(), a new API that attempts to bridge the gap between loading and responsiveness with the concepts of interrupts for user inputs on the web, and allows for JavaScript to be able to check for input without yielding to the browser.
    • You can also automatically remove an event listener after it has executed.
    • Firefox's recently released Warp, a significant update to SpiderMonkey (shipped in Firefox 83), Baseline Interpreter and there are a few JIT Optimization Strategies available as well.
An illustration to help you understand time loading and responsiveness
A blue banner showing running JS with white lines in regular gaps representing the time when we proactively check whether there’s user input without incurring the overhead of yielding execution to the browser and back
isInputPending() is a new browser API that attempts to bridge the gap between loading and responsiveness.(Large preview)
An illustration of a map showing the chain of each request to different domains, all the way to eighth-party scripts
The request map for CNN.com showing the chain of each request to different domains, all the way to eighth-party scripts. ソース。 (大プレビュー)
  1. Always prefer to self-host third-party assets.
    Yet again, self-host your static assets by default. It's common to assume that if many sites use the same public CDN and the same version of a JavaScript library or a web font, then the visitors would land on our site with the scripts and fonts already cached in their browser, speeding up their experience considerably. However, it's very unlikely to happen.

    For security reasons, to avoid fingerprinting, browsers have been implementing partitioned caching that was introduced in Safari back in 2013, and in Chrome last year. So if two sites point to the exact same third-party resource URL, the code is downloaded once per domain , and the cache is "sandboxed" to that domain due to privacy implications ( thanks, David Calhoun! ). Hence, using a public CDN will not automatically lead to better performance.

    Furthermore, it's worth noting that resources don't live in the browser's cache as long as we might expect, and first-party assets are more likely to stay in the cache than third-party assets. Therefore, self-hosting is usually more reliable and secure, and better for performance, too.

  2. Constrain the impact of third-party scripts.
    With all performance optimizations in place, often we can't control third-party scripts coming from business requirements. Third-party-scripts metrics aren't influenced by end-user experience, so too often one single script ends up calling a long tail of obnoxious third-party scripts, hence ruining a dedicated performance effort. To contain and mitigate performance penalties that these scripts bring along, it's not enough to just defer their loading and execution and warm up connections via resource hints, ie dns-prefetch or preconnect .

    Currently 57% of all JavaScript code excution time is spent on third-party code. The median mobile site accesses 12 third-party domains , with a median of 37 different requests (or about 3 requests made to each third party).

    Furthermore, these third-parties often invite fourth-party scripts to join in, ending up with a huge performance bottleneck, sometimes going as far as to the eigth-party scripts on a page. So regularly auditing your dependencies and tag managers can bring along costly surprises.

    Another problem, as Yoav Weiss explained in his talk on third-party scripts, is that in many cases these scripts download resources that are dynamic. The resources change between page loads, so we don't necessarily know which hosts the resources will be downloaded from and what resources they would be.

    Deferring, as shown above, might be just a start though as third-party scripts also steal bandwidth and CPU time from your app. We could be a bit more aggressive and load them only when our app has initialized.

    /* Before */ const App = () => { return <div> <script> window.dataLayer = window.dataLayer || []; function gtag(){...} gtg('js', new Date()); </script> </div> } /* After */ const App = () => { const[isRendered, setRendered] = useState(false); useEffect(() => setRendered(true)); return <div> {isRendered ? <script> window.dataLayer = window.dataLayer || []; function gtag(){...} gtg('js', new Date()); </script> : null} </div> }

    In a fantastic post on "Reducing the Site-Speed Impact of Third-Party Tags", Andy Davies explores a strategy of minimizing the footprint of third-parties — from identifying their costs towards reducing their impact.

    According to Andy, there are two ways tags impact site-speed — they compete for network bandwidth and processing time on visitors' devices, and depending on how they're implemented, they can delay HTML parsing as well. So the first step is to identify the impact that third-parties have, by testing the site with and without scripts using WebPageTest. With Simon Hearne's Request Map, we can also visualize third-parties on a page along with details on their size, type and what triggered their load.

    Preferably self-host and use a single hostname, but also use a request map to exposes fourth-party calls and detect when the scripts change. You can use Harry Roberts' approach for auditing third parties and produce spreadsheets like this one (also check Harry's auditing workflow).

    Afterwards, we can explore lightweight alternatives to existing scripts and slowly replace duplicates and main culprits with lighter options. Perhaps some of the scripts could be replaced with their fallback tracking pixel instead of the full tag.

    Left example showing 3KB of JavaScript using the lite-youtube custom element, middle and right example showing +540KB of JavaScript with the lite-youtube custom element
    Loading YouTube with facades, eg lite-youtube-embed that's significantly smaller than an actual YouTube player. (画像ソース)(大きなプレビュー)

    If it's not viable, we can at least lazy load third-party resources with facades, ie a static element which looks similar to the actual embedded third-party, but is not functional and therefore much less taxing on the page load. The trick, then, is to load the actual embed only on interaction .

    For example, we can use:

    • lite-vimeo-embed for the Vimeo player,
    • lite-vimeo for the Vimeo player,
    • lite-youtube-embed for the YouTube player,
    • react-live-chat-loader for a live chat (case study, and another case-study),
    • lazyframe for iframes.

    One of the reasons why tag managers are usually large in size is because of the many simultaneous experiments that are running at the same time, along with many user segments, page URLs, sites etc., so according to Andy, reducing them can reduce both the download size and the time it takes to execute the script in the browser.

    And then there are anti-flicker snippets. Third-parties such as Google Optimize, Visual Web Optimizer (VWO) and others are unanimous in using them. These snippets are usually injected along with running A/B tests : to avoid flickering between the different test scenarios, they hide the body of the document with opacity: 0 , then adds a function that gets called after a few seconds to bring the opacity back. This often results in massive delays in rendering due to massive client-side execution costs.

    Seven previews shown from 0.0 seconds to 6.0 seconds showing how and when contents are hidden by the anti-flicker snippet when a visitor initiates navigation
    With A/B testing in use, customers would often see flickering like this one. Anti-Flicker snippets prevent that, but they also cost in performance. Via Andy Davies. (大プレビュー)

    Therefore keep track how often the anti-flicker timeout is triggered and reduce the timeout. Default blocks display of your page by up to 4s which will ruin conversion rates. According to Tim Kadlec, "Friends don't let friends do client side A/B testing". Server-side A/B testing on CDNs (eg Edge Computing, or Edge Slice Rerendering) is always a more performant option.

    If you have to deal with almighty Google Tag Manager , Barry Pollard provides some guidelines to contain the impact of Google Tag Manager. Also, Christian Schaefer explores strategies for loading ads.

    注意:サードパーティのウィジェットの中には、監査ツールから身を隠すものがあるため、見つけて測定するのがより難しい場合があります。 サードパーティのストレステストを行うには、DevToolsのパフォーマンスプロファイルページでボトムアップの概要を調べ、リクエストがブロックされた場合やタイムアウトした場合にどうなるかをテストします。後者の場合は、WebPageTestのBlackholeサーバーblackhole.webpagetest.orgを使用できます。 hostsファイル内の特定のドメインを指すことができます。

    では、どのような選択肢がありますか? タイムアウトを使用してリソースのダウンロードを競合させてサービスワーカーを使用することを検討してください。リソースが特定のタイムアウト内に応答しなかった場合は、空の応答を返して、ページの解析を続行するようにブラウザーに指示してください。 成功しなかった、または特定の基準を満たさないサードパーティのリクエストをログに記録またはブロックすることもできます。 可能であれば、ベンダーのサーバーからではなく、独自のサーバーからサードパーティのスクリプトを読み込み、遅延読み込みします。

    もう1つのオプションは、コンテンツセキュリティポリシー(CSP)を確立して、サードパーティのスクリプトの影響を制限することです。たとえば、オーディオやビデオのダウンロードを禁止します。 最善のオプションは、 <iframe>を介してスクリプトを埋め込むことです。これにより、スクリプトはiframeのコンテキストで実行され、ページのDOMにアクセスできなくなり、ドメインで任意のコードを実行できなくなります。 sandbox属性を使用してIframeをさらに制限できるため、スクリプトの実行の防止、アラートの防止、フォームの送信、プラグイン、トップナビゲーションへのアクセスなど、iframeが実行する可能性のある機能を無効にすることができます。

    また、機能ポリシーを使用したブラウザ内パフォーマンスリンティングを介して、サードパーティをチェックすることもできます。これは、比較的新しい機能であり、 サイトの特定のブラウザ機能をオプトインまたはオプトアウトします。 (補足として、サイズが大きく最適化されていない画像、サイズが正しくないメディア、同期スクリプトなどを回避するためにも使用できます)。 現在、Blinkベースのブラウザでサポートされています。

    /* Via Tim Kadlec. https://timkadlec.com/remembers/2020-02-20-in-browser-performance-linting-with-feature-policies/ */ /* Block the use of the Geolocation API with a Feature-Policy header. */ Feature-Policy: geolocation 'none'
    /* Via Tim Kadlec. https://timkadlec.com/remembers/2020-02-20-in-browser-performance-linting-with-feature-policies/ */ /* Block the use of the Geolocation API with a Feature-Policy header. */ Feature-Policy: geolocation 'none'

    多くのサードパーティスクリプトがiframeで実行されているため、それらの許容量を徹底的に制限する必要があります。 サンドボックス化されたiframeは常に良いアイデアであり、 sandbox属性のいくつかのallow値を使用して、それぞれの制限を解除できます。 サンドボックス化はほとんどすべての場所でサポートされているため、サードパーティのスクリプトを、許可されるべき最小限のスクリプトに制限します。

    エンティティのスクリプトの平均実行にかかる時間を視覚化したThirdPartyWeb.TodayWebサイトのスクリーンショット
    ThirdPartyWeb.Todayは、すべてのサードパーティスクリプトをカテゴリ(分析、ソーシャル、広告、ホスティング、タグマネージャーなど)でグループ化し、エンティティのスクリプトの実行にかかる時間(平均)を視覚化します。 (大プレビュー)

    交差点オブザーバーの使用を検討してください。 これにより、イベントをディスパッチしたり、DOMから必要な情報(広告の可視性など)を取得したりしながら、広告をiframedすることができます。 機能ポリシー、リソースサイズの制限、CPU /帯域幅の優先度などの新しいポリシーに注意して、同期スクリプト、同期XHRリクエスト、 document.write 、古い実装など、ブラウザの速度を低下させる有害なWeb機能やスクリプトを制限します。

    最後に、サードパーティのサービスを選択するときは、Patrick HulceのThirdPartyWeb.Todayを確認することを検討してください。これは、すべてのサードパーティのスクリプトをカテゴリ(分析、ソーシャル、広告、ホスティング、タグマネージャーなど)ごとにグループ化し、エンティティのスクリプトの長さを視覚化するサービスです。実行するために取る(平均して)。 明らかに、最大のエンティティは、それらが表示されているページに最も悪いパフォーマンスの影響を与えます。 ページをざっと読むだけで、期待するパフォーマンスフットプリントがわかります。

    ああ、そして通常の容疑者を忘れないでください。共有用のサードパーティウィジェットの代わりに、静的なソーシャル共有ボタン(SSBGなど)とインタラクティブマップの代わりにインタラクティブマップへの静的リンクを使用できます。

ファーストパーティとサードパーティのリクエストの割合を比較したグラフの例:399KBはファーストパーティのリクエストの27%に相当し、1.15MBはサードパーティのリクエストの73%に相当します
Casper.comは、Optimizelyをセルフホスティングすることでサイトから1.7秒短縮する方法に関する詳細なケーススタディを公開しました。 それは価値があるかもしれません。 (画像ソース)(大きなプレビュー)
  1. HTTPキャッシュヘッダーを適切に設定します。
    キャッシングは非常に明白なことのようですが、正しく行うのはかなり難しいかもしれません。 expiresmax-agecache-control 、およびその他のHTTPキャッシュヘッダーが適切に設定されていることを再確認する必要があります。 適切なHTTPキャッシュヘッダーがないと、ブラウザはlast-modifiedてからの経過時間の10%に自動的に設定され、キャッシュが不足したり過剰になったりする可能性があります。

    一般に、リソースは非常に短時間(変更される可能性がある場合)または無期限(静的な場合)のいずれかでキャッシュ可能である必要があります。必要に応じて、URLのバージョンを変更できます。 これをCache-Forever戦略と呼ぶことができます。この戦略では、 Cache-ControlヘッダーとExpiresヘッダーをブラウザーに中継して、アセットの有効期限が1年のみになるようにすることができます。 したがって、アセットがキャッシュにある場合、ブラウザはアセットを要求することさえしません。

    例外はAPI応答です(例: /api/user )。 キャッシュを防ぐために、 private, no storeを使用でき、 max-age=0, no-storeありません:

     Cache-Control: private, no-store

    Cache-control: immutableを使用して、ユーザーがリロードボタンを押したときに明示的なキャッシュの有効期間が長く再検証されないようにします。 リロードの場合、 immutableはHTTPリクエストを保存し、ダイナミックHTMLが多数の304レスポンスと競合しなくなるため、ダイナミックHTMLのロード時間を改善します。

    immutableを使用したい典型的な例は、名前にハッシュが含まれるCSS / JavaScriptアセットです。 彼らにとっては、おそらくできるだけ長くキャッシュし、再検証されないようにしたいでしょう。

    Cache-Control: max-age: 31556952, immutable

    Colin Bendellの調査によると、 immutableは304リダイレクトを約50%削減します。これは、 max-ageを使用している場合でも、クライアントは更新時に再検証してブロックするためです。 Firefox、Edge、Safariでサポートされており、Chromeはまだこの問題について議論しています。

    Web Almanacによると、「その使用量は3.5%に増加し、FacebookやGoogleのサードパーティの応答で広く使用されています。」

    AndroidChromeおよびiOSSafariから取得したデータを使用した大陸全体でのキャッシュ制御の有効性
    Cache-Control:CloudinaryでのColin Bendellの調査によると、Immutableは304を約50%削減します。 (大プレビュー)

    古き良き再検証中の古さを覚えていますか? Cache-Control応答ヘッダーでキャッシュ時間を指定すると(例: Cache-Control: max-age=604800 )、 max-ageの期限が切れると、ブラウザーは要求されたコンテンツを再フェッチするため、ページの読み込みが遅くなります。 この速度低下は、 stale-while-revalidate使用して回避できます。 基本的に、バックグラウンドで非同期で再検証する限り、キャッシュが古いアセットを使用できる追加の時間枠を定義します。 したがって、(ネットワークとサーバーの両方で)遅延をクライアントから「隠蔽」します。

    2019年6月から7月に、 ChromeとFirefoxはHTTP Cache-Controlヘッダーでstale-while-revalidateサポートを開始しました。その結果、古いアセットがクリティカルパスにないため、後続のページ読み込みの待ち時間が改善されるはずです。 結果:リピートビューのRTTはゼロ。

    特にCDNに関連して、varyヘッダーに注意し、新しいリクエストが以前のリクエストとわずかに(ただし大幅ではない)異なる場合は常に検証のための追加のラウンドトリップを回避するのに役立つHTTP表現バリアントに注意してください(ありがとう、GuyとMark ! )。

    また、不要なヘッダー( x-powered-bypragmax-ua-compatibleexpiresX-XSS-Protectionなど)を送信していないこと、および有用なセキュリティとパフォーマンスのヘッダー( Content-Security-PolicyX-Content-Type-Optionsなどとして)。 最後に、シングルページアプリケーションでのCORSリクエストのパフォーマンスコストに注意してください。

    :キャッシュされたアセットは即座に取得されると想定されることがよくありますが、調査によると、キャッシュからオブジェクトを取得するには数百ミリ秒かかる場合があります。 実際、Simon Hearneによると、「ネットワークはキャッシュよりも高速である場合があり、キャッシュからのアセットの取得は、多数のキャッシュされたアセット(ファイルサイズではない)とユーザーのデバイスでコストがかかる可能性があります。例:ChromeOSの平均キャッシュ取得5つのキャッシュされたリソースで最大50ミリ秒から25のリソースで最大100ミリ秒まで2倍になります。」

    さらに、バンドルサイズは大きな問題ではないと想定されることが多く、ユーザーはバンドルサイズを一度ダウンロードしてから、キャッシュされたバージョンを使用します。 同時に、CI / CDを使用すると、コードを1日に複数回本番環境にプッシュし、キャッシュは毎回無効になるため、キャッシュについて戦略的に取り組むことが重要です。

    キャッシングに関しては、読む価値のあるリソースがたくさんあります。

    • 民間人のためのキャッシュ制御、ハリー・ロバーツによるすべてのキャッシュの詳細。
    • HTTPキャッシングヘッダーに関するHerokuの入門書、
    • JakeArchibaldによるキャッシュのベストプラクティス
    • Ilya GrigorikによるHTTPキャッシング入門書、
    • ジェフ・ポズニックによる再検証中の古いもので物事を新鮮に保つ。
    • CS Visualized:Lydia HallieによるCORSは、CORS、その仕組み、およびその意味を理解する方法についての優れた説明者です。
    • CORSについてお話ししますが、EricPortisによる同一生成元ポリシーについて少し復習します。
右側(上から下)に名前が付けられたさまざまなOSとブラウザでキャッシュされたアセットの数によるキャッシュ取得時間を示すグラフ:デスクトップChrome OS、タブレットAndroid OS、モバイルAndroid OS、デスクトップMac = S X、デスクトップWindows、デスクトップLinux
ブラウザのキャッシュはほぼ瞬時に発生すると想定していますが、データによると、キャッシュからオブジェクトを取得するには数百ミリ秒かかる場合があります。 ネットワークがキャッシュよりも高速である場合に関するSimonHearneの調査から。 (大プレビュー)

配信の最適化

  1. 重要なJavaScriptを非同期でロードするためにdeferを使用しますか?
    ユーザーがページをリクエストすると、ブラウザはHTMLをフェッチしてDOMを構築し、次にCSSをフェッチしてCSSOMを構築し、DOMとCSSOMを照合してレンダリングツリーを生成します。 JavaScriptを解決する必要がある場合、ブラウザは解決されるまでページのレンダリングを開始しないため、レンダリングが遅れます。 開発者として、ブラウザに待機せず、ページのレンダリングを開始するように明示的に指示する必要があります。 スクリプトに対してこれを行う方法は、HTMLのdefer属性とasync属性を使用することです。

    実際には、 asyncの代わりにdeferを使用する方が良いことがわかります。 ああ、また違いは何ですか? Steve Soudersによると、 asyncスクリプトが到着すると、スクリプトの準備ができるとすぐに実行されます。 これが非常に高速に発生する場合、たとえば、スクリプトがキャッシュリーダーにある場合、実際にはHTMLパーサーをブロックできます。 deferを使用すると、ブラウザはHTMLが解析されるまでスクリプトを実行しません。 したがって、レンダリングを開始する前にJavaScriptを実行する必要がない限り、 deferを使用することをお勧めします。 また、複数の非同期ファイルは非決定論的な順序で実行されます。

    asyncdeferについては、いくつかの誤解があることに注意してください。 最も重要なことは、 asyncは、スクリプトの準備ができたときにコードが実行されることを意味するわけではありません。 これは、スクリプトの準備が整い先行するすべての同期作業が完了するたびに実行されることを意味します。 ハリー・ロバーツの言葉によれば、「同期スクリプトの後にasyncスクリプトを配置すると、 asyncスクリプトは最も遅い同期スクリプトと同じくらい速くなります。」

    また、 asyncdeferの両方を使用することはお勧めしません。 最新のブラウザは両方をサポートしていますが、両方の属性が使用されている場合は常に、 asyncが優先されます。

    詳細を詳しく知りたい場合は、Milica Mihajlijaが、投機的構文解析、非同期、および延期の詳細について、DOMの高速構築に関する非常に詳細なガイドを作成しました。

  2. IntersectionObserverと優先度のヒントを使用して、高価なコンポーネントを遅延ロードします。
    一般に、重いJavaScript、ビデオ、iframe、ウィジェット、場合によっては画像など、高価なコンポーネントをすべて遅延読み込みすることをお勧めします。 ネイティブの遅延読み込みは、 loading属性を持つ画像とiframeですでに利用可能です(Chromiumのみ)。 内部的には、この属性は、ビューポートから計算された距離に達するまで、リソースのロードを延期します。
    <!-- Lazy loading for images, iframes, scripts. Probably for images outside of the viewport. --> <img loading="lazy" ... /> <iframe loading="lazy" ... /> <!-- Prompt an early download of an asset. For critical images, eg hero images. --> <img loading="eager" ... /> <iframe loading="eager" ... />

    そのしきい値は、フェッチされる画像リソースのタイプから有効な接続タイプまで、いくつかの要因に依存します。 ただし、AndroidでChromeを使用して実施された実験によると、4Gでは、遅延読み込みされた折り畳み下の画像の97.5%が、表示されてから10ミリ秒以内に完全に読み込まれたため、安全であるはずです。

    <script><img> 、または<link>要素でimportance属性( highまたはlow )を使用することもできます(点滅のみ)。 実際、カルーセル内の画像の優先順位を下げたり、スクリプトの優先順位を付け直したりするのに最適な方法です。 ただし、場合によっては、もう少しきめ細かい制御が必要になることがあります。

    <!-- When the browser assigns "High" priority to an image, but we don't actually want that. --> <img src="less-important-image.svg" importance="low" ... /> <!-- We want to initiate an early fetch for a resource, but also deprioritize it. --> <link rel="preload" importance="low" href="/script.js" as="script" />

    少し洗練された遅延読み込みを行う最もパフォーマンスの高い方法は、Intersection Observer APIを使用することです。これは、ターゲット要素と祖先要素またはトップレベルドキュメントのビューポートとの交差の変化を非同期的に監視する方法を提供します。 基本的に、コールバック関数と一連のオプションを受け取る新しいIntersectionObserverオブジェクトを作成する必要があります。 次に、観察するターゲットを追加します。

    コールバック関数は、ターゲットが表示または非表示になったときに実行されるため、ビューポートをインターセプトすると、要素が表示される前にいくつかのアクションを開始できます。 実際、 rootMargin (ルートの周囲のマージン)とthreshold (ターゲットの可視性の何パーセントを目指しているかを示す単一の数値または数値の配列)を使用して、オブザーバーのコールバックを呼び出すタイミングをきめ細かく制御できます。

    Alejandro Garcia Angladaは、実際に実装する方法に関する便利なチュートリアルを公開しています。RahulNanwaniは、遅延読み込みの前景と背景の画像に関する詳細な投稿を作成しました。GoogleFundamentalsは、交差点オブザーバーを使用した遅延読み込みの画像と動画に関する詳細なチュートリアルも提供しています。

    アート指向のストーリーテリングで、動くオブジェクトや粘着性のあるオブジェクトを使った長い読み物を覚えていますか? IntersectionObserverを使用してパフォーマンスの高いスクロールテリングを実装することもできます。

    他に遅延読み込みできるものをもう一度確認してください。 遅延読み込みの翻訳文字列や絵文字でさえ役立つ可能性があります。 そうすることで、モバイルTwitterは、新しい国際化パイプラインからJavaScriptの実行を80%高速化することができました。

    ただし、簡単に注意してください。遅延読み込みは、ルールではなく例外である必要があることに注意してください。 製品ページの画像、ヒーロー画像、メインナビゲーションをインタラクティブにするために必要なスクリプトなど、実際に人々にすばやく見てもらいたいものを遅延読み込みするのはおそらく合理的ではありません。

160KBのダウンロードで3000pxの古いしきい値を示す例(左)、新しいしきい値の量は1250pxで、ダウンロードは90KBのみ(右)で、imgの読み込みの遅延データの節約が改善されていることを示しています。
高速接続(例:4G)では、Chromeのビューポートからの距離のしきい値が最近3000pxから1250pxに減少し、低速接続(例:3G)では、しきい値が4000pxから2500pxに変更されました。 (大プレビュー)
Twitter UIが表示された携帯電話の周りにテキストが表示されたイラストで、遅延読み込みの翻訳文字列によるツールの改善について説明しています。
モバイルTwitterは、翻訳文字列を遅延読み込みすることで、新しい国際化パイプラインからJavaScriptの実行を80%高速化することに成功しました。 (画像クレジット:Addy Osmani)(大プレビュー)
  1. 画像を段階的にロードします。
    ページにプログレッシブ画像の読み込みを追加することで、遅延読み込みを次のレベルに引き上げることもできます。 Facebook、Pinterest、Medium、Woltと同様に、最初に低品質またはぼやけた画像を読み込んでから、ページの読み込みを続けながら、BlurHashテクニックまたはLQIP(低品質画像プレースホルダー)を使用してフル品質バージョンに置き換えます。技術。

    これらの手法によってユーザーエクスペリエンスが向上するかどうかについては意見が異なりますが、First ContentfulPaintまでの時間は確実に向上します。 低品質バージョンの画像をSVGプレースホルダーとして作成するSQIP、またはCSS線形グラデーションを使用したグラデーション画像プレースホルダーを使用して自動化することもできます。

    これらのプレースホルダーは、テキスト圧縮メソッドで自然に圧縮されるため、HTML内に埋め込むことができます。 Dean Humeは、彼の記事で、IntersectionObserverを使用してこの手法を実装する方法について説明しています。

    後退する? ブラウザが交差点オブザーバーをサポートしていない場合でも、ポリフィルを遅延ロードするか、画像をすぐにロードできます。 そして、そのためのライブラリもあります。

    もっと空想に行きたいですか? 画像をトレースし、プリミティブシェイプとエッジを使用して、軽量のSVGプレースホルダーを作成し、最初にロードしてから、プレースホルダーベクトルイメージから(ロードされた)ビットマップイメージに遷移することができます。

  2. Jose M. PerezによるSVG遅延読み込み手法を示す3つの異なるバージョン、左側にキュービズムアートに類似したバージョン、中央にピクセル化されたぼやけたバージョン、右側にJose自身の適切な写真
    Jose M.PerezによるSVG遅延読み込み手法。 (大プレビュー)
  3. content-visibilityでレンダリングを延期しますか?
    豊富なコンテンツブロック、画像、ビデオを含む複雑なレイアウトの場合、データのデコードとピクセルのレンダリングは、特にローエンドデバイスでは、非常にコストのかかる操作になる可能性があります。 content-visibility: autoを使用すると、コンテナーがビューポートの外にある間、ブラウザーに子のレイアウトをスキップするように求めることができます。

    たとえば、初期ロード時にフッターと後期セクションのレンダリングをスキップできます。

    footer { content-visibility: auto; contain-intrinsic-size: 1000px; /* 1000px is an estimated height for sections that are not rendered yet. */ }

    content-visibility:auto;に注意してください。 オーバーフローのように動作します:非表示。 、ただし、デフォルトのmargin-leftの代わりにpadding padding-leftpadding-rightを適用することで修正できますmargin-left: auto;margin-right: auto; と宣言された幅。 パディングを使用すると、基本的に、要素がコンテンツボックスをオーバーフローして、ボックスモデル全体を離れたり、切り取られたりすることなく、パディングボックスに入ることができます。

    また、新しいコンテンツが最終的にレンダリングされるときにCLSが導入される可能性があることに注意してください。そのため、適切なサイズのプレースホルダーを使用しcontain-intrinsic-sizeを使用することをお勧めします(ありがとう、Una! )。

    Thijs Terluinには、両方のプロパティと、ブラウザによるcontain-intrinsic-sizeの計算方法に関する詳細があり、Malte Ublはそれを計算する方法を示し、JakeとSurmaによる簡単なビデオ説明者がすべての動作を説明しています。

    また、CSS Containmentを使用してもう少し細かくする必要がある場合は、他の要素のサイズ、配置、または計算されたスタイルのみが必要な場合、または要素が現在ある場合は、DOMノードの子孫のレイアウト、スタイル、およびペイント作業を手動でスキップできます。オフキャンバス。

初期ロードでのレンダリングパフォーマンスは、ベースライン(左)で2,288ミリ秒、content-visibility:auto(右)のチャンクで13,464ミリ秒です。
デモでは、 content-visibility: autoをチャンク化されたコンテンツ領域に適用すると、初期ロード時にレンダリングパフォーマンスが7倍向上します。 (大プレビュー)
  1. decode decoding="async"を延期しますか?
    コンテンツが画面外に表示されることもありますが、お客様が必要なときにコンテンツを利用できるようにする必要があります。理想的には、クリティカルパスで何もブロックせず、非同期でデコードおよびレンダリングします。 decode decoding="async"を使用して、メインスレッドから画像をデコードする許可をブラウザに与えることができます。これにより、(Malte Ublを介して)画像のデコードに使用されるCPU時間のユーザーへの影響を回避できます。

    <img decoding="async" … />

    または、オフスクリーン画像の場合、最初にプレースホルダーを表示し、画像がビューポート内にあるときに、IntersectionObserverを使用して、画像をバックグラウンドでダウンロードするためのネットワーク呼び出しをトリガーできます。 また、img.decode()でデコードするまでレンダリングを延期するか、Image DecodeAPIが利用できない場合は画像をダウンロードすることができます。

    画像をレンダリングするとき、たとえばフェードインアニメーションを使用できます。 KatieHempeniusとAddyOsmaniは、彼らの講演「Speed at Scale:Web Performance Tips and Tricks fromtheTrenches」でより多くの洞察を共有しています。

  2. 重要なCSSを生成して提供していますか?
    ブラウザができるだけ早くページのレンダリングを開始できるようにするために、ページの最初の表示部分のレンダリングを開始するために必要なすべてのCSS(「クリティカルCSS」または「オーバーザフォールドCSS」と呼ばれる)を収集することが一般的な方法になりました。 ")そしてそれをページの<head>にインラインで含めることで、ラウンドトリップを減らします。 スロースタートフェーズ中に交換されるパッケージのサイズが限られているため、重要なCSSの予算は約14KBです。

    それを超えると、ブラウザはより多くのスタイルをフェッチするために追加のラウンドトリップが必要になります。 CriticalCSSとCriticalを使用すると、使用しているすべてのテンプレートの重要なCSSを出力できます。 しかし、私たちの経験では、すべてのテンプレートの重要なCSSを手動で収集するよりも優れた自動システムはありません。実際、これが最近戻ってきたアプローチです。

    次に、重要なCSSをインライン化し、残りをcrittersWebpackプラグインで遅延ロードできます。 可能であれば、フィラメントグループで使用される条件付きインライン化アプローチを使用するか、インラインコードをその場で静的アセットに変換することを検討してください。

    現在、loadCSSなどのライブラリを使用して完全なCSSを非同期でロードしている場合、実際には必要ありません。 media="print"を使用すると、ブラウザをだましてCSSを非同期にフェッチさせることができますが、ロードされると画面環境に適用されます。 (ありがとう、スコット!

    <!-- Via Scott Jehl. https://www.filamentgroup.com/lab/load-css-simpler/ --> <!-- Load CSS asynchronously, with low priority --> <link rel="stylesheet" href="full.css" media="print" onload="this.media='all'" />

    各テンプレートのすべての重要なCSSを収集するときは、「折り畳みの上」の領域だけを探索するのが一般的です。 ただし、複雑なレイアウトの場合は、レイアウトの基礎も含めて、大量の再計算と再描画のコストを回避し、結果としてCore WebVitalsスコアを損なうことを回避することをお勧めします。

    ユーザーがページの中央に直接リンクしているURLを取得したが、CSSがまだダウンロードされていない場合はどうなりますか? その場合、重要ではないコンテンツを非表示にすることが一般的になりました。たとえば、 opacity: 0; インラインCSSおよびopacity: 1 、CSSが使用可能な場合に表示します。 ただし、接続速度が遅いユーザーはページのコンテンツを読み取ることができない可能性があるため、大きな欠点があります。 そのため、適切なスタイルが設定されていない場合でも、コンテンツは常に表示されたままにしておくことをお勧めします。

    重要なCSS(およびその他の重要なアセット)をルートドメインの別のファイルに配置すると、キャッシュが原因で、インライン化よりも多くの利点があります。 Chromeは、ページをリクエストするときにルートドメインへの2番目のHTTP接続を投機的に開きます。これにより、このCSSをフェッチするためのTCP接続が不要になります。 つまり、重要な-CSSファイルのセット(たとえば、 critical-homepage.csscritical-product-page.cssなど)を作成し、それらをインライン化することなく、ルートから提供できます。 (ありがとう、フィリップ!

    注意:HTTP / 2を使用すると、重要なCSSを別のCSSファイルに保存し、HTMLを肥大化させることなくサーバープッシュを介して配信できます。 キャッチは、サーバーのプッシュがブラウザ間での多くの落とし穴と競合状態で厄介だったことです。 一貫してサポートされることはなく、キャッシュの問題がいくつかありました(Hooman Beheshtiのプレゼンテーションのスライド114以降を参照)。

    実際、この影響はマイナスになり、ネットワークバッファが肥大化し、ドキュメント内の本物のフレームが配信されなくなる可能性があります。 そのため、当面の間、Chromeがサーバープッシュのサポートを削除することを計画していることはそれほど驚くことではありませんでした。

  3. CSSルールを再グループ化してみてください。
    重要なCSSには慣れていますが、それを超える可能性のある最適化がいくつかあります。 ハリー・ロバーツは驚くべき研究を行い、驚くべき結果をもたらしました。 たとえば、メインのCSSファイルを個々のメディアクエリに分割することをお勧めします。 このようにして、ブラウザは優先度の高い重要なCSSを取得し、優先度の低い他のすべてのものを取得します—完全にクリティカルパスから外れます。

    また、 asyncスニペットの前に<link rel="stylesheet" />を配置することは避けてください。 スクリプトがスタイルシートに依存しない場合は、ブロックするスタイルの上にブロックするスクリプトを配置することを検討してください。 その場合は、そのJavaScriptを2つに分割し、CSSのいずれかの側にロードします。

    Scott Jehlは、インラインCSSファイルをService Workerでキャッシュすることで、別の興味深い問題を解決しました。これは、重要なCSSを使用している場合によくある問題です。 基本的に、JavaScriptを使用して簡単に見つけられるようにstyle要素にID属性を追加します。次に、JavaScriptの小さな部分がそのCSSを見つけ、Cache APIを使用してローカルブラウザキャッシュに保存します(コンテンツタイプはtext/css )。 text/css )以降のページで使用します。 後続のページにインライン化することを避け、代わりにキャッシュされたアセットを外部から参照するために、サイトへの最初のアクセス時にCookieを設定します。 出来上がり!

    動的なスタイリングも高価になる可能性があることに注意してください。ただし、通常は、同時にレンダリングされる何百もの構成されたコンポーネントに依存している場合に限ります。 したがって、CSS-in-JSを使用している場合は、CSSがテーマや小道具に依存していないときにCSS-in-JSライブラリが実行を最適化し、スタイル付きコンポーネントを過剰に構成しないようにしてください。 Aggelos Arvanitakisは、CSS-in-JSのパフォーマンスコストに関するより多くの洞察を共有しています。

  4. 応答をストリーミングしますか?
    忘れられたり無視されたりすることが多いストリームは、データの非同期チャンクを読み書きするためのインターフェイスを提供します。そのサブセットのみが、いつでもメモリで使用できる可能性があります。 基本的に、元のリクエストを行ったページは、データの最初のチャンクが利用可能になるとすぐにレスポンスの処理を開始でき、ストリーミング用に最適化されたパーサーを使用してコンテンツを段階的に表示できます。

    複数のソースから1つのストリームを作成できます。 たとえば、空のUIシェルを提供してJavaScriptにデータを入力させる代わりに、シェルがキャッシュから取得され、本体がネットワークから取得されるストリームをServiceWorkerに構築させることができます。 Jeff Posnickが指摘したように、Webアプリが部分的なテンプレートをつなぎ合わせてHTMLをサーバーレンダリングするCMSを利用している場合、そのモデルは、サーバーではなくService Workerで複製されたテンプレートロジックを使用して、ストリーミング応答を使用するように直接変換されます。 JakeArchibaldのTheYear of Web Streamsの記事は、それをどのように正確に構築できるかを強調しています。 パフォーマンスの向上は非常に顕著です。

    HTML応答全体をストリーミングすることの重要な利点の1つは、最初のナビゲーション要求中にレンダリングされたHTMLが、ブラウザーのストリーミングHTMLパーサーを最大限に活用できることです。 ページの読み込み後にドキュメントに挿入されるHTMLのチャンク(JavaScriptを介して入力されたコンテンツで一般的)は、この最適化を利用できません。

    ブラウザのサポート? Chrome、Firefox、Safari、Edgeで部分的にサポートされており、最新のすべてのブラウザーでサポートされているAPIとServiceWorkerをサポートしています。 また、冒険心があれば、ストリーミングリクエストの実験的な実装を確認できます。これにより、本文を生成しながらリクエストの送信を開始できます。 Chrome85で利用できます。

Android Chromeでのデータ保存の使用状況と、2019年11月と2020年4月にCloudinaryの調査で発見された平均imgヒットまたはセッションをまとめた画像
Cloudinaryの調査によると、世界中のAndroid Chromeユーザーの18%がLiteモード(別名Save-Data)を有効にしています。 (大プレビュー)
  1. コンポーネントを接続対応にすることを検討してください。
    データは高額になる可能性があり、ペイロードが増えるにつれて、サイトやアプリにアクセスする際にデータの節約を選択するユーザーを尊重する必要があります。 Save-Dataクライアントヒントリクエストヘッダーを使用すると、コストとパフォーマンスに制約のあるユーザー向けにアプリケーションとペイロードをカスタマイズできます。

    実際、高DPI画像のリクエストを低DPI画像に書き換えたり、ウェブフォント、派手な視差効果を削除したり、サムネイルと無限スクロールをプレビューしたり、動画の自動再生をオフにしたり、サーバーをプッシュしたり、表示されるアイテムの数を減らしたり、画質をダウングレードしたりできます。マークアップの配信方法も変更します。 Tim Vereeckeは、データ保存の多くのオプションを特徴とするdata-s(h)aver戦略に関する非常に詳細な記事を公開しました。

    誰がsave-dataを使用していますか、あなたは疑問に思うかもしれませんか? 世界のAndroidChromeユーザーの18%がライトモードを有効にしており( Save-Dataオン)、その数はもっと多くなる可能性があります。 Simon Hearneの調査によると、オプトイン率は安価なデバイスで最も高くなりますが、外れ値はたくさんあります。 例:カナダのユーザーのオプトイン率は34%を超え(米国の約7%と比較して)、最新のSamsungフラッグシップのユーザーのオプトイン率は世界全体でほぼ18%です。

    [ Save-Data ]モードをオンにすると、Chrome Mobileは最適化されたエクスペリエンスを提供します。つまり、遅延スクリプト、強制されたfont-display: swap 、および強制された遅延読み込みを使用したプロキシWebエクスペリエンスを提供します。 これらの最適化を行うためにブラウザに依存するよりも、自分でエクスペリエンスを構築する方が賢明です。

    ヘッダーは現在、Chromium、AndroidバージョンのChrome、またはデスクトップデバイスのデータセーバー拡張機能でのみサポートされています。 最後に、Network Information APIを使用して、ネットワークタイプに基づいて、コストのかかるJavaScriptモジュール、高解像度の画像およびビデオを配信することもできます。 ネットワーク情報API、特にnavigator.connection.effectiveTypeは、 RTTdownlinkeffectiveType値(およびその他のいくつか)を使用して、ユーザーが処理できる接続とデータの表現を提供します。

    このコンテキストでは、Max Bockは接続対応コンポーネントについて話し、AddyOsmaniは適応モジュールサービングについて話します。 たとえば、Reactを使用すると、接続タイプごとに異なるレンダリングを行うコンポーネントを作成できます。 Maxが示唆したように、ニュース記事の<Media />コンポーネントは次のように出力する可能性があります。

    • Offlinealtテキストを含むプレースホルダー、
    • 2G / save-dataモード:低解像度画像、
    • 非Retina画面での3G :中解像度の画像、
    • Retina画面の3G :高解像度のRetina画像、
    • 4G :HDビデオ。

    Dean Humeは、ServiceWorkerを使用して同様のロジックの実用的な実装を提供します。 ビデオの場合、デフォルトでビデオポスターを表示してから、「再生」アイコン、ビデオプレーヤーシェル、ビデオのメタデータなどをより適切な接続で表示できます。 サポートされていないブラウザのフォールバックとして、 canplaythroughイベントをリッスンし、 canplaythroughイベントが2秒以内に発生しない場合は、 Promise.race()を使用してソースの読み込みをタイムアウトすることができます。

    もう少し深く掘り下げたい場合は、開始するためのリソースがいくつかあります。

    • Addy Osmaniは、Reactでアダプティブサービングを実装する方法を示しています。
    • React Adaptive Loading Hooks&Utilitiesは、Reactのコードスニペットを提供します。
    • Netanel Baselは、Angularの接続対応コンポーネントを調査します。
    • Theodore Vorilasが、Vueでネットワーク情報APIを使用してアダプティブコンポーネントを提供する方法について説明します。
    • Umar Hansaは、高価なJavaScriptを選択的にダウンロード/実行する方法を示しています。
  2. コンポーネントをデバイスメモリ対応にすることを検討してください。
    ただし、ネットワーク接続では、ユーザーのコンテキストで1つの視点しか得られません。 さらに、Device Memory APIを使用して、使用可能なデバイスメモリに基づいてリソースを動的に調整することもできます。 navigator.deviceMemory returns how much RAM the device has in gigabytes, rounded down to the nearest power of two. The API also features a Client Hints Header, Device-Memory , that reports the same value.

    Bonus : Umar Hansa shows how to defer expensive scripts with dynamic imports to change the experience based on device memory, network connectivity and hardware concurrency.

A break-down showing how different resources are prioritized in Blink as of Chrome 46 and beyond
A break-down showing how different resources are prioritized in Blink as of Chrome 46 and beyond. (Image credit: Addy Osmani) (Large preview)
  1. Warm up the connection to speed up delivery.
    Use resource hints to save time on dns-prefetch (which performs a DNS lookup in the background), preconnect (which asks the browser to start the connection handshake (DNS, TCP, TLS) in the background), prefetch (which asks the browser to request a resource) and preload (which prefetches resources without executing them, among other things). Well supported in modern browsers, with support coming to Firefox soon.

    Remember prerender ? The resource hint used to prompt browser to build out the entire page in the background for next navigation. The implementations issues were quite problematic, ranging from a huge memory footprint and bandwidth usage to multiple registered analytics hits and ad impressions.

    Unsurprinsingly, it was deprecated, but the Chrome team has brought it back as NoState Prefetch mechanism. In fact, Chrome treats the prerender hint as a NoState Prefetch instead, so we can still use it today. As Katie Hempenius explains in that article, "like prerendering, NoState Prefetch fetches resources in advance ; but unlike prerendering, it does not execute JavaScript or render any part of the page in advance."

    NoState Prefetch only uses ~45MiB of memory and subresources that are fetched will be fetched with an IDLE Net Priority. Since Chrome 69, NoState Prefetch adds the header Purpose: Prefetch to all requests in order to make them distinguishable from normal browsing.

    Also, watch out for prerendering alternatives and portals, a new effort toward privacy-conscious prerendering, which will provide the inset preview of the content for seamless navigations.

    Using resource hints is probably the easiest way to boost performance , and it works well indeed. When to use what? As Addy Osmani has explained, it's reasonable to preload resources that we know are very likely to be used on the current page and for future navigations across multiple navigation boundaries, eg Webpack bundles needed for pages the user hasn't visited yet.

    Addy's article on "Loading Priorities in Chrome" shows how exactly Chrome interprets resource hints, so once you've decided which assets are critical for rendering, you can assign high priority to them. To see how your requests are prioritized, you can enable a "priority" column in the Chrome DevTools network request table (as well as Safari).

    Most of the time these days, we'll be using at least preconnect and dns-prefetch , and we'll be cautious with using prefetch , preload and prerender . Note that even with preconnect and dns-prefetch , the browser has a limit on the number of hosts it will look up/connect to in parallel, so it's a safe bet to order them based on priority ( thanks Philip Tellis! ).

    Since fonts usually are important assets on a page, sometimes it's a good idea to request the browser to download critical fonts with preload . However, double check if it actually helps performance as there is a puzzle of priorities when preloading fonts: as preload is seen as high importance, it can leapfrog even more critical resources like critical CSS. ( thanks, Barry! )

    <!-- Loading two rendering-critical fonts, but not all their weights. --> <!-- crossorigin="anonymous" is required due to CORS. Without it, preloaded fonts will be ignored. https://github.com/w3c/preload/issues/32 via https://twitter.com/iamakulov/status/1275790151642423303 --> <link rel="preload" as="font" href="Elena-Regular.woff2" type="font/woff2" crossorigin="anonymous" media="only screen and (min-width: 48rem)" /> <link rel="preload" as="font" href="Mija-Bold.woff2" type="font/woff2" crossorigin="anonymous" media="only screen and (min-width: 48rem)" />
    <!-- Loading two rendering-critical fonts, but not all their weights. --> <!-- crossorigin="anonymous" is required due to CORS. Without it, preloaded fonts will be ignored. https://github.com/w3c/preload/issues/32 via https://twitter.com/iamakulov/status/1275790151642423303 --> <link rel="preload" as="font" href="Elena-Regular.woff2" type="font/woff2" crossorigin="anonymous" media="only screen and (min-width: 48rem)" /> <link rel="preload" as="font" href="Mija-Bold.woff2" type="font/woff2" crossorigin="anonymous" media="only screen and (min-width: 48rem)" />

    Since <link rel="preload"> accepts a media attribute, you could choose to selectively download resources based on @media query rules, as shown above.

    Furthermore, we can use imagesrcset and imagesizes attributes to preload late-discovered hero images faster, or any images that are loaded via JavaScript, eg movie posters:

    <!-- Addy Osmani. https://addyosmani.com/blog/preload-hero-images/ --> <link rel="preload" as="image" href="poster.jpg" image image>
    <!-- Addy Osmani. https://addyosmani.com/blog/preload-hero-images/ --> <link rel="preload" as="image" href="poster.jpg" image image>

    We can also preload the JSON as fetch , so it's discovered before JavaScript gets to request it:

    <!-- Addy Osmani. https://addyosmani.com/blog/preload-hero-images/ --> <link rel="preload" as="fetch" href="foo.com/api/movies.json" crossorigin>

    We could also load JavaScript dynamically, effectively for lazy execution of the script.

    /* Adding a preload hint to the head */ var preload = document.createElement("link"); link.href = "myscript.js"; link.rel = "preload"; link.as = "script"; document.head.appendChild(link); /* Injecting a script when we want it to execute */ var script = document.createElement("script"); script.src = "myscript.js"; document.body.appendChild(script);

    A few gotchas to keep in mind: preload is good for moving the start download time of an asset closer to the initial request, but preloaded assets land in the memory cache which is tied to the page making the request. preload plays well with the HTTP cache: a network request is never sent if the item is already there in the HTTP cache.

    Hence, it's useful for late-discovered resources, hero images loaded via background-image , inlining critical CSS (or JavaScript) and pre-loading the rest of the CSS (or JavaScript).

    An example using the cover of the Greyhound movie starring Tom Hanks to show that preloaded images load earlier as there is no need to wait on JavaScript to discover
    Preload important images early; no need to wait on JavaScript to discover them. (Image credit: “Preload Late-Discovered Hero Images Faster” by Addy Osmani) (Large preview)

    A preload tag can initiate a preload only after the browser has received the HTML from the server and the lookahead parser has found the preload tag. Preloading via the HTTP header could be a bit faster since we don't to wait for the browser to parse the HTML to start the request (it's debated though).

    Early Hints will help even further, enabling preload to kick in even before the response headers for the HTML are sent (on the roadmap in Chromium, Firefox). Plus, Priority Hints will help us indicate loading priorities for scripts.

    Beware : if you're using preload , as must be defined or nothing loads, plus preloaded fonts without the crossorigin attribute will double fetch. If you're using prefetch , beware of the Age header issues in Firefox.

A graph showing first contentful paint (by server worker status) with count from 0 to 150 across a given period of time (in ms)
With a service worker, we can request just the bare minimum of data, and then transform that data into a full HTML document to improve FCP. (via Phil Walton) (Large preview)
  1. Use service workers for caching and network fallbacks.
    No performance optimization over a network can be faster than a locally stored cache on a user's machine (there are exceptions though). If your website is running over HTTPS, we can cache static assets in a service worker cache and store offline fallbacks (or even offline pages) and retrieve them from the user's machine, rather than going to the network.

    As suggested by Phil Walton, with service workers, we can send smaller HTML payloads by programmatically generating our responses. A service worker can request just the bare minimum of data it needs from the server (eg an HTML content partial, a Markdown file, JSON data, etc.), and then it can programmatically transform that data into a full HTML document. So once a user visits a site and the service worker is installed, the user will never request a full HTML page again. The performance impact can be quite impressive.

    Browser support? Service workers are widely supported and the fallback is the network anyway. Does it help boost performance ? Oh yes, it does. And it's getting better, eg with Background Fetch allowing background uploads/downloads via a service worker as well.

    There are a number of use cases for a service worker. For example, you could implement "Save for offline" feature, handle broken images, introduce messaging between tabs or provide different caching strategies based on request types. In general, a common reliable strategy is to store the app shell in the service worker's cache along with a few critical pages, such as offline page, frontpage and anything else that might be important in your case.

    There are a few gotchas to keep in mind though. With a service worker in place, we need to beware range requests in Safari (if you are using Workbox for a service worker it has a range request module). If you ever stumbled upon DOMException: Quota exceeded. error in the browser console, then look into Gerardo's article When 7KB equals 7MB.

    Gerardoは次のように述べています。「プログレッシブウェブアプリを構築していて、サービスワーカーがCDNから提供される静的アセットをキャッシュするときにキャッシュストレージが肥大化する場合は、クロスオリジンリソースに適切なCORS応答ヘッダーが存在することを確認してください。不透明な応答はキャッシュしないでください。サービスワーカーが意図せずに、クロスcrossorigin属性を<img>タグに追加することで、クロスオリジンイメージアセットをCORSモードにオプトインします。」

    サービスワーカーを始めるための優れたリソースはたくさんあります。

    • サービスワーカーの考え方。これは、サービスワーカーが舞台裏でどのように機能するか、およびサービスワーカーを構築するときに理解することを理解するのに役立ちます。
    • Chris Ferdinandiは、サービスワーカーに関する一連のすばらしい記事を提供し、オフラインアプリケーションの作成方法を説明し、最近表示したページをオフラインで保存する方法から、サービスワーカーのキャッシュにアイテムの有効期限を設定する方法まで、さまざまなシナリオをカバーしています。

    • サービスワーカーの落とし穴とベストプラクティス、スコープに関するいくつかのヒント、サービスワーカーの登録とサービスワーカーのキャッシュの遅延。
    • Ire Aderinokunによる、Service Workerによる「オフラインファースト」の素晴らしいシリーズで、アプリシェルのプリキャッシングに関する戦略があります。
    • Service Worker:豊富なオフラインエクスペリエンス、定期的なバックグラウンド同期、プッシュ通知のためにServiceWorkerを使用する方法に関する実用的なヒントの紹介。
    • 古き良きジェイク・アーチボルドのオフラインクックブックを参照して、自分のサービスワーカーを焼く方法に関するレシピをいくつか紹介することは常に価値があります。
    • Workboxは、プログレッシブWebアプリを構築するために特別に構築されたServiceWorkerライブラリのセットです。
  2. たとえばA / Bテストのために、CDN / Edgeでサーバーワーカーを実行していますか?
    この時点では、クライアントでサービスワーカーを実行することにかなり慣れていますが、CDNをサーバーに実装すると、エッジでのパフォーマンスを微調整するためにも使用できます。

    たとえば、A / Bテストでは、HTMLがユーザーごとにコンテンツを変更する必要がある場合、CDNサーバー上のServiceWorkerを使用してロジックを処理できます。 HTMLの書き換えをストリーミングして、GoogleFontsを使用するサイトを高速化することもできます。

2016年1月から2020年7月までの時間の経過に伴うページの割合を含む、デスクトップとモバイルでのServiceWorkerのインストールの時系列を示すグラフ
ServiceWorkerのインストールの時系列。 Web Almanacによると、すべてのデスクトップページの0.87%だけがサービスワーカーを登録しています。 (大プレビュー)
  1. レンダリングパフォーマンスを最適化します。
    アプリケーションが遅いときはいつでも、すぐに目立ちます。 したがって、ページをスクロールするとき、または要素がアニメーション化されるときにラグがないこと、および1秒あたり60フレームを常にヒットしていることを確認する必要があります。 それが不可能な場合は、少なくとも1秒あたりのフレーム数を一定にすることが60〜15の混合範囲よりも望ましいです。CSSのwill-changeを使用して、どの要素とプロパティが変更されるかをブラウザに通知します。

    発生しているときはいつでも、DevToolsで不要な再描画をデバッグしてください。

    • ランタイムレンダリングのパフォーマンスを測定します。 それを理解する方法に関するいくつかの役立つヒントを確認してください。
    • 開始するには、ブラウザレンダリングの最適化に関するPaul Lewisの無料のUdacityコースと、ブラウザのペイントとWebパフォーマンスに関する考慮事項に関するGeorgyMarchukの記事を確認してください。
    • FirefoxDevToolsの「その他のツール→レンダリング→ペイントフラッシュ」でペイントフラッシュを有効にします。
    • React DevToolsで、[更新を強調表示]をオンにし、[各コンポーネントがレンダリングされた理由を記録する]を有効にします。
    • また、Why Did You Renderを使用することもできるため、コンポーネントが再レンダリングされると、フラッシュが変更を通知します。

    組積造のレイアウトを使用していますか? 間もなく、CSSグリッドだけで石積みレイアウトを構築できる可能性があることに注意してください。

    このトピックをさらに深く掘り下げたい場合は、Nolan Lawsonが彼の記事でレイアウトのパフォーマンスを正確に測定するための秘訣を共有しており、JasonMillerも代替手法を提案しています。 また、GPUアニメーションを正しくする方法についてのSergeyChikuyonokによるlilの記事があります。

    位置、スケール、回転、不透明度などの高性能アニメーション
    ブラウザは、変換と不透明度を安価にアニメーション化できます。 CSSトリガーは、CSSがリレイアウトまたはリフローをトリガーするかどうかを確認するのに役立ちます。 (画像クレジット:Addy Osmani)(大プレビュー)

    :GPU合成レイヤーへの変更は最も安価であるため、 opacitytransformを介して合成のみをトリガーすることで回避できる場合は、正しい方向に進んでいます。 Anna Migasは、UIレンダリングパフォーマンスのデバッグに関する講演でも多くの実践的なアドバイスを提供しています。 また、DevToolsでペイントパフォーマンスをデバッグする方法を理解するには、Umarのペイントパフォーマンス監査ビデオを確認してください。

  2. 知覚されるパフォーマンスに合わせて最適化しましたか?
    コンポーネントがページにどのように表示されるか、およびアセットをブラウザーに提供する方法の戦略は重要ですが、知覚されるパフォーマンスの役割も過小評価してはなりません。 このコンセプトは、待機の心理的側面を扱い、基本的に、何か他のことが起こっている間、顧客を忙しくしたり、従事させたりします。 そこで、知覚管理、先制的開始、早期完了、および許容度管理が機能します。

    それはどういう意味ですか? アセットをロードしている間、私たちは常にお客様の一歩先を行くように努めることができるので、バックグラウンドでかなり多くのことが起こっている間、経験は迅速に感じられます。 顧客の関心を維持するために、インジケーターをロードする代わりにスケルトン画面をテストし(実装デモ)、トランジション/アニメーションを追加し、基本的に最適化するものがないときにUXをごまかすことができます。

    The Art of UI Skeletonsのケーススタディで、Kumar McMillanは、動的リスト、テキスト、最終画面をシミュレートする方法、およびReactでスケルトン思考を検討する方法に関するいくつかのアイデアとテクニックを共有しています。

    ただし、注意してください。一部のテストでは、スケルトンスクリーンのパフォーマンスがすべてのメトリックで最悪であることが示されたため、スケルトンスクリーンはデプロイする前にテストする必要があります。

  3. レイアウトのずれや塗り直しを防ぎますか?
    知覚されるパフォーマンスの領域では、おそらくより破壊的なエクスペリエンスの1つは、再スケーリングされた画像やビデオ、Webフォント、挿入された広告、またはコンポーネントに実際のコンテンツを取り込む最近発見されたスクリプトによって引き起こされるレイアウトシフトまたはリフローです。 その結果、顧客は、読書エリアの上のレイアウトジャンプによって中断されるだけで記事を読み始める可能性があります。 経験はしばしば突然で非常に混乱します:そしてそれはおそらく再考される必要がある優先順位をロードする場合です。

    コミュニティは、リフローを回避するためのいくつかの手法と回避策を開発しました。 一般に、ユーザーの操作に応じて発生する場合を除いて、既存のコンテンツの上に新しいコンテンツを挿入しないことをお勧めします。 画像には常に幅と高さの属性を設定するため、最近のブラウザはボックスを割り当て、デフォルトでスペースを予約します(Firefox、Chrome)。

    画像と動画の両方で、SVGプレースホルダーを使用して、メディアが表示される表示ボックスを予約できます。つまり、アスペクト比を維持する必要がある場合にも、領域が適切に予約されます。 広告や動的コンテンツにプレースホルダーやフォールバック画像を使用したり、レイアウトスロットを事前に割り当てたりすることもできます。

    外部スクリプトを使用して画像を遅延読み込みする代わりに、ネイティブ遅延読み込みを使用するか、ネイティブ遅延読み込みがサポートされていない場合にのみ外部スクリプトを読み込むときにハイブリッド遅延読み込みを使用することを検討してください。

    上記のように、常にWebフォントの再描画をグループ化し、すべてのフォールバックフォントからすべてのWebフォントに一度に移行します。font-style-matcherを使用してフォント間の行の高さと間隔を調整することにより、切り替えが急激になりすぎないようにします。 。

    フォールバックフォントのフォントメトリックをオーバーライドしてWebフォントをエミュレートするには、@ font-face記述子を使用してフォントメトリックをオーバーライドできます(デモ、Chrome 87で有効)。 (ただし、複雑なフォントスタックでは調整が複雑になることに注意してください。)

    最近のCSSの場合、レイアウトが重要なCSSが各テンプレートのヘッダーにインライン化されていることを確認できます。 さらに、長いページの場合、垂直スクロールバーを追加すると、メインコンテンツが16px左にシフトします。 スクロールバーを早期に表示するために、 overflow-y: scrollを追加できますhtmlをスクロールして、最初のペイントでスクロールバーを適用します。 後者は、幅が変更されたときにスクロールバーが折り目の上のコンテンツのリフローのために重要なレイアウトシフトを引き起こす可能性があるため、役立ちます。 ただし、ほとんどの場合、Windowsのような非オーバーレイスクロールバーを備えたプラットフォームで発生するはずです。 しかし: position: stickyです。

    スクロール時にページの上部に固定または固定されたヘッダーを処理する場合は、コンテンツのプレースホルダー要素やmargin-topなど、ヘッダーがパインになったときにヘッダー用のスペースを予約します。 例外は、CLSに影響を与えてはならないCookie同意バナーですが、影響を与える場合もあります。実装によって異なります。 このTwitterスレッドには、いくつかの興味深い戦略とポイントがあります。

    さまざまな量のテキストが含まれる可能性のあるタブコンポーネントの場合、CSSグリッドスタックを使用してレイアウトのシフトを防ぐことができます。 各タブのコンテンツを同じグリッド領域に配置し、一度に1つを非表示にすることで、コンテナが常に大きい要素の高さを占めるようにすることができるため、レイアウトのずれは発生しません。

    ああ、そしてもちろん、リストの下にコンテンツ(フッターなど)がある場合は、無限のスクロールと「さらに読み込む」によってレイアウトがシフトする可能性があります。 CLSを改善するには、ユーザーがページのその部分にスクロールするに読み込まれるコンテンツ用に十分なスペースを確保し、コンテンツの読み込みによって押し下げられる可能性のあるページ下部のフッターまたはDOM要素を削除します。また、折り畳み下のコンテンツのデータと画像をプリフェッチして、ユーザーがそこまでスクロールするまでに、すでにそこにあるようにします。 react-windowのようなリスト仮想化ライブラリを使用して長いリストを最適化することもできます(ありがとう、Addy Osmani! )。

    リフローの影響を確実に抑えるには、Layout InstabilityAPIを使用してレイアウトの安定性を測定します。 これを使用すると、累積レイアウトシフト( CLS )スコアを計算し、それをテストの要件として含めることができるため、リグレッションが発生した場合はいつでも、それを追跡して修正できます。

    レイアウトシフトスコアを計算するために、ブラウザはビューポートのサイズと、レンダリングされた2つのフレーム間のビューポート内の不安定な要素の動きを調べます。 理想的には、スコアは0に近くなります。 CLSとは何か、CLSの測定方法については、MilicaMihajlijaとPhilipWaltonによるすばらしいガイドがあります。 これは、特にビジネスクリティカルなタスクの場合に、知覚されるパフォーマンスを測定および維持し、中断を回避するための良い出発点です。

    クイックヒント:DevToolsでレイアウトシフトの原因を見つけるには、パフォーマンスパネルの[エクスペリエンス]でレイアウトシフトを調べることができます。

    ボーナス:リフローとリペイントを減らしたい場合は、CharisTheodoulouのDOMリフロー/レイアウトスラッシングの最小化ガイドとPaulIrishのレイアウト/リフローを強制するもののリストとCSSTriggers.com、レイアウトをトリガーするCSSプロパティのリファレンステーブル、ペイントを確認してくださいと合成。

ネットワーキングとHTTP / 2

  1. OCSPステープリングは有効になっていますか?
    サーバーでOCSPステープリングを有効にすることで、TLSハンドシェイクを高速化できます。 オンライン証明書ステータスプロトコル(OCSP)は、証明書失効リスト(CRL)プロトコルの代替として作成されました。 両方のプロトコルは、SSL証明書が取り消されているかどうかを確認するために使用されます。

    ただし、OCSPプロトコルでは、ブラウザが証明書情報のリストをダウンロードして検索するのに時間を費やす必要がないため、ハンドシェイクに必要な時間が短縮されます。

  2. SSL証明書失効の影響を減らしましたか?
    「EV証明書のパフォーマンスコスト」に関する彼の記事で、Simon Hearneは、一般的な証明書の概要と、証明書の選択が全体的なパフォーマンスに与える影響について説明しています。

    Simonが書いているように、HTTPSの世界では、トラフィックを保護するために使用される証明書検証レベルにはいくつかの種類があります。

    • ドメイン検証(DV)は、証明書リクエスターがドメインを所有していることを検証します。
    • 組織検証(OV)は、組織がドメインを所有していることを検証します。
    • Extended Validation (EV)は、組織がドメインを所有していることを厳密な検証で検証します。

    これらの証明書はすべて、テクノロジーに関して同じであることに注意することが重要です。 それらは、それらの証明書で提供される情報とプロパティのみが異なります。

    EV証明書は、人間が証明書を確認してその有効性を確認する必要があるため、費用と時間がかかります。 一方、DV証明書は、多くの場合、無料で提供されます。たとえば、Let's Encryptによって、多くのホスティングプロバイダーやCDNに十分に統合されたオープンな自動認証局です。 実際、これを書いている時点では、ページの2.69%(Firefoxで開かれている)にすぎませんが、2億2500万を超えるWebサイト(PDF)に電力を供給しています。

    では、何が問題なのでしょうか。 問題は、 EV証明書が上記のOCSPステープリングを完全にサポートしていないことです。 ステープルを使用すると、サーバーは証明書が取り消されているかどうかを認証局に確認し、この情報を証明書に追加(「ステープル」)できます。ステープルを使用しないと、クライアントはすべての作業を行う必要があり、TLSネゴシエーション中に不要な要求が発生します。 。 接続が不十分な場合、パフォーマンスコストが顕著になる可能性があります(1000ミリ秒以上)。

    EV証明書は、Webパフォーマンスに最適な選択肢ではなく、DV証明書よりもパフォーマンスに大きな影響を与える可能性があります。 最適なWeb​​パフォーマンスを得るには、常にOCSPステープルDV証明書を提供してください。 また、EV証明書よりもはるかに安価で、取得の手間も少なくなります。 まあ、少なくともCRLiteが利用可能になるまでは。

    プレーン、圧縮、またはその両方の場合のサイトUDPデータグラムに沿ったハンドシェイクの数を示すグラフ
    圧縮の問題:非圧縮の証明書チェーンの40〜43%は大きすぎて、3つのUDPデータグラムの単一のQUICフライトに収まりません。 (画像クレジット:)ファストリー)(大プレビュー)

    :QUIC / HTTP / 3を使用している場合、TLS証明書チェーンがQUICハンドシェイクのバイト数を支配する1つの可変サイズのコンテンツであることに注意してください。 サイズは数百バイから10KB以上の間で異なります。

    したがって、TLS証明書を小さく保つことは、QUIC / HTTP / 3で非常に重要です。これは、証明書が大きいと複数のハンドシェイクが発生するためです。 また、証明書が圧縮されていることを確認する必要があります。そうしないと、証明書チェーンが大きすぎて1つのQUICフライトに収まりません。

    問題と解決策へのより多くの詳細とポインタを見つけることができます:

    • EV証明書は、Aaron PetersによるWebの速度を低下させ、信頼性を低下させます。
    • MattHobbsによるWebパフォーマンスに対するSSL証明書の失効の影響
    • SimonHearneによるEV証明書のパフォーマンスコスト
    • QUICハンドシェイクは高速であるために圧縮を必要としますか? パトリック・マクマヌス著。
  3. IPv6はもう採用しましたか?
    IPv4のスペースが不足しており、主要なモバイルネットワークがIPv6を急速に採用しているため(米国はIPv6の採用しきい値のほぼ50%に達しています)、将来に備えてDNSをIPv6に更新することをお勧めします。 ネットワーク全体でデュアルスタックサポートが提供されていることを確認してください。これにより、IPv6とIPv4を同時に実行できます。 結局のところ、IPv6には下位互換性がありません。 また、調査によると、IPv6は、近隣探索(NDP)とルートの最適化により、これらのWebサイトを10〜15%高速化しました。
  4. すべてのアセットがHTTP / 2(またはHTTP / 3)で実行されていることを確認してください。
    グーグルが過去数年にわたってより安全なHTTPSウェブを推進しているので、HTTP / 2環境への切り替えは間違いなく良い投資です。 実際、Web Almanacによると、すべてのリクエストの64%がすでにHTTP / 2を介して実行されています。

    HTTP / 2は完全ではなく、優先順位付けの問題があることを理解することが重要ですが、それは非常によくサポートされています。 そして、ほとんどの場合、あなたはそれを使ったほうがいいです。

    注意:HTTP / 2サーバープッシュはChromeから削除されているため、実装がサーバープッシュに依存している場合は、サーバープッシュを再検討する必要があります。 代わりに、Fastlyですでに実験として統合されているEarlyHintsを検討している可能性があります。

    まだHTTPで実行している場合、最も時間のかかるタスクは、最初にHTTPSに移行してから、ビルドプロセスを調整してHTTP / 2の多重化と並列化に対応することです。 HTTP / 2をGov.ukに導入することは、まさにそれを実行し、その過程でCORS、SRI、およびWPTを介して方法を見つけることに関する素晴らしいケーススタディです。 この記事の残りの部分では、HTTP / 2に切り替えているか、すでに切り替えていることを前提としています。

2016年1月2日から2020年10月1日までのデスクトップとモバイルの両方でのHTTP / 2リクエストの時系列を示すグラフ
Web Almanacによると、すべてのリクエストの64%は、正式な標準化からわずか4年後の2020年後半にHTTP / 2経由で処理されます。 (画像ソース:Webアルマナック)(大プレビュー)
  1. HTTP / 2を適切にデプロイします。
    繰り返しになりますが、HTTP / 2を介してアセットを提供することは、これまでのアセットの提供方法を​​部分的に見直すことで恩恵を受けることができます。 モジュールのパッケージ化と多数の小さなモジュールの並列ロードとの間の微妙なバランスを見つける必要があります。 結局のところ、それでも最善のリクエストはリクエストなしですが、目標は、アセットの迅速な最初の配信とキャッシングの間の微妙なバランスを見つけることです。

    一方では、インターフェース全体を多くの小さなモジュールに分割し、ビルドプロセスの一部としてそれらを圧縮して並列にロードするのではなく、アセットを完全に連結することを避けたい場合があります。 1つのファイルを変更しても、スタイルシート全体またはJavaScriptを再ダウンロードする必要はありません。 また、解析時間を最小限に抑え、個々のページのペイロードを低く抑えます。

    一方、パッケージングは​​依然として重要です。 多くの小さなスクリプトを使用すると、全体的な圧縮が低下し、キャッシュからオブジェクトを取得するコストが増加します。 大きなパッケージの圧縮は辞書の再利用の恩恵を受けますが、小さな個別のパッケージはそうではありません。 これに対処するための標準的な作業がありますが、今のところそれは遠いです。 第二に、ブラウザはまだそのようなワークフロー用に最適化されていません。 たとえば、Chromeはリソースの数に比例したプロセス間通信(IPC)をトリガーするため、数百のリソースを含めるとブラウザのランタイムコストが発生します。

    プログレッシブCSS読み込みを使用したHTMLコード
    HTTP / 2で最良の結果を得るには、ChromeのJake Archibaldが提案しているように、CSSを段階的にロードすることを検討してください。

    それでも、CSSを段階的にロードしてみることができます。 実際、インボディCSSはChromeのレンダリングをブロックしなくなりました。 ただし、優先順位付けの問題がいくつかあるため、それほど単純ではありませんが、試してみる価値があります。

    HTTP / 2接続の合体を回避することもできます。これにより、HTTP / 2の恩恵を受けながらドメインシャーディングを使用できますが、実際にこれを実現することは困難であり、一般に、これは良い習慣とは見なされません。 また、HTTP / 2とサブリソースの整合性が常に機能するとは限りません。

    何をすべきか? そうですね、HTTP / 2で実行している場合、 6〜10個のパッケージを送信することは、まともな妥協案のように思えます(そして、レガシーブラウザにとってはそれほど悪くはありません)。 実験と測定を行って、Webサイトの適切なバランスを見つけてください。

  2. すべてのアセットを単一のHTTP / 2接続で送信しますか?
    HTTP / 2の主な利点の1つは、単一の接続を介してアセットをネットワークに送信できることです。 ただし、CORSの問題が発生したり、 crossorigin属性を誤って設定したりすると、ブラウザが新しい接続を開くように強制されるなど、何か問題が発生した可能性があります。

    すべてのリクエストが単一のHTTP / 2接続を使用しているかどうか、または何かが正しく構成されていないかどうかを確認するには、DevTools→Networkの「ConnectionID」列を有効にします。 たとえば、ここでは、すべてのリクエストが同じ接続を共有します(286)—別の接続を開くmanifest.json(451)を除きます。

Chromeブラウザで開いているDevToolsのスクリーンショット
すべてのリクエストは同じHTTP / 2接続(286)を共有します—別の接続を開くmanifest.json(451)を除きます。 iamakulov経由。 (大プレビュー)
  1. サーバーとCDNはHTTP / 2をサポートしていますか?
    サーバーとCDNが異なれば(まだ)HTTP / 2のサポートも異なります。 CDN比較を使用してオプションを確認するか、サーバーのパフォーマンスとサポートが期待できる機能をすばやく調べます。

    HTTP / 2の優先順位(ビデオ)とHTTP / 2の優先順位付けのためのテストサーバーのサポートに関するPatMeenanの驚くべき研究を参照してください。 Patによると、Linux 4.9カーネル以降で確実に機能するようにHTTP / 2の優先順位付けを行うには、BBR輻輳制御を有効にし、 tcp_notsent_lowatを16KBに設定することをお勧めします(ありがとう、Yoav! )。 Andy Daviesは、ブラウザ、CDN、クラウドホスティングサービス全体でのHTTP / 2の優先順位付けについて同様の調査を行いました。

    その間、カーネルがTCP BBRをサポートしているかどうかを再確認し、可能であれば有効にします。 現在、Google Cloud Platform、Amazon Cloudfront、Linux(Ubuntuなど)で使用されています。

  2. HPACK圧縮を使用していますか?
    HTTP / 2を使用している場合は、サーバーがHTTP応答ヘッダーにHPACK圧縮を実装していることを再確認して、不要なオーバーヘッドを削減してください。 一部のHTTP / 2サーバーは、HPACKを例として、仕様を完全にサポートしていない場合があります。 H2specは、それをチェックするための優れた(技術的に詳細な場合)ツールです。 HPACKの圧縮アルゴリズムは非常に印象的で、機能します。
  3. サーバーのセキュリティが防弾であることを確認してください。
    HTTP / 2のすべてのブラウザ実装はTLSを介して実行されるため、セキュリティ警告やページ上の一部の要素が機能しないことを避けたいと思うでしょう。 セキュリティヘッダーが適切に設定されていることを再確認し、既知の脆弱性を排除して、HTTPS設定を確認します。

    また、すべての外部プラグインとトラッキングスクリプトがHTTPS経由で読み込まれていること、クロスサイトスクリプティングが不可能であること、HTTP Strict TransportSecurityヘッダーとContentSecurityPolicyヘッダーの両方が適切に設定されていることを確認してください。

  4. サーバーとCDNはHTTP / 3をサポートしていますか?
    HTTP / 2は、Webに多くの大幅なパフォーマンスの改善をもたらしましたが、改善の余地もかなりありました。特に、TCPのヘッドオブラインブロッキングは、パケット損失が大きい低速ネットワークで顕著でした。 HTTP / 3はこれらの問題を永久に解決しています(記事)。

    HTTP / 2の問題に対処するために、IETFは、Google、Akamaiなどとともに、最近HTTP / 3として標準化された新しいプロトコルに取り組んでいます。

    RobinMarxはHTTP / 3について非常によく説明しており、以下の説明は彼の説明に基づいています。 コアでは、HTTP / 3は機能の点でHTTP / 2と非常に似ていますが、内部的には非常に異なった動作をします。 HTTP / 3は、より高速なハンドシェイク、より優れた暗号化、より信頼性の高い独立したストリーム、より優れた暗号化とフロー制御など、多くの改善を提供します。 注目すべき違いは、HTTP / 3がトランスポート層としてQUICを使用し、QUICパケットがTCPではなくUDPダイアグラムの上にカプセル化されていることです。

    QUICはTLS1.3をプロトコルに完全に統合しますが、TCPでは最上位に階層化されています。 通常のTCPスタックでは、TCPとTLSが独自のハンドシェイクを実行する必要があるため、オーバーヘッドのラウンドトリップ時間が数回ありますが、QUICを使用すると、両方を組み合わせて1回のラウンドトリップで完了することができます。 TLS 1.3では、結果として生じる接続の暗号化キーを設定できるため、2番目以降の接続では、「0-RTT」と呼ばれる最初のラウンドトリップでアプリケーション層データをすでに送受信できます。

    また、HTTP / 2のヘッダー圧縮アルゴリズムは、優先順位付けシステムとともに完全に書き直されました。 さらに、QUICは、各QUICパケットのヘッダーにある接続IDを介したWi-Fiからセルラーネットワークへの接続移行をサポートします。 ほとんどの実装はカーネル空間ではなくユーザー空間で行われるため(TCPで行われるように)、プロトコルが将来進化することを期待する必要があります。

    それはすべて大きな違いを生むでしょうか? おそらくそうです。特にモバイルでの読み込み時間だけでなく、エンドユーザーへのアセットの提供方法にも影響を与えます。 HTTP / 2では、複数のリクエストが接続を共有しますが、HTTP / 3リクエストでも接続を共有しますが、独立してストリーミングするため、ドロップされたパケットはすべてのリクエストに影響を与えることはなく、1つのストリームにのみ影響します。

    つまり、1つの大きなJavaScriptバンドルでは、1つのストリームが一時停止するとアセットの処理が遅くなりますが、複数のファイルが並列にストリーミングされる場合(HTTP / 3)の影響はそれほど大きくありません。 したがって、パッケージングは​​依然として重要です。

    HTTP / 3はまだ進行中です。 Chrome、Firefox、Safariにはすでに実装があります。 一部のCDNはすでにQUICとHTTP / 3をサポートしています。 2020年後半に、ChromeはHTTP / 3とIETFQUICの導入を開始しました。実際、すべてのGoogleサービス(Google Analytics、YouTubeなど)はすでにHTTP / 3で実行されています。 LiteSpeedWebサーバーはHTTP / 3をサポートしていますが、Apache、nginx、IISのいずれもまだサポートしていませんが、2021年に急速に変更される可能性があります。

    結論:サーバーとCDNでHTTP / 3を使用するオプションがある場合は、そうすることをお勧めします。 主な利点は、特に待ち時間の長い接続で、複数のオブジェクトを同時にフェッチすることから得られます。 その分野で行われた研究はあまりないので、まだはっきりとはわかりませんが、最初の結果は非常に有望です。

    プロトコルの詳細と利点について詳しく知りたい場合は、次の点を確認してください。

    • HTTP / 3 Explained、HTTP / 3とQUICプロトコルを文書化するための共同作業。 さまざまな言語で利用でき、PDFとしても利用できます。
    • DanielStenbergによるHTTP / 3によるWebパフォーマンスのレベルアップ。
    • Robin Marxを使用したQUICのアカデミックガイドでは、QUICおよびHTTP / 3プロトコルの基本概念を紹介し、HTTP / 3がヘッドオブラインブロッキングと接続移行を処理する方法、およびHTTP / 3が常緑になるように設計されている方法を説明しています(ありがとう、 Simon !)。
    • サーバーがHTTP3Check.netのHTTP / 3で実行されているかどうかを確認できます。

テストとモニタリング

  1. 監査ワークフローを最適化しましたか?
    大したことではないように聞こえるかもしれませんが、適切な設定を指先で行うことで、テストにかかる時間を大幅に節約できる可能性があります。 WebPageTestのパブリックインスタンスにテストを送信するには、TimKadlecのAlfredWorkflow forWebPageTestを使用することを検討してください。 実際、WebPageTestには多くのあいまいな機能があるため、時間をかけてWebPageTestウォーターフォールビューチャートを読み取る方法と、WebPageTest接続ビューチャートを読み取ってパフォーマンスの問題をより迅速に診断および解決する方法を学習してください。

    また、GoogleスプレッドシートからWebPageTestを駆動し、アクセシビリティ、パフォーマンス、SEOスコアをLighthouse CIを使用してTravisセットアップに組み込むか、Webpackに直接組み込むこともできます。

    最近リリースされたAutoWebPerfをご覧ください。これは、複数のソースからパフォーマンスデータを自動的に収集できるモジュラーツールです。 たとえば、重要なページに毎日テストを設定して、CrUX APIからフィールドデータをキャプチャし、PageSpeedInsightsからLighthouseレポートからラボデータをキャプチャすることができます。

    また、何かをすばやくデバッグする必要があるが、ビルドプロセスが非常に遅いように思われる場合は、「空白の削除とシンボルのマングリングは、複雑なコード変換ではなく、ほとんどのJavaScriptの縮小コードのサイズ縮小の95%を占めることに注意してください。圧縮を無効にするだけで、Uglifyのビルドが3〜4倍高速化されます。」

レビューが必要であり、チェックが正常に解決されるまでマージがブロックされることを示すGitHubのプルリクエスト通知のスクリーンショット
アクセシビリティ、パフォーマンス、SEOスコアをLighthouse CIを使用してTravisセットアップに統合すると、貢献しているすべての開発者にとって新機能のパフォーマンスへの影響が浮き彫りになります。 (画像ソース)(大きなプレビュー)
  1. プロキシブラウザとレガシーブラウザでテストしましたか?
    ChromeとFirefoxでのテストだけでは不十分です。 プロキシブラウザとレガシーブラウザでWebサイトがどのように機能するかを調べます。 たとえば、UCBrowserとOperaMiniは、アジアで大きな市場シェアを持っています(アジアでは最大35%)。 将来の大きな驚きを避けるために、関心のある国の平均インターネット速度を測定します。 ネットワークスロットリングでテストし、高DPIデバイスをエミュレートします。 BrowserStackは、リモートの実際のデバイスでのテストに最適であり、オフィス内の少なくともいくつかの実際のデバイスで補完することもできます。それだけの価値があります。
  1. 404ページのパフォーマンスをテストしましたか?
    通常、404ページに関しては二度と考えません。 結局のところ、クライアントがサーバーに存在しないページを要求すると、サーバーは404ステータスコードと関連する404ページで応答します。 そんなに多くはありませんね。

    404応答の重要な側面は、ブラウザーに送信される実際の応答本文のサイズです。 Matt Hobbsによる404ページの調査によると、404応答の大部分は、ファビコンの欠落、WordPressアップロード要求、壊れたJavaScript要求、マニフェストファイル、CSSおよびフォントファイルからのものです。 クライアントが存在しないアセットをリクエストするたびに、404レスポンスを受け取ります。多くの場合、そのレスポンスは膨大です。

    404ページのキャッシュ戦略を調べて最適化してください。 私たちの目標は、ブラウザがHTML応答を期待する場合にのみ、ブラウザにHTMLを提供し、他のすべての応答に対して小さなエラーペイロードを返すことです。 Mattによると、「CDNをオリジンの前に配置すると、404ページの応答をCDNにキャッシュする機会があります。これがないと、404ページをヒットするとDoS攻撃ベクトルとして使用される可能性があるため便利です。 CDNにキャッシュされたバージョンで応答させるのではなく、オリジンサーバーにすべての404要求に応答するように強制します。」

    404エラーはパフォーマンスに悪影響を与える可能性があるだけでなく、トラフィックにコストがかかる可能性があるため、Lighthouseテストスイートに404エラーページを含めて、そのスコアを経時的に追跡することをお勧めします。

  2. GDPR同意プロンプトのパフォーマンスをテストしましたか?
    GDPRとCCPAの時代には、EUの顧客が追跡をオプトインまたはオプトアウトするためのオプションを提供するために、サードパーティに依存することが一般的になっています。 ただし、他のサードパーティスクリプトと同様に、それらのパフォーマンスは、パフォーマンスの取り組み全体に非常に大きな影響を与える可能性があります。

    もちろん、実際の同意によって全体的なパフォーマンスに対するスクリプトの影響が変わる可能性が高いため、Boris Schapiraが指摘したように、いくつかの異なるWebパフォーマンスプロファイルを調査することをお勧めします。

    • 同意は完全に拒否されました、
    • 同意は部分的に拒否されました、
    • 同意は完全に与えられました。
    • ユーザーが同意プロンプトに対応していません(またはプロンプトがコンテンツブロッカーによってブロックされました)、

    通常、Cookieの同意プロンプトはCLSに影響を与えるべきではありませんが、影響を与える場合もあるため、無料のオープンソースオプションであるOsanoまたはcookie-consent-boxの使用を検討してください。

    一般に、マウスイベントの水平方向または垂直方向のオフセットを決定し、アンカーに対してポップアップを正しく配置する必要があるため、ポップアップのパフォーマンスを調べる価値があります。 Noam Rosenthalは、Webパフォーマンスのケーススタディ:ウィキペディアのページプレビュー(ビデオおよび議事録としても利用可能)の記事でウィキメディアチームの学習を共有しています。

  3. パフォーマンス診断CSSを保持していますか?
    パフォーマンスの低いコードがデプロイされていることを確認するためにあらゆる種類のチェックを含めることができますが、簡単に解決できるいくつかの簡単な成果をすばやく把握しておくと便利なことがよくあります。 そのために、Tim Kadlecの優れたパフォーマンス診断CSS(遅延読み込み画像、サイズなし画像、レガシー形式の画像、同期スクリプトを強調表示するHarryRobertsのスニペットに触発されたもの)を使用できます。

    たとえば、折り目の上の画像が遅延ロードされないようにすることができます。 必要に応じてスニペットをカスタマイズできます。たとえば、使用されていないWebフォントを強調表示したり、アイコンフォントを検出したりできます。 デバッグ中に間違いが表示されるようにするため、または現在のプロジェクトを非常に迅速に監査するための優れた小さなツール。

    /* Performance Diagnostics CSS */ /* via Harry Roberts. https://twitter.com/csswizardry/status/1346477682544951296 */ img[loading=lazy] { outline: 10px solid red; }
  1. Have you tested the impact on accessibility?
    When the browser starts to load a page, it builds a DOM, and if there is an assistive technology like a screen reader running, it also creates an accessibility tree. The screen reader then has to query the accessibility tree to retrieve the information and make it available to the user — sometimes by default, and sometimes on demand. And sometimes it takes time.

    When talking about fast Time to Interactive, usually we mean an indicator of how soon a user can interact with the page by clicking or tapping on links and buttons. The context is slightly different with screen readers. In that case, fast Time to Interactive means how much time passes by until the screen reader can announce navigation on a given page and a screen reader user can actually hit keyboard to interact.

    Leonie Watson has given an eye-opening talk on accessibility performance and specifically the impact slow loading has on screen reader announcement delays. Screen readers are used to fast-paced announcements and quick navigation, and therefore might potentially be even less patient than sighted users.

    Large pages and DOM manipulations with JavaScript will cause delays in screen reader announcements. A rather unexplored area that could use some attention and testing as screen readers are available on literally every platform (Jaws, NVDA, Voiceover, Narrator, Orca).

  2. Is continuous monitoring set up?
    Having a private instance of WebPagetest is always beneficial for quick and unlimited tests. However, a continuous monitoring tool — like Sitespeed, Calibre and SpeedCurve — with automatic alerts will give you a more detailed picture of your performance. Set your own user-timing marks to measure and monitor business-specific metrics. Also, consider adding automated performance regression alerts to monitor changes over time.

    Look into using RUM-solutions to monitor changes in performance over time. For automated unit-test-alike load testing tools, you can use k6 with its scripting API. Also, look into SpeedTracker, Lighthouse and Calibre.

クイックウィン

This list is quite comprehensive, and completing all of the optimizations might take quite a while. So, if you had just 1 hour to get significant improvements, what would you do? Let's boil it all down to 17 low-hanging fruits . Obviously, before you start and once you finish, measure results, including Largest Contentful Paint and Time To Interactive on a 3G and cable connection.

  1. Measure the real world experience and set appropriate goals. Aim to be at least 20% faster than your fastest competitor. Stay within Largest Contentful Paint < 2.5s, a First Input Delay < 100ms, Time to Interactive < 5s on slow 3G, for repeat visits, TTI < 2s. Optimize at least for First Contentful Paint and Time To Interactive.
  2. Optimize images with Squoosh, mozjpeg, guetzli, pingo and SVGOMG, and serve AVIF/WebP with an image CDN.
  3. Prepare critical CSS for your main templates, and inline them in the <head> of each template. For CSS/JS, operate within a critical file size budget of max. 170KB gzipped (0.7MB decompressed).
  4. Trim, optimize, defer and lazy-load scripts. Invest in the config of your bundler to remove redundancies and check lightweight alternatives.
  5. Always self-host your static assets and always prefer to self-host third-party assets. Limit the impact of third-party scripts. Use facades, load widgets on interaction and beware of anti-flicker snippets.
  6. Be selective when choosing a framework. For single-page-applications, identify critical pages and serve them statically, or at least prerender them, and use progressive hydration on component-level and import modules on interaction.
  7. Client-side rendering alone isn't a good choice for performance. Prerender if your pages don't change much, and defer the booting of frameworks if you can. If possible, use streaming server-side rendering.
  8. Serve legacy code only to legacy browsers with <script type="module"> and module/nomodule pattern.
  9. Experiment with regrouping your CSS rules and test in-body CSS.
  10. Add resource hints to speed up delivery with faster dns-lookup , preconnect , prefetch , preload and prerender .
  11. Subset web fonts and load them asynchronously, and utilize font-display in CSS for fast first rendering.
  12. Check that HTTP cache headers and security headers are set properly.
  13. Enable Brotli compression on the server. (If that's not possible, at least make sure that Gzip compression is enabled.)
  14. Enable TCP BBR congestion as long as your server is running on the Linux kernel version 4.9+.
  15. Enable OCSP stapling and IPv6 if possible. Always serve an OCSP stapled DV certificate.
  16. Enable HPACK compression for HTTP/2 and move to HTTP/3 if it's available.
  17. Cache assets such as fonts, styles, JavaScript and images in a service worker cache.

Download The Checklist (PDF, Apple Pages)

With this checklist in mind, you should be prepared for any kind of front-end performance project. Feel free to download the print-ready PDF of the checklist as well as an editable Apple Pages document to customize the checklist for your needs:

  • Download the checklist PDF (PDF, 166 KB)
  • Download the checklist in Apple Pages (.pages, 275 KB)
  • Download the checklist in MS Word (.docx, 151 KB)

If you need alternatives, you can also check the front-end checklist by Dan Rublic, the "Designer's Web Performance Checklist" by Jon Yablonski and the FrontendChecklist.

オフウィーゴー!

Some of the optimizations might be beyond the scope of your work or budget or might just be overkill given the legacy code you have to deal with. それはいいです! Use this checklist as a general (and hopefully comprehensive) guide, and create your own list of issues that apply to your context. But most importantly, test and measure your own projects to identify issues before optimizing. Happy performance results in 2021, everyone!


A huge thanks to Guy Podjarny, Yoav Weiss, Addy Osmani, Artem Denysov, Denys Mishunov, Ilya Pukhalski, Jeremy Wagner, Colin Bendell, Mark Zeman, Patrick Meenan, Leonardo Losoviz, Andy Davies, Rachel Andrew, Anselm Hannemann, Barry Pollard, Patrick Hamann, Gideon Pyzer, Andy Davies, Maria Prosvernina, Tim Kadlec, Rey Bango, Matthias Ott, Peter Bowyer, Phil Walton, Mariana Peralta, Pepijn Senders, Mark Nottingham, Jean Pierre Vincent, Philipp Tellis, Ryan Townsend, Ingrid Bergman, Mohamed Hussain SH, Jacob Groß, Tim Swalling, Bob Visser, Kev Adamson, Adir Amsalem, Aleksey Kulikov and Rodney Rehm for reviewing this article, as well as our fantastic community which has shared techniques and lessons learned from its work in performance optimization for everybody to use. あなたは本当に粉砕しています!