同一のマークアップ: "@_jscript_version" の説明と新しい HTML5 要素のスタイル設定

本記事は、マイクロソフト本社の IE チームのブログ から記事を抜粋し、翻訳したものです。 

【元記事】Same Markup: Explaining "@_jscript_version" and Styling New HTML5 Elements (2010/6/11 5:41 AM)

※担当者註 : この記事は 2010 年 6 月の記事ですか、資料性が高いうことで翻訳、投稿されました

先月、クロスブラウザー コードを記述するための一般的なガイドラインを掲載しました。この記事では、ブラウザー間の相違に対処するにはブラウザーではなく機能を検出する方が適切であることを強調しました。

機能を検出すれば、ブラウザーが何をサポートするかが自動的にわかるので、ブラウザーがアップデートされてもスムーズに対応できます。ブラウザーを検出すると、あらゆるブラウザーのあらゆるバージョンについてサポート状況をチェックしなければならず、新しいブラウザーがリリースされるたびにコードを修正しなければなりません。

今日は、この問題に関する最近の議論のいくつかを、実際の使用に即したレベルまで掘り下げて説明したいと思います。議論の発端となったのは次のようなコードでした。

 // このようなコードは使用しないでください。
/*@cc_on
   @if( @_jscript_version < 9 )
      // 新しい HTML5 要素にスタイルを適用します。
       ...
   @end
@*/

このコードでは、機能の検出を行い、その機能が存在しない場合はそれに対処しています。

ここで検出しているのは、HTML5 要素にスタイルを適用できるかどうか、具体的には CSS を使って新しい HTML5 要素の表示をカスタマイズできるかどうかということです。このコードは IE9 の互換表示では正しく実行されず、新しい HTML5 要素にスタイルを適用できません。IE9 標準モードでは、問題なく既定ですべての要素にスタイルを適用できます。

このような結果になるのは、条件付きコメント (英語) に似た JScript の条件付きコンパイルを使用していることが第一の原因です。

これらはどちらも一種のブラウザー検出であるため、最新バージョンのブラウザーをターゲットとする場合には特に使用を避けるべきです。

このコードのさらに重大な 2 つ目の問題点は、@_jscript_version ステートメントによってページのドキュメント モードを検出しようとしていることです。

@_jscript_version ステートメントは本来、ブラウザー全体でどのバージョンの JScript が使用されているかを示す機能です。現時点で IE9 では、このステートメントの値はすべてのドキュメント モードで "9" となります。IE8 ではすべてのドキュメント モードで "5.8"、IE7 では "5.7" となるため、ドキュメント モードの判別に使用するにはふさわしくありません。

幸い、ドキュメント モードは直接確実に確かめることができます。IE8 にはドキュメント モードを返す DOM API document.documentMode (英語) が用意されています。最初のコードを次のように変更して、この API の戻り値を使用するようにします。

 // 改善されていますが使用は避けてください。
// 代わりに機能検出を行ってください。
if(document.documentMode < 9) {
   // 新しい HTML5 要素にスタイルを適用します。
   ...
} 

最初のコードよりもましですが、本来の目的を達成するには、ブラウザーを調べるのではなく、HTML5 要素のスタイル設定が可能かどうかを直接検出するのが最善の方法です。

これには、次のような処理を行います。

 // 未知の要素にスタイルを適用する機能を検出します。
var elm = document.createElement("div");
elm.innerHTML = "<foo>test</foo>";
if(elm.childNodes.length !== 1) {
   // 新しい HTML5 要素にスタイルを適用します。
   var elms = [
       "abbr","article","aside","audio","canvas","command",
       "datalist","details","figcaption","figure","footer",
       "header","hgroup","mark","meter","nav","output",
       "progress","section","summary","time","video"
  ];
  for(var i = 0; i < elms.length; i++) {
     document.createElement(elms[i]);
  }
}

このしくみを説明しましょう。

IE9 より古いバージョンの IE では、以下の 2 つの理由から、既定で新しい HTML5 要素にスタイルを適用できません。

第一に、新しい HTML5 要素は未知の要素として扱われるためです。第二に、旧バージョンの IE では未知の要素は解析時にすべて無視されます。つまり、要素の子要素はすべてその要素の親要素の子要素となります。

また、無視された要素は DOM では開始タグと終了タグが別々のエントリとして扱われます。次のサンプル コードとその結果の DOM をご覧ください。

var elm = document.createElement("div");

elm.innerHTML = "<foo>test</foo>";

IE8 での結果の DOM

 - <DIV>
       - test
       - </FOO>

IE9 での結果の DOM

 - <div>
       - <foo>
              - test

ご覧のとおり、ステートメント elm.innerHTML = "<foo>test</foo>" は、未知の要素を無視するブラウザーでは子要素の数が 1 つではなく 2 つになっています。この動作は、機能検出を使って簡単に特定できます (たとえば、elm.childNodes.length !== 1 かどうかをチェックします)。

コードの最後の部分は、未知の要素にスタイルを適用する方法を示していますが、そのような要素を HTML パーサーが検出する前に、スクリプトからdocument.createElement("unknownElementName") を呼び出しているにすぎません。つまり、新しい HTML5 要素にスタイルを適用するには、新たに HTML5 仕様で定義された要素 (英語) それぞれについて document.createElement を呼び出す必要があります。

これは、ブラウザーではなく機能を検出することのメリットを示す良い例と言えます。上記のコードを使えば、どのブラウザーのどのバージョンが新しい HTML5 要素のスタイル適用をサポートしているかに頭を悩まさずに済みます。コードはコード自体の動作をテストし、必要な場合は自動で適切な対処を行います。

Tony Ross

プログラム マネージャー

編集、2:28pm: 3 つ目のコード サンプルを編集。

6 月 11 日 - IE8 での結果の DOM の記述を訂正。