HTML の先頭に書く DOCTYPE (文書型宣言) は、ただの決まり文句ではありません。ブラウザーは DOCTYPE を見て、ページをどの「レンダリングモード」(表示の仕方) で扱うかを決めています。古い Internet Explorer (IE) の時代には、DOCTYPE の書き方ひとつで表示が大きく崩れることがあり、IE8 からは X-UA-Compatible という独自の指定も加わって、さらに複雑になりました。ここでは、その仕組みと今の書き方をまとめます。

3 つのレンダリングモード

ブラウザーには、おおまかに次の 3 つの表示の仕方があります。

  • 標準モード (standards mode): CSS の仕様どおりに表示する
  • 互換モード (quirks mode): 仕様が固まる前の、古いブラウザーの表示をまねる
  • ほぼ標準モード (almost standards mode): 標準モードとほとんど同じ。表のセルの中に置いた画像の、上下のすき間の扱いだけが古い表示に合わせてある

HTML の仕様では、それぞれ no-quirks mode、quirks mode、limited-quirks mode と呼ばれています。

互換モードがあるのは、すべてを仕様どおりの表示に切り替えると、それまでに作られたページが崩れてしまうからです。そこでブラウザーは、「DOCTYPE が無い、または古い書き方のページは昔の表示、きちんとした DOCTYPE があるページは仕様どおりの表示」と切り替えることにしました。この仕組みは DOCTYPE スイッチと呼ばれます。

古い IE で起きていたこと

IE の互換モードは、IE5 のころの表示をまねるものでした。いちばん大きな違いは、ボックスの幅の計算です。標準モードでは width は中身の幅で、padding と border はその外側に足されます。IE の互換モードでは、width に padding と border まで含めて計算していました。

.box {
  width: 200px;
  padding: 10px;
  border: 5px solid #333;
}
/* 標準モード: 見た目の幅は 200 + 10 × 2 + 5 × 2 = 230px */
/* IE の互換モード: 見た目の幅は 200px (中身の幅は 170px) */

どちらのモードになるかの条件はわかりにくく、意図せず互換モードになることがよくありました。

  • DOCTYPE を書かない
  • HTML 4.01 Transitional の DOCTYPE で、DTD の URL を省く
  • IE6 で、XHTML のページの先頭に XML 宣言 (<?xml version="1.0" encoding="UTF-8"?>) を書く
  • IE で、DOCTYPE より前にコメントを書く

特に XML 宣言は、XHTML では書くのが正しいとされていたため、正しく書いたつもりで IE6 だけ表示が崩れる、ということが起きていました。

IE8 からの X-UA-Compatible

IE8 では、標準モードの表示が IE7 から大きく変わりました。IE7 に合わせて調整したページが IE8 で崩れないように、IE8 は「ドキュメントモード」という考え方を取り入れ、どの版の表示の仕方を使うかをページの側から指定できるようにしました。それが X-UA-Compatible です。

<!-- IE7 の標準モードと同じ表示にする -->
<meta http-equiv="X-UA-Compatible" content="IE=7">

<!-- その IE で使える、いちばん新しい表示の仕方にする -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">

IE=7 は DOCTYPE に関係なく IE7 の標準モード、IE=EmulateIE7 は DOCTYPE スイッチに従って IE7 の標準モードか互換モード、IE=edge はその IE の最新のモード、という意味です。同じ指定は HTTP のレスポンスヘッダーでも送れました。meta 要素で書くときは、head の中で、title とほかの meta 以外の要素より前に置く必要がありました。

さらに IE8 以降には、利用者がボタンで切り替える「互換表示」もありました。互換表示にすると IE7 に近い表示になるため、同じ IE8 でも人によって見え方が違う、ということが起きました。開発者ツールでモードを切り替えながら表示を確かめるのが、このころの定番の作業でした。

今はどうするか

Internet Explorer はサポートが終わっており、今のブラウザーは X-UA-Compatible を見ません。新しく作るページに書く必要はありません。HTML の仕様でも、書くなら content="IE=edge" だけが認められていて、ブラウザーは無視することになっています。

DOCTYPE は、次のように 1 行目に <!doctype html> と書くだけで十分です。大文字・小文字は区別されません。この DOCTYPE なら、今のブラウザーでも古い IE でも標準モードになります。その前には何も書かないでください。

<!doctype html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>ページの題名</title>
</head>
<body>
  <p>本文</p>
</body>
</html>

互換モードは、今のブラウザーにも古いページのために残っています。互換モードで表示すると、単位を書かない長さ (width: 100) を px として扱う、# の無い色の指定を受け付ける、高さのパーセント指定の計算が違う、といった違いが出ます。DOCTYPE を書き忘れたページで「CSS が思ったとおりに効かない」ときは、まずモードを疑ってみてください。

なお、width に padding と border を含める計算は、今は box-sizing: border-box で、意図して選べます。

モードを確かめる

今のページがどのモードで表示されているかは、開発者ツールのコンソールで document.compatMode を見るとわかります。

// 標準モードとほぼ標準モードでは "CSS1Compat"、互換モードでは "BackCompat"
console.log(document.compatMode);

iframe で読み込んだページは別の文書なので、モードもそれぞれ別に決まります。親ページが標準モードでも、中のページの DOCTYPE が無ければ、そのページだけ互換モードになります。

まとめ

  • ブラウザーは DOCTYPE を見て、標準モード・ほぼ標準モード・互換モードを切り替える
  • 古い IE の互換モードは IE5 のころの表示をまね、ボックスの幅の計算まで変わった
  • IE8 以降は X-UA-Compatible で表示の版を指定できたが、今のブラウザーには不要
  • 今は 1 行目に <!doctype html> を書き、その前には何も書かない
  • モードは document.compatMode で確かめられる

参考