COLUMN コラム
2021.8.18
CSSセレクタを最適化してWebサイトを高速化
Webデザイナーの中にはデザインだけでなくコーディングまで担当している方も多いと思いますが、CSSがどのような処理を経てHTMLに適用されているかご存知でしょうか?
CSSでスタイルを指定するセレクタには「要素型セレクタ」や「クラスセレクタ」「子孫セレクタ」「隣接セレクタ」など色々ありますが、使用するセレクタによってはHTMLへの適用処理に時間がかかり、パフォーマンス低下の要因となるものがあります。
今回はCSSがHTMLに適用される仕組みと、パフォーマンス向上のための改善ポイントについて紹介します。
目次
1. ブラウザのレンダリング
1-1. Loading
1-2. Scripting
1-3. Rendering
1-4. Painting
2. スタイルの計算(Calculate Style)
2-1. マッチング処理は総当り
2-2. CSSセレクタの処理は右から左
3. CSSの最適化
3-1. CSSセレクタをシンプルにする
3-2. 子孫セレクタや間接セレクタを控える
3-3. 不要なCSSルールを削除する
おわりに
1. ブラウザのレンダリング
CSSがHTMLにどのように適用されているかを知るには、ブラウザのレンダリングについて理解する必要があります。ChromeやSafariなどブラウザによって使用されているレンダリングエンジンは異なりますが、いずれもページが表示されるまでのプロセスは、次の4つのフェーズに分けることができます。
1-1. Loading
最初のフェーズではリソースの「ダウンロード」と「パース」の2つの処理が行われます。
「リソースのダウンロード(Download)」
最初にHTMLを取得し、その中で参照されているCSS、JavaScript、画像ファイルといったリソースが読み込まれます。
「リソースのパース(Parse)」
取得したリソースをパース(構文解析)して、レンダリングエンジンの内部表現に変換します。
・HTML → DOMツリー(Document Object Model)に変換。
・CSS → CSSOMツリー(CSS Object Model)に変換。
1-2. Scripting
JavaScriptのコードをJavaScriptエンジンに引き渡して実行します。
1-3. Rendering
レイアウトツリーを構築します。このフェーズでは「スタイルの計算」と「レイアウト」の2つの処理が行われます。
「スタイルの計算(Calculate Style)」
DOM要素に対して、どのCSSプロパティが適用されるかを計算する。
「レイアウト(Layout)」
要素の大きさや余白、位置などのレイアウト情報を計算する。
1-4. Painting
最後にレンダリング結果を描画します。このフェーズでようやくユーザーが見る画面が描画されます。ここでは「ペイント(Paint)」「ラスタライズ(Rasterize)」「レイヤーの合成(Composite Layers)」の3つの処理が行われます。
これら4つの処理にかかる時間は、Chromeの開発者ツールで確認することができます。
2. スタイルの計算(Calculate Style)
CSSがHTMLに適用されるのは「Rendering」フェーズの「スタイルの計算(Calculate Style)」になります。ここからはCSSがどのように処理されているのかを紹介します。
2-1. マッチング処理は総当り
「Loading」フェーズで構築されたDOMツリーとCSSOMツリーから、すべてのDOM要素に対して、どのCSSプロパティが当たるのかを計算します。この時の計算方法は、すべてのDOM要素にどのCSSルールのセレクタがマッチするのか総当りしていきます。例えばDOM要素が100個、CSSルールが50個あった場合、100×50=5,000回のマッチング処理が行われることになります。
1つのDOM要素に複数のCSSルールがマッチする場合は、CSSルールの詳細度を算出して、適用するCSSプロパティを判断していきます。
2-2. CSSセレクタの処理は右から左
あるDOM要素とCSSルールが適合するかどうかは、CSSセレクタのマッチング処理によって判別されます。そしてCSSセレクタのマッチング処理は、右から左に向けて行われます。
例)CSSセレクタのマッチング処理の流れ
body > .header > a.logo { ... }
1. DOM要素のclassに「logo」が含まれている
2. その要素名が「a」である
3. その親要素のclassに「header」が含まれている
4. その親要素のDOM要素名が「body」である
一見、記述通りに左から右へ処理されていくと思ってしまいがちなので注意です。右から順に一つ一つの試行がすべて通って、はじめてマッチしているとみなされます。
3. CSSの最適化
CSSがHTMLに適用される仕組みを知ると、改善するポイントが見えてきます。ここからはパフォーマンスを考慮したCSSセレクタの記述方法について紹介します。
3-1. CSSセレクタをシンプルにする
CSSセレクタの処理が右から左に行われるということは、セレクタの記述が長ければ長いほど、処理に時間がかかるということになります。これを改善する方法はセレクタの記述をシンプルにすることです。複数のセレクタを組み合わせて指定するのをやめて、クラスセレクタ1つで記述することでマッチング処理が最速になります。
例1)h1タグにclassを付与する
// BAD
div.box > h1 { ... }
// GOOD
.box__title { ... }
例2)aタグにclassを付与する
// BAD
nav.g-nav > ul > li > a { ... }
// GOOD
.g-nav__link { ... }
CSSセレクタをシンプルに記述するには、CSS設計の「BEM」を取り入れるのが有効です。BEMは基本的に1つのクラスセレクタのみを使用するルールとなっており、classの命名規則も定まっているため、非常に効率良くコーディングを進めることができます。
BEMについては以前のコラムでも紹介しているので、合わせてご覧ください。
https://dol.co.jp/column/bem%e3%83%bbflocss%e3%81%ab%e3%82%88%e3%82%8bcss%e8%a8%ad%e8%a8%88%e3%81%ae%e3%81%99%e3%81%99%e3%82%81/
3-2. 子孫セレクタや間接セレクタを控える
子孫セレクタや間接セレクタは要素の親子関係で指定するため、必然的にセレクタの記述が長くなってしまいます。また、これらのセレクタはマッチング処理でたどる要素が大きくなりすぎてしまうので、極力使用するのは控えましょう。
例)子孫セレクタ
#wrapper .box { ... }
例)間接セレクタ(h1以降にあるp要素)
h1 ~ p { ... }
3-3. 不要なCSSルールを削除する
コーディングを進めていると初期に記述したCSSルールで不要なものも出てきますが、忘れずにしっかり削除しましょう。CSSセレクタのマッチングは総当りで行われるので、不要なCSSルールを1つでも減らすことができれば、DOM要素の数だけ処理を減らすことができます。
おわりに
今回はブラウザレンダリングの仕組みと、CSSセレクタの最適化について紹介しました。
Webデザイナーとして勤めている方でも、CSSセレクタが右から処理されていることを知らなかった…という人はいるのではないでしょうか?ブラウザレンダリングの仕組みを知らなくてもサイトを作ることは可能ですが、仕組みを理解していないとサイトが重たくなる要因がどこにあるのか気付くことができません。優れたUX(ユーザー体験)を提供するためにも、パフォーマンス向上となるポイントがどこなのか把握できるようにしておきましょう。
弊社では士業やメディア、医療関係を中心にサイト制作を行っております。Webサイトについてお悩みのある方はお気軽にお問い合わせください。
『Webフロントエンド ハイパフォーマンス チューニング』久保田光則・著