Google推奨のブラウザレンダリングに関する4つのベストプラクティス
Googleが推奨する、ブラウザレンダリングに関する4つのベストプラクティスについて紹介します。
この記事は「Optimize browser rendering」を参考に書き起こしたものです。
元記事は2012年3月28日に更新されたものです。記事には5つの項目がありますが、残りの1つは情報がやや古いようなので割愛しました。
解釈が間違っている部分がありましたらどこかでつぶやいてください。
1.CSSセレクタを効率的に使用する
基本として、CSSのレンダリングは、記述されたセレクタについて、一番右端のセレクタ(キーセレクタ)から開始し、右から左方向に評価します。
で、多くの要素に一致するような非効率的なキーセレクタを避けることで、ページのレンダリングをスピードアップできるようです。
以下の子孫セレクタは非効率な例です。
キーセレクタがユニバーサルセレクタの子孫セレクタ
body * { ... }
.hide-scrollbars * { ... }
キーセレクタが要素セレクタの子孫セレクタ
ul li a { ... }
#footer h3 { ... }
* html #atticPromo ul li a { ... }
非効率な理由は、ブラウザは各要素に対して一致するか、ルート要素に到達するまでDOMツリーをトラバースして評価する必要があるためです。
次の子セレクタも同様の理由で非効率ですが、子孫セレクタよりはましなようです。
キーセレクタがユニバーサルセレクタの子セレクタ
body > * { ... }
.hide-scrollbars > * { ... }
キーセレクタが要素セレクタの子セレクタ
ul > li > a { ... }
#footer > h3 { ... }
また冗長なセレクタも不必要に評価されてしまいます。IDセレクタを利用する場合、要素セレクタを指定する必要はありません。
ul#top_blue_nav { ... }
form#UserLogin { ... }
非リンク要素への擬似セレクタは、IE7/8でレンダリング速度が落ちるようです。
h3:hover { ... }
.foo:hover { ... }
#foo:hover { ... }
div.faa :hover { ... }
1項のまとめです。
- ユニバーサルキーセレクタを避ける
- 子セレクタや子孫セレクタを避ける
- 冗長な修飾は行わない
- クラスセレクタやIDセレクタを使用する
ただし劇的に速度が上がる訳ではないようなので、既存のCSSを修正する場合は費用対効果を考えた方がよさそうです。
その他、本項では「未使用のCSSを削除すればパフォーマンスが改善する」とも書かれています。
2.CSSをHTMLドキュメントの最初の方に配置する
CSSのlink要素はhead要素の中の上部に記述します。
理由は、ブラウザはすべての外部スタイルシートがダウンロードされるまで、Webページをレンダリングブロックするためです。
スタイルシートを最初にダウンロード・解析されることで、ブラウザは徐々にページをレンダリングできます。
なお、CSSのlink要素を並べて記述すればパラレルに取得できます。以下は「Minimize round-trip times」からの引用です。
良い例
<head>
<link rel="stylesheet" type="text/css" href="stylesheet1.css" />
<link rel="stylesheet" type="text/css" href="stylesheet2.css" />
<link rel="stylesheet" type="text/css" href="stylesheet3.css" />
<script type="text/javascript" src="scriptfile1.js" />
<script type="text/javascript" src="scriptfile2.js" />
</head>
レンダリング動作
悪い例
<head>
<link rel="stylesheet" type="text/css" href="stylesheet1.css" />
<script type="text/javascript" src="scriptfile1.js" />
<script type="text/javascript" src="scriptfile2.js" />
<link rel="stylesheet" type="text/css" href="stylesheet2.css" />
<link rel="stylesheet" type="text/css" href="stylesheet3.css" />
</head>
レンダリング動作
また、@importを併用すると、パラレルに取得できるCSSがパラレルに取得できなくなる可能性があるため、「Don't use」と書かれています。
その他、style要素はhead要素に記述しないとレンダリングに影響があるように書かれています(そもそもstyle要素はHTML仕様でhead要素に記述することになっているので、body要素に記述したケースを想定して書かれているのかもしれません)。
2項のまとめです。
- CSSのlink要素はhead要素の最初の方に記述する
- @import文を使用しない
- 複数のCSSのlink要素は並べて記述する
- style要素はhead要素に配置する
3.画像のサイズを指定する
画像を表示するとき、画像のサイズ(幅と高さ)を指定することでレンダリングのパフォーマンスが向上します。
理由は、サイズを指定することで、ブラウザは画像のダウンロード前にレイアウトを算出することができ、ページ表示にかかる時間を短縮できるためです。
指定するのは、img要素のwidth属性とheight属性または、img要素の親ブロックレベル要素のいずれかです。
<img src="..." width="60" height="60" alt="..." />
または
<style>
.image {
width: 60px;
height: 60px;
}
</style>
...
<div class="image"><img src="..." alt="..." /></div>
親ブロックレベル要素に指定する場合、直接の親要素ではない要素に指定しないでください。
また、指定する場合は、画像と一致するサイズを指定します。サイズを拡大・縮小するサイズを指定するとパフォーマンスが劣化します。
3項のまとめです。
- 画像と同じサイズを指定する
- サイズは、img要素または直接の親ブロックレベル要素に指定する
4.キャラクタセット(文字セット)を指定する
当たり前すぎる内容なのであまり言及されている記事がありませんが、HTML文書にmeta要素でキャラクタセット(文字セット)を指定することで、HTMLと実行スクリプトの構文解析をすぐに開始することができます。
<meta charset="UTF-8" />
キャラクタセットの指定が必要な理由は、ブラウザが画面上へレンダリングする際に文字エンコード情報を使用するためです。
ほとんどのブラウザでは、キャラクタセットを検索しながら任意のJavaScriptを実行したり、ページを描画する前に、特定のバイト数をバッファリングします(Internet Explorer6/7/8は例外)。
レンダリングに必要なバイト数をバッファリングしたあと、デフォルトと一致しないキャラクタセットがみつかった場合、ページをレンダリングするために、ブラウザは入力を再解析してページを再描画する必要があり、この部分でパフォーマンスへの影響が発生します。
del要素の取り消し線を文字と異なる色にする方法
HTMLのdel要素で、取り消し線を文字と異なる色にする方法を紹介します。
変更前
削除したコンテンツ
変更後
削除したコンテンツ
1.del要素とは
del要素は、コンテンツの修正箇所を残す場合に利用するもので、指定した範囲が削除されたことを示します。
HTMLマークアップ
<del>削除したコンテンツ</del>
del要素で括ったコンテンツは、次のように取り消し線が表示されます。
削除したコンテンツ
del要素にはcite属性とdatetime属性を指定できます。
- cite属性:削除理由となる情報のURLを設定
- datetime属性:削除した日付と時刻を設定
設定例
<del datetime="2012-06-24T08:15:30-05:00"
cite="http://www.foo.org/mydoc/comments.html">
削除したコンテンツ
</del>
取り消し線はCSSで非表示にすることもできます。
del {
text-decoration: none;
}
また、取り消し線を表示することで文書が読みにくくなる場合は、非表示にするという手もあります。
del {
display: none;
}
2.del要素の取り消し線文字と異なる色にする
本題です。
del要素の取り消し線文字と異なる色にする場合、次のようにdel要素に中にspan要素を記述します。
<del><span>削除したコンテンツ</span></del>
そしてCSSを次のように指定します。
del {
color: #f00;
}
span {
color: #000;
}
これで取り消し線を文字と異なる色にできます。
削除したコンテンツ
del要素に指定したcolorプロパティはdel要素内の文字にも反映されるので、del要素の中のspan要素でさらにcolorプロパティを設定することで、取り消し線の色と文字の色を変更することができます。
「CSSを使えばこういうこともできます」という実験なので、HTMLマークアップ上、意味的に問題があるということであればご利用はお控えください。
data URI Schemeを使ってHTTPリクエストを削減する
data URI Schemeを使ってHTTPリクエストを削減する方法を紹介します。
1.概略
HTMLで画像を表示する場合、
<img src="http://user-domain/foo.jpg" />
という風に、httpを使ってサーバ上の画像ファイルを表示させるのが一般的ですが、httpの代わりにdata URI Schemeを使えば、HTMLファイルに埋め込んだインラインデータで画像を表示することができます。
2.data URI Schemeとは
RFCの規定上、http、https、ftpなどは「URI Scheme(スキーム)」と呼ばれます。
data URI Schemeは、「http」にあたる部分が「data」であるURI Schemeのことを指し、RFC2397で規定されています。
3.data URI Schemeの構文とサンプル
data URI Schemeの構文は次のようになります。
data:[<メディアタイプ>][;base64],<データ>
「<データ>」には、Base64エンコードしたデータを設定します(エンコードツールは後方で紹介)。「メディアタイプ」はMIMEタイプのことです。
下はRFC2397に掲載されているdata URI Scheme(赤色部分)を利用したimg要素のサンプルです(分かりにくいので改行をいれて折り返してます)。
<img src="data:image/gif;base64,R0lGODdhMAAwAPAAAAAAAP///
ywAAAAAMAAwAAAC8IyPqcvt3wCcDkiLc7C0qwyGHhSWpjQu
5yqmCYsapyuvUUlvONmOZtfzgFzByTB10QgxOR0TqBQejhR
NzOfkVJ+5YiUqrXF5Y5lKh/DeuNcP5yLWGsEbtLiOSpa/TP
g7JpJHxyendzWTBfX0cxOnKPjgBzi4diinWGdkF8kjdfnyc
QZXZeYGejmJlZeGl9i2icVqaNVailT6F5iJ90m6mvuTS4OK
05M0vDk0Q4XUtwvKOzrcd3iq9uisF81M1OIcR7lEewwcLp7
tuNNkM3uNna3F2JQFo97Vriy/Xl4/f1cf5VWzXyym7PHhhx
4dbgYKAAA7" alt="Larry" />
上記のimg要素は次のように表示されます(罫線はCSSで指定しています)。
data URI SchemeはCSSでも利用できます。
background-img: url("data:image/gif;base64,R0lG...AA7");
data URI Schemeは画像以外にも、即値として利用したいさまざまなデータを扱うことができます。
下はCSSの例です。
<link rel="stylesheet" type="text/css" href="data:text/css;base64,LyogKioqKiogVGVtcGxhdGUgKioq..." />
下はJavaScriptの例です。
<script src="data:text/javascript;base64,dmFyIHNjT2JqMSA9IG5ldyBzY3Jv..."></script>
メディアタイプにはパラメータを含めることができます。次の例はcharsetパラメータを含んだ例です。
data:text/plain;charset=iso-8859-7,%be%fg%be
4.対応ブラウザ
この技術は古くからあるのですが、IEが対応していなかったという理由でながらく使われていなかったようです。
主要ブラウザの対応状況は次のとおりです。
- Firefox2以降
- Google Chrome
- IE8以降
- Opera 7.2以降
- Safari
最近、data URI Schemeをふんだんに使っている普通のウェブサイトをみつけたのですが、見失ってしまいました。運よくみつけたらここに掲載しておきます。 →ありました。
5.注意事項
RFC2397ではdata URI Schemeを「短い値に適用することが有益である」としています。
言い換えると、表示データをインラインで埋め込むため、ファイルサイズが大きくなるとファイルロードに時間がかかってしまい、本末転倒になってしまいます。
背景画像はCSS Spriteを利用してHTTPリクエストを削減する手段もあるので、要は「バランスを考えて利用しましょう」ということです。
なお、RFC2397では、RFC1866で規定するLITLEN(表記の長さ)を1024バイト、TAGLEN(開始タグの長さ)が2100バイトとなっており、指定可能な長さに制限があるようです。
またネットで調べた感じではブラウザによってもファイルサイズに制限があるようです。
6.Base64エンコードするツール
データをBase64にするツールは探せばいろいろあるようです。
ここでは「Binary File to Base64 Encoder / Translator」を紹介しておきます。
Binary File to Base64 Encoder / Translator
Base64エンコードしたいデータのURLを入力して「送信」をクリックすれば、データのMIMEタイプに応じたdata URI Schemeを生成してくれます。
img要素でCSS Spriteする方法
「CSS Sprite」は背景画像などの複数の画像ファイルをひとつの画像にまとめて、画像の中から表示させたい部分の座標をbackground-positionプロパティで指定するという手法です。これにより画像ファイルのHTTPリクエスト数を減らすことができます。
この手法は背景画像での利用が一般的なのですが、img要素でも利用することができるようなので、本エントリーで紹介します。
本エントリーでは、次のソーシャルブックマークボタン用の4つの画像を1つにまとめて、CSS Spriteを行ってみます。
背景画像の場合はbackground-positionプロパティでさくっと表示できるのですが、img要素として表示させるのにかなり苦労しました。ということで、コピペで使えそうなサンプルも用意しました。
「そういう場合、背景画像に変更するのが本来では?」というツッコミはなしでお願いします(笑)。
1.スプライト画像の作成
まず、スプライト画像(ばらばらの画像をひとつの画像にマージしたもの)にしたい複数の画像を、zipツールなどで圧縮しておきます。
ここでは次の4つの画像を圧縮して「sprite.zip」を作っておきます。
スプライト画像の作成には、定番の「CSS Sprite Generator」を利用します。言語が選択できるので、「日本語」を選択しておくといいいでしょう。
さきほど圧縮した「sprite.zip」を指定します。
各種設定も備忘録的に残しておきます。「重複する画像」「元画像をリサイズ」はデフォルトのままにします。
「スプライト画像設定」では、オフセットや連結方向、保存フォーマットなどを設定します。ここではスクリーンショットの設定にしました。背景画像で「repeat-x」の指定をする場合は縦方向に、「repeat-y」の指定をする場合は横方向に連結してください。
「CSS設定」もデフォルトのままとします。
「スプライト画像とCSSを作成」をクリック。
表示された画面で、CSSルールとスプライト画像のダウンロードが行えます。
ダウンロードした画像ファイルは「sprite.gif」など、適当にリネームしてください。
また、表示されたCSSルールは背景画像用です。今回は背景画像に用いるのではありませんが、利用したい値が含まれているので、どこかにメモしておきましょう。
下は完成したスプライト画像です(便宜上、枠線とパディングはCSSでつけています)。
2.HTMLとCSSの設定(画像リンクの場合)
リンクつき画像のHTMLは次のようになります。
<ul id="sbm_icon">
<li>
<a href="http://.../">
<img src="sprite.gif" width="16" height="73" class="sprite-hatena" />
</a>
</li>
<li>
<a href="http://.../">
<img src="sprite.gif" width="16" height="73" class="sprite-delicious" />
</a>
</li>
<li>
<a href="http://.../">
<img src="sprite.gif" width="16" height="73" class="sprite-livedoor" />
</a>
</li>
<li>
<a href="http://.../">
<img src="sprite.gif" width="16" height="73" class="sprite-yahoo" />
</a>
</li>
</ul>
マークアップのポイントは以下のとおりです。
- a要素・img要素はブロックレベル要素内に記述
- img要素のsrc属性にスプライト画像を指定
- img要素に表示位置調整用のclass属性を指定
- img要素にwidth属性・height属性を記述する場合は、スプライト画像のサイズを記述(表示したい画像サイズを記述すると、縮小された画像が表示されてしまいます)
CSSは次のとおりです。
#sbm_icon li {
display: inline-block;
}
#sbm_icon a {
width: 16px;
height: 16px;
float: left;
overflow: hidden;
}
#sbm_icon a img {
border: none;
}
.sprite-hatena {
margin-top: 0; /* 不要 */
}
.sprite-delicious {
margin-top: -19px;
}
.sprite-livedoor {
margin-top: -38px;
}
.sprite-yahoo {
margin-top: -57px;
}
a要素にwidthプロパティとheightプロパティで表示サイズを指定し、「overflow: hidden」で画像の表示範囲を制限しています。ここではすべて同じ値なので、ひとつのセレクタに丸めてますが、サイズが異なる場合は「sprite-xxx」のclass属性をa要素に格上げして、個別に指定してください。
また、classセレクタのmargin-topプロパティの値はCSS Sprite Generatorで出力したCSSのbackground-positionプロパティをそのまま使います。
スプライト画像の一番上の画像表示にmargin-topプロパティは不要ですが、一応書いておきました。
動作サンプルも用意しています。
3.HTMLとCSSの設定(画像のみ)
画像のみの場合のHTMLは次のようになります。
<ul id="sbm_icon">
<li>
<img src="sprite.gif" width="16" height="73" class="sprite-hatena" />
</li>
<li>
<img src="sprite.gif" width="16" height="73" class="sprite-delicious" />
</li>
<li>
<img src="sprite.gif" width="16" height="73" class="sprite-livedoor" />
</li>
<li>
<img src="sprite.gif" width="16" height="73" class="sprite-yahoo" />
</li>
</ul>
CSSは次のとおりです。2項でaセレクタに指定していたプロパティをliセレクタに移動しています。
#sbm_icon li {
display: inline-block;
overflow: hidden;
width: 16px;
height: 16px;
}
.sprite-hatena {
margin-top: 0; /* 不要 */
}
.sprite-delicious {
margin-top: -19px;
}
.sprite-livedoor {
margin-top: -38px;
}
.sprite-yahoo {
margin-top: -57px;
}
こちらも動作サンプルを用意しています。
4.IEの対処
CSS Spriteの話ではありませんが、上記のサンプルでは「display: inline-block;」の指定を行っていて、過去バージョンのIEでは正常に動作しません。
その場合、次のような条件付きコメントを設定すると良いでしょう(間違っていたらご指摘ください)。
<!--[if lte IE 7]>
<style>
#sbm_icon li {
display: inline;
zoom: 1;
</style>
<![endif]-->