パフォーマンスからみるSass/Compass 第1回:Nestingと@import
2012年7月12日 by t32k | Filed under performance.タイトルは釣り、かつ第2回以降は未定ですがコンチワ!t32kです。メモがてら残していこうと思います。
Sassとかいろんな機能ありますよね、でもぶっちゃけそんなにいっぱい機能あっても使わないし( ・´ω・`) 案外、//ダブスラでコメントアウトできるのが一番嬉しかったりもします今日このごろです。
@import
というわけで、そんな僕がSassを使うと思ったのも@importを使いたかったからという至極単純な動機によるものです。@import自体は普通のCSSでも使えますが、パフォーマンス的に難がありまして、あんまり使う気になれない、かといってファイル管理はページ単位やコンポーネント単位でちゃんとやらないと後々めんどいなというジレンマもあります。
そうゆうわけで、なんで普通の@importがダメなのか説明します。
IEにおいて@importはページ下部に置いた<link>タグのような挙動をします。
Yahoo!のパフォーマンスベスト・プラクティスにおいて、上記のような記述がありました。Styleの情報というのはできる限りページ上部に置いてレンダリングを早く開始させる必要があるのでこれは頂けませぬ。
まぁ基本的に@importのパフォーマンス的問題はIE以外ならOKであれば使ってもいいのかなと思ってたんですけど、よくよく調べてみるとそうでもなかったですという話。
/* first.css */
@import url("second.css")
まぁ上記のような<link>で読み込んだfirst.cssでsecond.cssを@importするといった例があるとします。これがどのような挙動をするのかと言いますと、
ブラウザーはsecond.cssをダウンロード可能と発見する前に、必ずfirst.cssのダウンロード、パース、実行をする。
Minimize round-trip times – Make the Web Faster — Google Developers
Googleの方には上記のようなことが書かれていました。つまり、first.cssを読み込み完了してからsecond.cssを読み込みに行くので並列ダウンロードができないってことです。これってIEに限ったことではなくてすべてのブラウザーで起こりうることらしいです。マジかいや!てことで、Steve Soudersセンセのテストケースを最新のChromeのNetworkパネルで見てみると本当にそうでした。さーせん!ということで、やっぱり普通の@importは使うべきではないですな。
詳しくは下記ブログ読むと良いよ。
まぁ、そうゆうわけでSassの@importですよ。基本ローカル環境でコンパイルして一つのCSSファイルにまとめるので、読み込むのは実質1ファイルだけになるんですね。それでいて、ページ単位やコンポーネント単位でファイル分割できるのでコードの見通しも悪くならない、素敵です。sass –watchとかScoutとか使えば毎回手動でコンパイルしなくても更新があれば自動的にコンパイルしてくれます。
// Sass
@import "_reset";
@import "_common";
@import "_header";
@import "_main";
@import "_footer";
これだけのためにでもSass導入してもいいんじゃないかと個人的には思っています。
Nesting
あと、便利っちゃー便利なのがネストです。下記のようにセレクタ、プロパティの重複する部分ってのを省略して書けます。
// Sass
table.hl {
margin: 2em 0;
td.ln {
text-align: right;
}
}
li {
font: {
family: serif;
weight: bold;
size: 1.2em;
}
}
上記は下記のようにコンパイルされます。
/* CSS */
table.hl {
margin: 2em 0;
}
table.hl td.ln {
text-align: right;
}
li {
font-family: serif;
font-weight: bold;
font-size: 1.2em;
}
子孫セレクタとか何回も同じセレクタを宣言するのはめんどいですよね。あとモジュール単位で、例えば.module{}以下に必要なスタイルをネストしておけば、そのモジュールが要らなくなったりとか修正が必要になった時とか対応が楽です。
とは言いつつも、そのモジュールの見通しが甘くて案外複雑なことをやらないとだめになりネストが3階層、4階層となってしまう時があります。そうなるとコンパイルされたCSSというのは子孫セレクタとかでつながった長いセレクタになってしまいます。
これってどーなのよ?って話ですよね。はじめに言っておきますが気にしなくてもいい。
世の中にはCSSセレクタの最適化というものがありまして、要はCSSセレクタの解釈というのは右から左へとされていくわけでして、セレクタが長ければ長いほど解釈するのに時間がかかるので、単一のクラスセレクタとかにしたらいいよーみたいな話です。
これってどんだけの程度なのよ!?ってことが気になります。詳しくは下記翻訳でまとめられています。
1000個のCSSセレクタを改善しても20msくらいしか変わらなかったという結論です。これは2009年の話でして、世の中進歩しています。
2011年の年末に書かれた上記の記事ではwebkitに関してですが、CSSセレクタのマッチング処理ってのはブラウザ側で最適化されているという話です。
- Style Sharing
- Rule Hashes
- Ancestor Filters
- Fast Path
上記のような改善がされていてるとのことでして、詳しいことは日本語で解説されてる以下のブログで(素敵!)
まぁ要するに2009年段階でも気にしなくてもいいレベルだったのにそれから2年経ってさらに気にしなくてもいいレベルになってきた感じです。
/* Baseline
コード量の差をなくすためにマッチングしないセレクタが記述されている*/
.noclass0001 { background: #CFD; }
/* Descendant*/
DIV DIV DIV P A.class0001 { background: #CFD; }
- CSS Selectors: Baseline (ベースライン)
- CSS Selectors: Descendant (子孫セレクタ)
試しに、最新のChromeで上記のSoudersセンセのテストケースをもう一度やってみると、数ミリ秒しか変わんなかったです。1000個のセレクタ改善しても数ミリ秒しか違わないのは費用対効果悪すぎです。
ってことで、Sassでネストしまくって、それによるセレクタの解釈遅延ってのは気にしなくてもいいのかなという個人的結論。もちろん、ネストしまくったら何がなんだかわからないCSSになってしまうので、可読性のために、2,3階層程度でとどめておくほうが良いでしょう。
関連すると思われるエントリ
Tags: sass