スタイルシートをシンプルに効率よくすることは、ネットワーク転送量の低下、パース速度の向上、そしてHTMLとのマッチング効率化に繫がります。これはページのパフォーマンスを大きく向上させることに繫がります。
前回は大まかなブラウザの挙動を見ました。
今回は、そういった動きを踏まえた上で、やってしまいがちな非効率なスタイル指定を挙げてみます。そういった指定を避けることで、軽量で高速なスタイルシートを記述することができるでしょう。
なお、この記事は、Google Page Speedの”“および、Mozillaの”Writing Efficient CSS for use in the Mozilla UI“などを元に書いています。
1. 不要なスタイルは書かない
言うまでもない大前提です。ですが、ちょっと調べてみると意外と多いのではないでしょうか。
例えばサイト内で幾つかのパターンのページがあります。しかしひとつの外部cssを使っているため、それぞれのページでは不要なスタイルを大量に読み込んでいるようなことは無いでしょうか。
または、ページを変更してコンテンツを入れ替えた場合、新しいコンポーネントのためのスタイルは当然追加しますが、削除した方のスタイルは削除しているでしょうか。
確かにファイルがキャッシュされれば転送時間は軽減できますが、それでも余分なスタイル記述はDisk I/Oの増加をもたらすだけでなく、ルールの多さはそのままマッチングコストの増加に繫がります。
を用いれば、そのページで使っていないルールを確認できます。
スタイルはスクリプトに比べて分割ダウンロードもしやすいので、使いやすい単位にcssを分割するなどして、可能な限り不要なスタイルを書かないようにしましょう。
2. Universal Rulesを使わない (出来れば、Tag Rulesも)
前回説明しましたが、Keyセレクタによってルールは4種類に分けられます。その際に最も非効率なのが、Universal Rulesです。Universal Rulesはつまり、IDでもクラスでも要素でも無いルールです。これは全ての要素が常に立ち止まって確認するルールになってしまいます。
次にパフォーマンスの悪いのは、Tag Rulesです。これらを極力避けるようにしましょう。
3. IDをタグやクラス名とあわせない
IDはページ内で完全に一意なものなので、そこにタグやクラス名を重ねることは全くの無駄です。
場合によっては、スクリプトなどでクラス指定を切り替え、それによって動きを変えたい場合があるかもしれません。しかしその場合でも、クラス名の方をユニークにすることで無駄な評価を避けられるはずです。
また、ひとつのcssファイルを複数ページで使いまわし、その時にページによって同じIDのあたるタグが変わることでルールを変えるような運用も、前述のような理由で避けるべきです。
× button#backButton { ... } × .menu-left#newMenuIcon { ... } ○ #backButton { ... } ○ #newMenuIcon { ... }
4. 子孫セレクタを使わない
次のようなセレクタを、descendant(子孫)セレクタと呼びます。
body * {...} #footer h3 {...} * html #atticPromo ul li a {...]
これは関係を辿るセレクタとしては最低jといってよいほどにかかるので、極力避けましょう。
と書くと、ショックを受ける人もいるのではないでしょうか。(自分は最初にこれを聞いた時、少なからずそうでした)
CssはCASCADE Styele Sheetです。「カスケード」はまさに、こういった入れ子での制御を使いこなすことだと思っていました。
しかし、前回のエントリを見ていただいたら分かるのではないかと思うのですが、要素がマッチする限りDOMツリーを辿ることを繰り返さなければなりません。この上でKeyセレクタがTagもしくはUniversalであれば、まさに最悪です。(先ほど挙げた例は、まさにそれです)
要素の関係性で表現するのではなく、クラス指定などを用いて効率の良いマッチングが行えるようにしましょう。
例えば次のようなスタイルを書くよりも、
.side-menu ul li { ... } .side-menu ol li { ... } .top-menu ul li { ... }
各li要素にクラス指定を行った方が、マッチングコストは安くあがります。
.side-menu-list { ... } .side-menu-list { ... } .top-menu-list { ... }
5. 子セレクタを使わない
子孫セレクタほどではありませんが、child(子)セレクタも非常に高コストです。
特にTag RulesやUniversal Rulesと組み合わせてはいけません。特にルールが頻繁にマッチしてしまうと、辿る回数はその分だけ増えていきます。例えば次のようなルールは、その親要素であることが稀であり、無駄にコストを上げてしまう一例です。
form > input { ... } dl > dt { ... } table > thead > tr > th { ... }
前の子孫セレクタ同様に、クラス指定などでの直裁的な指定をするようにしましょう。
6. :hover擬似セレクタを使わない
:hover擬似セレクタの指定は、どんな場合であれパフォーマンスに悪影響を与えますが、特にアンカー(aタグ)でない要素に対して用いると問題が多くなります。
div:hover * div:hover
出来るならば、擬似セレクタではなく javascript の onmouseover などによる制御を行いましょう。
7. 継承に委ねる
親要素から自動的に継承されるスタイルをきちんと理解して、無駄な指定を省きましょう。
例えば list-style-image スタイルは親要素から継承されます。これを知っているかどうかで、場合によっては次のようなスタイルルールを作ってしまうかもしれません。
div.star-list ul li { list-style-image: url( star.gif ); }
しかし、これは次のような指定で充分です。
div.star-list { list-style-image: url( star.gif ); }
些細なことのようですが、ここでulブロックやli要素が数百あったらどうでしょう。上の例では、その数百の要素に対して「先祖がulで、その先祖がstar-listというクラスを持つdiv要素であるか」という評価を繰り返すことになってしまいます。しかし下の例であれば、その数百のli要素群は全くマッチングコストをかけることなく、同じ効果を与えられます。
なお、ここで言う「効率が良い」とは、あくまで実行時のパフォーマンスにフォーカスしたものです。開発やメンテナンスなどの管理効率などとは相反するような場合もあるかもしれません。
しかし、ここで挙げられていることはよく読めば、「直接指定」や「重複を避ける」など、スタイル指定のスパゲティ化を避ける方法とも言えます。
ページの高速化は何よりのユーザビリティ向上なので、うまくバランスをとりながらパターンを確立していきましょう。
Related posts:
- [css] ページにスタイルがあてられる仕組みを学ぶ