CSSのリファクタリング:サイズとパフォーマンスの最適化(パート3)

公開: 2022-03-10
簡単な要約↬リファクタリングされたコードベースは、同様または改善されたパフォーマンスと改善されたコードベースの健全性をもたらすはずです。 結局のところ、リファクタリングされたコードベースをデプロイすると、読み込みやパフォーマンスの問題が発生する場合、トラフィックと収益が減少します。 幸いなことに、潜在的なファイルサイズとパフォーマンスの問題に取り組むために適用できる最適化手法はたくさんあります。

このシリーズのこれまでの記事では、CSSコードベースの状態の監査と、CSSの増分リファクタリング戦略、テスト、およびメンテナンスについて説明しました。 リファクタリングプロセス中にCSSコードベースがどれだけ改善されたか、またそれがどれほど保守可能で拡張可能であるかに関係なく、最終的なスタイルシートは、可能な限り最高のパフォーマンスと可能な限り最小のファイルサイズになるように最適化する必要があります。

リファクタリングされたコードベースをデプロイしても、Webサイトのパフォーマンスやユーザーエクスペリエンスが低下することはありません。 結局のところ、ユーザーはWebサイトがロードされるのを永遠に待つことはありません。 また、コード品質の向上にもかかわらず、最適化されていないコードベースによって引き起こされるトラフィックと収益の減少に経営陣は不満を抱くでしょう。

この記事では、CSSファイルのサイズ、読み込み時間、レンダリングのパフォーマンスを最適化できるCSS最適化戦略について説明します。 このように、リファクタリングされたCSSコードベースは、保守性と拡張性が向上するだけでなく、パフォーマンスも向上し、エンドユーザーと管理者の両方にとって重要なすべてのボックスをチェックします。

一部:CSSリファクタリング

  • パート1:CSSリファクタリング:はじめに
  • パート2:CSS戦略、回帰テストとメンテナンス
  • パート3:サイズとパフォーマンスの最適化
  • 次のニュースレターを見逃さないように、メールマガジンを購読してください。

スタイルシートのファイルサイズの最適化

ファイルサイズの最適化は、不要な文字の削除とフォーマット、およびCSSコードを最適化して、ファイル内の文字の総数を減らすためにさまざまな構文または省略形のプロパティを使用することです。

最適化と縮小

CSSの最適化と縮小化は何年も前から行われており、フロントエンドの最適化の定番となっています。 cssnanoやclean-cssのようなツールは、CSSの最適化と縮小に関して私のお気に入りのツールの1つです。 これらは、コードの最適化方法とサポートされるブラウザーをさらに制御するためのさまざまなカスタマイズオプションを提供します。

これらのツールは同じように機能します。 まず、最適化されていないコードが、構成で設定されたルールに従って解析およびトランスパイルされます。 その結果、使用する文字数は少なくなりますが、フォーマット(改行と空白)は保持されます。

 /* Before - original and unoptimized code */ .container { padding: 24px 16px 24px 16px; background: #222222; } /* After - optimized code with formatting */ .container { padding: 24px 16px; background: #222; }

そして最後に、トランスパイルされた最適化されたコードは、不要なテキストフォーマットをすべて削除することで縮小されます。 構成で設定されているコードベースとサポートされているブラウザーによっては、非推奨のベンダープレフィックスを持つコードも削除される可能性があります。

 /* Before - optimized code with formatting */ .container { padding: 24px 16px; background: #222; } /* After - optimized and minified code */ .container{padding:24px 16px;background:#222}

この基本的な例でも、全体のファイルサイズを76バイトから55バイトに減らすことができ、23%の削減になりました。 コードベースと最適化ツールおよび構成によっては、CSSの最適化と縮小がさらに効果的になる場合があります。

CSSの最適化と縮小は、CSSワークフローにわずかな調整を加えるだけで大​​きな見返りが得られるため、簡単に成功すると見なすことができます。 そのため、ミニファイは、プロジェクトのすべてのスタイルシートの最低限のパフォーマンス最適化および要件として扱われる必要があります。

ジャンプした後もっと! 以下を読み続けてください↓

メディアクエリの最適化

CSSでメディアクエリを作成する場合、特に複数のファイル(PostCSSまたはSass)を使用する場合、通常、プロジェクト全体の単一のメディアクエリの下にコードをネストしません。 保守性、モジュール性、およびコード構造を改善するために、通常、複数のCSSコンポーネントに対して同じメディアクエリ式を記述します。

最適化されていないCSSコードベースの次の例を考えてみましょう。

 .page { display: grid; grid-gap: 16px; } @media (min-width: 768px) { .page { grid-template-columns: 268px auto; grid-gap: 24px; } } /* ... */ .products-grid { display: grid; grid-template-columns: repeat(2, 1fr); grid-gap: 16px; } @media (min-width: 768px) { .products-grid { grid-template-columns: repeat(3, 1fr); grid-gap: 20px; } }

ご覧のとおり、読みやすさとメンテナンスを向上させるために、コンポーネントごと@media (min-width: 768px)が繰り返されています。 このコード例で最適化と縮小を実行して、何が得られるかを見てみましょう。

 .page{display:grid;grid-gap:16px}@media (min-width: 768px){.page{grid-template-columns:268px auto;grid-gap:24px}}.products-grid{display:grid;grid-template-columns:repeat(2,1fr);grid-gap:16px}@media (min-width: 768px){.products-grid{grid-template-columns:repeat(3,1fr);grid-gap:20px}}

これは少し読みにくいかもしれませんが、注意しなければならないのは、@ media @media (min-width: 768px)メディアクエリが繰り返されることだけです。 スタイルシートの文字数を減らし、単一のメディアクエリで複数のセレクターをネストできることはすでに結論付けていますが、ミニファイアが重複した式を削除しなかったのはなぜですか? それには単純な理由があります。

CSSではルールの順序が重要であるため、複製されたメディアクエリをマージするには、コードブロックを移動する必要があります。 これにより、ルールの順序が変更され、スタイルに望ましくない副作用が発生する可能性があります。

ただし、メディアクエリを組み合わせると、コードベースと構造によっては、ファイルサイズがさらに小さくなる可能性があります。 postcss-sort-media-queriesのようなツールやパッケージを使用すると、重複したメディアクエリを削除し、ファイルサイズをさらに減らすことができます。

もちろん、ルールの順序に依存しない、適切に構造化されたCSSコードベース構造を持つことには重要な注意点があります。 この最適化は、CSSリファクタリングを計画し、基本ルールを確立するときに考慮に入れる必要があります。

最初に、最適化のメリットが潜在的なリスクを上回っているかどうかを確認することをお勧めします。 これは、CSS監査を実行し、メディアクエリの統計を確認することで簡単に実行できます。 含まれている場合は、後で追加して自動回帰テストを実行し、結果として発生する可能性のある予期しない副作用やバグを検出することをお勧めします。

未使用のCSSの削除

リファクタリングプロセス中に、完全に削除されていない未使用のレガシースタイルが発生したり、使用されていない新たに追加されたスタイルが発生したりする可能性が常にあります。 これらのスタイルは、全体の文字数とファイルサイズにも追加されます。 ただし、自動化されたツールを使用してこれらの未使用のスタイルを削除すると、ツールが実際に使用されているスタイルを正確に予測できないため、多少リスクが伴う可能性があります。

purgecssのようなツールは、プロジェクト内のすべてのファイルを調べ、ファイルに記載されているすべてのクラスをセレクターとして使用します。これは、注意を怠って、動的なJavaScriptが挿入された要素のセレクターを誤って削除しないようにするためです。 ただし、purgecssは、これらの潜在的な問題とリスクの回避策として、柔軟な構成オプションを提供します。

ただし、この改善は、潜在的な利益がリスクを上回っている場合にのみ行う必要があります。 さらに、この最適化手法は、セットアップ、構成、およびテストにかなりの時間を必要とし、将来的に意図しない問題を引き起こす可能性があるため、慎重に進め、セットアップが防弾であることを確認してください。

レンダリングブロックCSSの排除

デフォルトでは、CSSはレンダリングをブロックするリソースです。つまり、リンクされたすべてのスタイルシートとその依存関係(フォントなど)がダウンロードされ、ブラウザーによって解析されるまで、Webサイトはユーザーに表示されません

フォントスタイルシートとフォントファイルの依存関係を持つレンダリングブロックCSSの例
フォントスタイルシートとフォントファイルの依存関係を持つレンダリングブロックCSSの例。 (Creative Commons Attribution 4.0 Licenseのweb.devから)(大きなプレビュー)

スタイルシートファイルのファイルサイズが大きいか、サードパーティのサーバーまたはCDNに複数の依存関係がある場合、ネットワークの速度と信頼性によっては、Webサイトのレンダリングが大幅に遅れる可能性があります。

最大のコンテンツフルペイント(LCP)は、過去数か月で重要な指標になりました。 LCPは、パフォーマンスだけでなくSEOにとっても重要です。LCPスコアが高いWebサイトほど、検索結果のランキングが高くなります。 CSSなどのレンダリングブロックリソースを削除することは、LCPスコアを向上させる1つの方法です。

ただし、スタイルシートの読み込みと処理を延期すると、 Flash Of Unstyled Content (FOUC)が発生します。コンテンツはすぐにユーザーに表示され、しばらくしてからスタイルが読み込まれて適用されます。 このスイッチは耳障りに見える可能性があり、一部のユーザーを混乱させる可能性さえあります。

重要なCSS

クリティカルCSSを使用すると、最初にレンダリングされたときにページで使用されることが保証されている最小限のスタイルでWebサイトを確実にロードできます。 このようにして、FOUCをはるかに目立たなくするか、ほとんどの場合それを排除することができます。 たとえば、ホームページにナビゲーション付きのヘッダーコンポーネントと、折り畳みの上に配置されたヒーローコンポーネントがある場合、これは、重要なCSSに、これらのコンポーネントに必要なすべてのグローバルスタイルとコンポーネントスタイルが含まれ、ページ上の他のコンポーネントのスタイルが含まれることを意味します。延期されます。

このCSSはstyleタグの下でHTMLにインライン化されるため、スタイルはHTMLファイルと一緒にロードおよび解析されます。 これにより、 HTMLファイルサイズがわずかに大きくなりますが(これも縮小する必要があります)、他のすべての重要ではないCSSは延期され、すぐには読み込まれず、Webサイトのレンダリングが速くなります。 全体として、メリットはHTMLファイルサイズの増加を上回ります。

 <head> <style type="text/css"><!-- Minified Critical CSS markup --></style> </head>

セットアップに応じて、重要なCSSを抽出し、遅延スタイルシートを生成できる多くの自動化ツールとNPMパッケージがあります。

スタイルシートの延期

CSSをどの程度正確に非ブロッキングにするのですか? ページのHTMLが最初にダウンロードされるときに、HTMLのhead要素で参照されるべきではないことがわかっています。 Demian Renzulliは、彼の記事でこの方法の概要を説明しています。

レンダリングをブロックするリソースの読み込みを最適化または延期するためのネイティブHTMLアプローチは(現時点では)ないため、JavaScriptを使用して、最初のレンダリング後に重要でないスタイルシートをHTMLマークアップに挿入する必要があります。 また、ユーザーがブラウザーでJavaScriptが有効になっていない状態でページにアクセスしている場合は、これらのスタイルが最適でない(レンダリングをブロックする)方法で読み込まれるようにする必要があります。

 <!-- Deferred stylesheet --> <link rel="preload" as="style" href="path/to/stylesheet.css" onload="this.onload=null;this.rel='stylesheet'"> <!-- Fallback --> <noscript> <link rel="stylesheet" href="path/to/stylesheet.css"> </noscript>

link rel="preload" as="style"を使用すると、スタイルシートファイルが非同期で要求され、 onload JavaScriptハンドラーにより、HTMLドキュメントの読み込みが完了した後に、ファイルがブラウザーによって読み込まれ、処理されます。 ある程度のクリーンアップが必要なため、この関数が複数回実行されて不要な再レンダリングが発生しないように、 onloadnullに設定する必要があります。

これはまさにSmashingMagazineがスタイルシートを処理する方法です。 各テンプレート(ホームページ、記事のカテゴリ、記事のページなど)には、 head要素のHTML styleタグ内にインライン化されたテンプレート固有の重要なCSSと、すべての重要でないスタイルを含む遅延されmain.cssスタイルシートがあります。

ただし、ここでは、 relパラメータを切り替える代わりに、ページの読み込みが完了すると、メディアクエリが自動的に延期された低優先度のprintメディアから高優先度all属性に切り替えられるのを確認できます。 これは、重要ではないスタイルシートのロードを延期するための代替の、同様に実行可能なアプローチです。

 <link href="/css/main.css" media="print" onload="this.media='all'" rel="stylesheet">

メディアクエリを使用したスタイルシートの分割と条件付き読み込み

前述の最適化を適用した後でも、最終的なスタイルシートファイルのファイルサイズが大きい場合は、メディアクエリに基づいてスタイルシートを複数のファイルに分割し、リンクHTML要素で参照されるスタイルシートのメディアプロパティを使用して条件付きでロードできます。 。

 <link href="print.css" rel="stylesheet" media="print"> <link href="mobile.css" rel="stylesheet" media="all"> <link href="tablet.css" rel="stylesheet" media="screen and (min-width: 768px)"> <link href="desktop.css" rel="stylesheet" media="screen and (min-width: 1366px)">

そうすれば、モバイルファーストのアプローチが使用される場合、より大きな画面サイズのスタイルは、低速または信頼性の低いネットワークで実行されている可能性のあるモバイルデバイスにダウンロードまたは解析されません。

繰り返しになりますが、前述の最適化方法の結果が最適ではないファイルサイズのスタイルシートになる場合は、この方法を使用する必要があります。 通常の場合、この最適化方法は、個々のスタイルシートのサイズによっては、それほど効果的でも影響力もありません。

フォントファイルとスタイルシートの延期

フォントスタイルシート(たとえば、Google Fontファイル)を延期することも、初期のレンダリングパフォーマンスに役立つ可能性があります。 スタイルシートはレンダリングをブロックしていると結論付けましたが、スタイルシートで参照されているフォントファイルも同様です。 フォントファイルはまた、初期のレンダリングパフォーマンスにかなりのオーバーヘッドを追加します。

フォントスタイルシートとフォントファイルのロードは複雑なトピックであり、それに飛び込むには、実行可能なすべてのアプローチを説明するためだけにまったく新しい記事が必要になります。 幸いなことに、ザックレザーマンは、この素晴らしい包括的なガイドで多くの実行可能な戦略を概説し、各アプローチの長所と短所を要約しました。 Google Fontsを使用している場合、HarryRobertsはGoogleFontsを最速でロードするための戦略を概説しています。

フォントスタイルシートを延期することにした場合は、Flash of Unstyled Text(FOUT)になります。 据え置きフォントファイルとスタイルシートがダウンロードされて解析されるまで、ページは最初にフォールバックフォントでレンダリングされ、その時点で新しいスタイルが適用されます。 この変更は非常に目立ち、個々のケースによっては、レイアウトの変更やユーザーの混乱を引き起こす可能性があります。

Barry Pollardは、FOUTに対処するのに役立ついくつかの戦略を概説し、FOUTに対処するためのより簡単でネイティブな方法を提供する今後のサイズ調整CSS機能について話しました。

サーバー側の最適化

HTTP圧縮

縮小とファイルサイズの最適化に加えて、HTML、CSSファイル、JavaScriptファイルなどの静的アセット。GzipやBrotliなどのHTTP圧縮アルゴリズムを使用して、ダウンロードしたファイルサイズをさらに減らすことができます。

HTTP圧縮は、技術スタックと構成に依存するサーバーで構成する必要があります。 ただし、ブラウザは圧縮ファイルを解凍して解析する必要があるため、パフォーマンス上の利点はさまざまであり、標準のスタイルシートの縮小や最適化ほどの影響はない可能性があります。

スタイルシートのキャッシュ

静的ファイルのキャッシュは、便利な最適化戦略です。 ブラウザは、最初の読み込み時にサーバーから静的ファイルをダウンロードする必要がありますが、キャッシュされると、後続のリクエストでサーバーから直接読み込まれるため、読み込みプロセスが高速化されます。

キャッシュは、サーバーレベルでCache-Control HTTPヘッダーを介して制御できます(たとえば、Apacheサーバーの.htaccessファイルを使用)。

max-ageを使用すると、ファイルをブラウザーにキャッシュしておく時間(秒単位)を指定でき、 publicを使用すると、ファイルをブラウザーやその他のキャッシュでキャッシュできることを示します。

 Cache-Control: public, max-age=604800

静的アセットのより積極的で効果的なキャッシュ戦略は、 immutableの構成で実現できます。 これにより、この特定のファイルは変更されず、新しい更新を行うとこのファイルが削除され、別のファイル名の新しいファイルが代わりに使用されることがブラウザに通知されます。 これは、キャッシュバスティングとして知られています。

 Cache-Control: public, max-age=604800, immutable

適切なキャッシュ無効化戦略がないと、ユーザーのブラウザにキャッシュされるファイルを制御できなくなるリスクがあります。 つまり、ファイルが変更された場合、ブラウザは、更新されたファイルをダウンロードし、古いキャッシュファイルを使用しないようにする必要があることを認識できません。 そして、その時点から、それを修正するために私たちができることは事実上何もありません。ユーザーは、期限切れになるまで古いファイルで立ち往生します。

スタイルシートの場合、新しいスタイルを必要とする新しいコンテンツやコンポーネントでHTMLファイルを更新した場合、古いスタイルシートはキャッシュ無効化戦略なしでキャッシュされ、ブラウザはそれを認識しないため、これらのスタイルは表示されません。新しいファイルをダウンロードする必要があります。

スタイルシートやその他の静的ファイルにキャッシュ戦略を使用する前に、効果的なキャッシュ無効化メカニズムを実装して、古い静的ファイルがユーザーのキャッシュにスタックするのを防ぐ必要があります。 キャッシュバスティングには、次のバージョン管理メカニズムのいずれかを使用できます。

  • ファイル名にクエリ文字列を追加します。
    たとえば、 styles.css?v=1.0.1. ただし、一部のCDNは、ファイル名からクエリ文字列を完全に無視または削除する可能性があり、その結果、ファイルがユーザーのキャッシュにスタックし、更新されなくなります。
  • ファイル名の変更またはハッシュの追加。
    たとえば、 styles.a1bc2.cssまたはstyles.v1.0.1.css. これは、ファイル名にクエリ文字列を追加するよりも信頼性が高く、効果的です。

CDNまたはセルフホスティング?

コンテンツ配信ネットワーク(CDN)は、画像、ビデオ、HTMLファイル、CSSファイル、JavaScriptファイルなどの静的アセットの信頼性の高い高速配信に一般的に使用される地理的に分散したサーバーのグループです。

CDNは、セルフホスティングの静的アセットの優れた代替手段のように見えるかもしれませんが、ハリーロバーツはこのトピックについて詳細な調査を行い、セルフホスティングアセットの方がパフォーマンスに有益であると結論付けました。

「静的資産を他の人のインフラストラクチャに残す理由はほとんどありません。 認識されている利点はしばしば神話であり、そうでなかったとしても、トレードオフは単に価値がありません。 複数のオリジンからのアセットの読み込みは明らかに遅くなります。」

そうは言っても、デフォルトでスタイルシート(可能であればフォントスタイルシートを含む)をセルフホスティングし、実行可能な理由やその他の利点がある場合にのみCDNに移行することをお勧めします。

CSSファイルのサイズとパフォーマンスの監査

WebPageTestおよびその他の同様のパフォーマンス監査ツールを使用して、Webサイトの読み込みプロセス、ファイルサイズ、レンダリングブロックリソースなどの詳細な概要を取得できます。これらのツールを使用すると、さまざまなデバイスでWebサイトがどのように読み込まれるかを知ることができます。高速ネットワークで実行されているデスクトップPCから、低速で信頼性の低いネットワークで実行されているローエンドのスマートフォンまで。

このシリーズの最初の記事で言及されているWebサイト(2MBの縮小されたCSSを使用しているWebサイト)でパフォーマンス監査を実行してみましょう。

まず、コンテンツの内訳を見て、どのリソースが最も多くの帯域幅を使用しているかを判断します。 次のグラフから、画像がほとんどのリクエストを処理していることがわかります。つまり、画像を遅延読み込みする必要があります。 2番目のグラフから、スタイルシートとJavaScriptファイルがファイルサイズの点で最大であることがわかります。 これは、これらのファイルを縮小して最適化するか、リファクタリングするか、複数のファイルに分割して非同期でロードする必要があることを示しています。

MIMEタイプごとのコンテンツの内訳を示す2つのグラフ
MIMEタイプ別のコンテンツ内訳(最初のビュー)。 (大プレビュー)

Web Vitalsチャートから、さらに多くの結論を引き出すことができます。 Largest Contentful Paint(LCP)チャートを見ると、レンダリングブロックリソースの詳細な概要と、それらが最初のレンダリングにどの程度影響するかを知ることができます。

ウェブサイトのスタイルシートがLCPと読み込み統計に最も影響を与えるとすでに結論付けることができます。 ただし、フォントスタイルシート、JavaScriptファイル、およびスタイルシート内で参照されている画像は、レンダリングをブロックしていることがわかります。 前述の最適化手法を適用して、レンダリングブロッキングリソースを排除することでLCP時間を短縮できることを知っています。

最大のコンテンツフルペイントチャート
8561msで発生する最大のコンテンツフルペイントのチャート。 リソースのリストのタイムラインにあるオレンジ色の電球に注目してください。これらのリソースはレンダリングをブロックしています。 (大プレビュー)

結論

コードの正常性と品質が改善され、コードベースの弱点と問題が修正された場合、リファクタリングプロセスは完了しません。 リファクタリングされたコードベースは、従来のコードベースと同じか、パフォーマンスが向上するはずです。

エンドユーザーは、リファクタリングされたコードベースからのパフォーマンスの問題や長い読み込み時間を経験するべきではありません。 幸いなことに、コードベースが堅牢でパフォーマンスが高いことを確認するための多くの方法があります。単純な縮小と最適化の方法から、レンダリングブロックリソースの排除やコード分割などのより複雑な方法までです。

WebPageTestなどのさまざまなパフォーマンス監査ツールを使用して、読み込み時間、パフォーマンス、レンダリングブロックリソース、およびその他の要因の詳細な概要を取得できるため、これらの問題に早期かつ効果的に対処できます。

一部:CSSリファクタリング

  • パート1:CSSリファクタリング:はじめに
  • パート2:CSSリファクタリング:戦略、回帰テスト、およびメンテナンス
  • パート3: CSSリファクタリング:サイズとパフォーマンスの最適化
  • 次のニュースレターを見逃さないように、メールマガジンを購読してください。

参考文献

  • 「レンダリングブロッキングCSS」、Ilya Grigorik
  • 「非重要なCSSを延期する」、Demian Renzulli
  • 「フォント読み込み戦略の包括的なガイド」ZachLeatherman
  • 「フォント読み込みの影響を減らす新しい方法:CSSフォント記述子」Barry Pollard
  • 「静的資産をセルフホストする」ハリー・ロバーツ
  • 「WebFontの読み込みとレンダリングを最適化する」IlyaGrigorik