CSSセレクタの高速化の話を検証
CSSセレクタの高速化の話し - Webtech Walkerの件。元ネタは続・ハイパフォーマンスWebサイト ―ウェブ高速化のベストプラクティスで、元ネタの元ネタはWriting Efficient CSS for use in the Mozilla UI - MDC。
先に書いておくと、この元ネタのMozillaの記事には、in the Mozilla UIとある通り、FirefoxなどのUIレベルの話です。Mozillaの場合、ウィンドウとかタブとか、とにかくなんでもCSSでスタイルを指定できる(している)のでCSSのパフォーマンスについて考慮する点が他のブラウザとはズレています。
とはいえ、実際にどうなのか検証したことなかったので、少し試してみました。
今回の検証方法は、dl>dt+ddを5重に入れ子にした300KB強の大きめなHTMLを用意して、CSSを動的に適用したときの時間を計測してみました。
検証ページはCSSセレクタのパフォーマンスです
結果はこんな感じに。(単位はms)
ブラウザ | IE6 | IE8 | Chrome5 | Firefox3.6 | Opera10.53 |
.class | 3 | 10 or 20*1 | 29.2 | 0 | 1.5 |
#ID tag.class | 3 | 20.6 | 29.7 | 0 | 2 |
body … tag.class | 2 | 20.8 | 30 | 0 | 2 |
実行時間*2 | 880 | 2000 | 850 | 1200(610)*3 | 430 |
意外にIE6が高速、だけど、よく考えてみるとシンプルなセレクタにしか対応してないからだろうなと察しが付く…。Firefoxは大変優秀で、この程度のHTMLは余裕らしい。しかし、Chromeが遅いのが本当に意外。Safari4も同じようなものなので、-webkitの代償なんでしょうか…(まあ、そのうち修正されるでしょう)。
ブックマークコメントで id:miya2000 さんからFirefoxは非同期処理しているのではという指摘がありましたが、実はその逆です。CSSの適用後、すぐにリセットする処理を入れているので、Firefox以外のブラウザはレンダリングしないのですが、Firefoxだけはその一瞬をレンダリングします。dl{height:0;}のようなCSSを実行してスクロールバーの動きをみるとわかりやすいです。
id:shinichiro_hさんのコメント受けて、実行ボタンを押してから終了するまでの時間を測るとOpera:Chrome:Firefox:IEの順番に。Firefoxは計測した箇所ではほとんど何もせず、遅延評価しているような印象です。もちろん、このテストはブラウザのベンチマークとして作ったものではないので、そういった目的ならPeacekeeperなどを試すのが良いでしょう。
そもそも、この記事は「CSSセレクタの高速化」というが本当に効果のあるものなのかという疑問から、その部分を検証するために書いたのですが、その結果をこのように貼ってみるとついブラウザ間の差に目が言ってしまいますね(と、書いてる私自身も…。反省。)。繰り返しますが、そこはあくまでおまけ程度に見ていただければと。
ついでに、同じセレクタでquerySelectorAllを実行してみた場合はこんな感じに。
ブラウザ | IE6(jQuery) | IE8 | Chrome5 | Firefox3.6 | Opera10.53 |
.class | 204.4 | 50 | 24.7 | 95.8 | 49.5 |
#ID tag.class | 108.2 | 65 | 41.4 | 110.8 | 67.3 |
body … tag.class | 483 | 66.4 | 50.5 | 119.5 | 80 |
こちらの場合、元ネタの通りクラス名だけの方が速いという結果に。なるほど、元ネタは間違ってはいないようです。
まとめ
と、その前に、今回の検証はHTMLやセレクタの組み合わせの1つのケースでしかないので、この結果もしかりです。
- セレクタを複雑にしてもパフォーマンスにはほとんど影響はない
- JavaScriptからquerySelectorAllを使うときはクラス名だけのほうが高速だけど、IE6,7のことを考えるならせめてタグ名は指定したほうが良い
結論は予想通り、ありきたりとも言う。
追記: id:arikuiさんのSelectorの話し - f8gはシンプルなHTMLでのquerySelectorAllの検証。傾向は大体同じ。
あわせて読みたい:t32k.com
おまけで、CSSを動的に適用する方法はこんな感じに。
var style, css; if (document.createStyleSheet){ // IE style = document.createStyleSheet(); css = function(s){ style.cssText = s; } } else { style = document.createElement('style'); document.getElementsByTagName('head')[0].appendChild(style); css = function(s){ style.textContent = s; } } /* var s = +new Date; css('*{color:red;}'); var t = new Date - s; */