RSS

CSSセレクタによる高速化、実際のところ

by tomita on 2011.10.6


突然のジョブズ氏逝去のニュースに驚きました。
windowsからmacに移って一年に満たないにわかマカーですが、ご冥福をお祈りいたします。
ネイバージャパンでマークアップを担当している富田です。

さて、今回はサイトの高速化について、とくに、MEひとりでも実施可能なCSSとHTMLのみでの高速化の手法とそれを実施する上で注意すべきポイントについて見てみたいと思います。

高速化のテクニックと、コーディング時のコスト

CSSのセレクタは、body .contents .header span aというように、左から右により詳細になっていくように指定するかたちが一般的です。
しかしブラウザはこれとは逆に、右から左にセレクタを解釈しながら描画していきます。

そのため、より負荷のすくないCSSを書くために、

  • スタイルを当てる要素にはできるだけclass又はIDを指定する
  • 子孫セレクタは重いので、できるだけ減らす

ということを念頭においておくと良いと言われています。

ただ、そうは言っても、日々マークアップ作業をしていく中で、このような点を忠実に守ろうとすると面倒くさい時間的なコストが発生する場合があります。

例えば

<div>
<ul>
<li><span><a href="#">hoge</a></span></li>
</ul>
</div>

というような構造で、liが数十個繰り返されるHTMLがあった場合、繰り返されたaタグやspanタグすべてにclass名を振ったとすると、ゴチャゴチャとして見づらい、管理のしづらいHTMLになってしまいます。

また子孫セレクタを減らしたほうがいいとはいっても、HTMLの構造と親子関係が一致しているCSSのほうが、継承関係が見えやすいため、直感的に作業しやすく、他人が書いたコードでも追いやすくなる利点があります。

余談ですが、sass(CSSを拡張するメタ言語)を導入したことで、CSSよりも簡単な記述で、非常に見やすいツリー構造のCSSを書くことができるようになりました。
その他にも、コードを再利用できるMixin機能や、値の演算ができたりなど、痒いところに手が届くとはまさにこのこと。
一度手を染めてしまうと、もう普通のCSSは面倒くさくて書く気がしません。ビバsass!!

閑話休題

このように、場合によっては開発、運用時のコスト増加とトレードオフとなる場合があるため、やみくもに導入する前に、その施策にはどの程度効果があるのかという点を理解しておく必要があります。

実際に測ってみる

これらの施策は、実際どの程度効果があるのでしょうか。
サンプルファイルを作って計測してみます。

サンプルコード

<div class="cl01"><span class="cl01sp">01</span>
<div class="cl02"><span class="cl02sp">02</span>
<div class="cl03"><span class="cl03sp">03</span>
<div class="cl04"><span class="cl04sp">04</span>
<div class="cl05"><span class="cl05sp">05</span>
<div class="cl06"><span class="cl06sp">06</span>
<div class="cl07"><span class="cl07sp">07</span>
<div class="cl08"><span class="cl08sp">08</span>
<div class="cl09"><span class="cl09sp">09</span>
<div class="cl10"><span><span class="cl10sp">10</span></span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

上記のHTMLに対して、
以下のパターンでCSSを作成し、計測してみます。

  1. クラス名 .cl10
  2. クラス名 クラス名 .cl01 .cl10sp
  3. クラス名 タグ .cl10 span
  4. クラス名 タグ(HTMLにあわせてネスト)
    .cl01 div div div div div div div div div span span
  5. タグ クラス名(HTMLにあわせてネスト)
    div div div div div div div div div div span .cl10sp
  6. クラス名 クラス名(HTMLにあわせてネスト)
    .cl01 .cl02 .cl03 .cl04 .cl05 .cl06 .cl07 .cl08 .cl09 .cl10 .cl10sp

上記の結果はすべて同じで、「10」が赤く表示されます。

ブラウザの挙動がCSSを右から解釈するならば、一番右がタグになっている3、4が重くなりそうです。
また、子孫セレクタが重いのであれば4、5、6も重くなりそうです

上記HTMLを10回、CSSを300回繰り返した状態で、JSを使ってload時間とload完了時間の差分を計測した結果が以下となります。

※計測ブラウザは
Internet Explorer 8
Firefox 7
Google Chrome 12

IE Fx Cr
1. 16 6 13
2. 16 7 13
3. 31 10 16
4. 32 11 15
5. 16 9 15
6. 16 9 15

※単位はms

IEでは3,4が顕著に、Fxでも3,4がやや重くなりました。

HTML、CSSともに10倍繰り返した結果でも計測してみます。

IE Fx Cr
1. 110 149 80
2. 152 170 150
3. 672 489 153
4. 813 541 182
5. 188 220 187
6. 204 252 188

※単位はms

やはり3、4がかなり重くなっていますが、5、6についても影響が見られます。

ということで、確かに

  • スタイルを当てる要素にはできるだけclass又はIDを指定する
  • 子孫セレクタは重いのできるだけ減らす

という施策に一定の効果はあるようですが、その効果が如実に現れるのはHTML、CSSのコードが非常に大きいページに限られるようです。

そのなかでも、子孫セレクタを減らす施策よりも、スタイルを当てる要素にはできるだけclass名を指定する施策のほうが、効果があるようです。

また、google cromeでは3、4でも他のケースとあまり変化がないところをみると、他のブラウザについても、今後のバージョンアップにともなって改善される場合があるかもしれません。

バランスが大事

施策の仕組を理解せずに盲目的にルール化してしまうと、過度な最適化となり、開発、運用を含めた日々の作業に思わぬコストが発生してしまうこともあります。
また、速度改善のためのボトルネックはもっと他にあり、そちらに工数をかけたほうがはるかに効果的な場合もあります。

結論としてはありふれたものとなりますが、それが本当に有効と言えるか、導入の前に広い視野からコストとメリットを比較してみることが重要ではないでしょうか。