Tags: Posted in Web 12 Comments

Stop Import実は以前に別の場所でも書いたのですが、今回Google Page Speedの方でも少しだけ触れられていたので、改めてまとめ。

自分でも経験があることなのですが、開発をやっているとどうしても、構造をモジュール化して複数のファイルに分割して管理したくなります。
StyleSheetにおいても同様で、プレゼンテーション層のコンポーネントにあわせてCSSを用意し、ページ構成にあわせて取り込むようなことをやりたくなるでしょう。

しかしその際、@import構文を使うのはパフォーマンスと挙動の両方に有害である可能性が高いと、「」の著者としても知られるSteve Souders氏が警鐘を鳴らしています。

使うべきでないポイント

@importは、大きく分けて2つの観点で「使うべきでない」とされています。

ひとつは、パフォーマンスの問題。StyleSheetはほぼ全ての主要ブラウザでパラレルロードがサポートされています。これにより、例えば取得に1秒かかるファイルを3つ使うにも、3ファイルを平行して取得できるのでトータル1秒で済みます。
しかし、@importを使うことで、パラレルにダウンロードが出来なくなるケースがあります。その結果、3つのファイルは順に取得され、計3秒かかることになってしまいます。

次に、挙動の問題。こちらはある意味、パフォーマンスよりも深刻です。
ある条件下で@importを使うと、CSSの読み込み順序が変わってしまうことがあります。スタイルシートは読み込まれる順番によって適用スタイルの優先度が変わるため、結果として「ある特定のブラウザで、挙動が変わることがある」という非常に再現性の悪い不具合を内包させてしまうことになってしまいます。

検証1: @import x 2

まず、a.cssとb.cssという2つの外部ファイルを、HTML内で直接、共に@importで取り込む場合の検証をしてみましょう。


この方法であれば、2つのCSSは並行してダウンロードされ、パフォーマンスの問題は発生しません。
# 後述するように、JavaScriptとあわせた場合にエラーの原因となる可能性はありますが。
figure1

検証2: linkと@import

次に、HTMLでa.cssをlinkで、b.cssをインラインstyle要素の@importで呼び出すようにしてみます。



この場合、Internet Explorerの6~8では、次のようにシーケンシャルにダウンロードされるようになってしまいます。
figure2
結果、パフォーマンスの劣化を招きます。

検証3: link中で@import

a.cssをlinkで呼び出し、その中でb.cssを@importで呼んでいた場合はどうでしょうか。

[HTML]


[a.css]

@import url('b.css');

この場合、ブラウザはまずa.cssを読み込み、次にようやくb.cssを取り込むことを通知されます。
結果、先ほどの例のようにIEだけでなく、全てのブラウザでシーケンシャルロードになってしまいます。
figure3

検証4: linkブロック中で@import

では、少し変えて、今度は非常に軽量なc.cssを用意してみます。そしてc.cssが@importでb.cssを読み込みます。a.cssとc.cssをlinkで読み込んでみると、どうなるでしょうか。
[HTML]



[c.css]

@import url('b.css');

実行前に少し考えてみましょう。まず、a.cssとc.cssは並行して読み込まれるはずです。そして非常に小さなc.cssを読み込んだところで、b.cssの読み込みが始まります。トータルでかかる時間は、c.css+b.cssになると予想されます。

結果は、次のようなものでした。2行目から順にa, c, bの読み込みを表します。
figure5
予測した通りの結果です。

ところが、同じコードをIEで実行すると、次のようになってしまいます。
figure4
a.cssとc.cssは平行してダウンロードされていますが、a.cssのダウンロードが終わるまでb.cssの取得が開始されていません。
どうやらIEでは、パラレルダウンロードされるファイルの最も遅いものに引き摺られてしまうようです。

検証5: 大量の@importとscript

今度は、検証1で少し触れた@importとscriptの組み合わせを試してみます。



IEでの実行結果を見てください。
figure6
上から2行目の、最も長いのがone.jsのダウンロードです。
この例のようにスクリプトタグを一番最後に書いても、IEでは真っ先にダウンロードが始まってしまいます。
このため、このスクリプトがスタイルが当たっていることを前提としている場合(cssによって指定される位置や色、形状などを元にしたエフェクトなど)、予期しない動作を招いてしまう可能性があります。

検証6: link x 2

linkだけを並べたケースは、最も問題が起きにくい優れた記述です。



検証5で既に部分的に見ていることですが、IEであっても期待通りに平行してダウンロードが行われます。
figure7

検証7: linkと@imporブロック

では、linkを並べる形をとれば、その中で@importをネストしても大丈夫なのでしょうか?
a.cssとb.cssを並べて読み込み、a.cssからは多くの他のファイルを@importで読み込むようにしてみます。



[b.css]

@import url('c.css');
@import url('d.css');
@import url('e.css');
@import url('f.css');

figure8
期待通りにa.cssの読み込みが終わったところで、他のファイルのダウンロードが始まっています。

検証8: 大量のlinkとscript

最後に、検証5で問題だったスクリプトとの実行順序を確認します。






IEで検証しても、期待通りの動作をします。
figure9

まとめ
  • スタイルシートから他のスタイルシートを読み込むことは、どんな方法であれ2つのCSSのロードをシーケンシャルに行わせることになります。
  • インラインで@importを使うことは、IEではパフォーマンスの劣化と異常動作を招くことになります。

以上のことから、可能な限り@importは用いず、linkを使ってパラレルに読み込むことが最も推奨されます。
既に稼動しているシステムで使ってしまっている場合、急に変更することは難しいと思いますが、せめてHTMLからの呼び出しは全てlinkに統一しておきましょう。

このエントリーをはてなブックマークに追加
Bookmark this on Yahoo Bookmark
Bookmark this on Livedoor Clip
Share on FriendFeed
Share on StumbleUpon
Newsing it!

Related posts:

  1. [Web] Google Page Speedでサイトを高速化(3)
  2. [Design] Responsive Layoutを学ぶ(1)

2009 年 6 月 7 日