XHTML文書を公開する際にユーザエージェントの実装状況から気をつけなければならない事を覚書として纏めておきました。
正直、XHTML文書の配信には充分な注意が必要かと思われます。
従来、XHTMLでマークアップされた文書のMIMEタイプは、application/xhtml+xml が最も適切とされておりました。
しかし、実際に文書を作る現場では殆どそれに従う者はおりませんでした。
殆どのXHTML文書が、在来HTMLの代用として使うべきでないとされたXHTML 1.1文書でさえも、text/html で配信されてきたのです。
これにはマイクロソフト社がインターネットエクスプローラでの application/xhtml+xml への対応を事実上拒否していた事が大きな原因のようです。
しかし、その一方で、この事はXHTMLがXMLの応用言語として受け容れられる事がなかったと言う事も意味しました。
この状況を認識したW3Cは、それまでのウェブ文書をXML化していく方針をあきらめ、より現状に即した方針に転換したのです。
XHTML文書のMIMEタイプにしても、XMLならではの技術が利用出来ない事を承知した上であれば、text/html として配信するのも已むを得ないと言う事に改められました。
以上のような経緯から、現在ではXMLならではの機能を利用したいのでなければ、XHTML 1.0でなくても text/html として配信するのは已むを得ないとするようになりました。
しかし、そうした場合、XMLの文法に沿った文書を従来のウェブブラウザが適切に処理出来るようにするのに幾つか注意しなければならない事が出て来ます。
ガイドラインには、XHTML文書を text/html として配信する場合の注意事項を幾つか挙げておりますが、ここでは、主な項目に関して制作者なりに解釈した補足を加えて解説したいと思います。
尚、以下参照元
としているのは、ガイドラインのCompatibility Guidelines内の項目です。
<img>要素や<link>要素など、仕様で内容を持ち得ない空要素とされている要素について、在来HTMLでは終了タグの記述が出来ません。
XHTML文書を text/html として配信する場合、当然これに合わせる必要があります。(参照元 2)
XMLでは、内容がない場合には、開始タグの末尾を /> と記述する事で終了タグも兼ねている事を明示する事が出来ますので、これを用いるようにします。
例えば、以下のようにします。
<img alt="堀北真希ちゃん♡" src="HORIKITA_Maki.JPG" width="240" height="320" />
尚、この際、/ の直前には必ず半角空白を入れるようにしてください。
そうしないと、その / もトークンの一部と誤認してしまうウェブブラウザがあるからです。
<hr/> と記述すると、ウェブブラウザに依っては<hr/>要素と誤認してしまうものがあると言う事です。逆に内容があるとされている要素でも、内容が偶々存在しない場合もあります。
例えば、表でのコマとなる<td>要素は内容を持つものと定義されておりますが、空のコマの場合には内容が存在しない事となります。
このように、内容が存在するとされた要素で内容を持たない場合には、逆に終了タグを省略してはいけません。(参照元 3)
URL内でクエリの区切りなどに用いられる & については、必ず実体参照を用いて & と記述するようにしてください。(参照元 12)
そうしないと、XMLとして扱ったときに文法エラーとなってしまいます。
また、XMLの仕様で定められている実体参照 ' (' に対する実体参照)は在来HTMLでは定義されておりません。
従って、どうしても文字参照で記述する必要がある場合には数値文字参照 ' と記述する必要があります。(参照元 16)
また、ガイドラインには記述がないようですが、XMLの仕様で定められていない一般の文字参照('を含む)は全て数値文字参照で記述しなければなりません。これは、application/xhtml+xml などXMLとして配信する場合であっても同様です。
何故なら、多くのウェブブラウザはDTDを読まないからです。
XHTMLの場合、XMLで定められていない文字参照は全てDTDで定義されているのですが、DTDを読まないと言う事は、当然それらの定義を認識しないと言う事になります。
その結果、意味不明の実体参照とみなされてエラーとなる場合があります。
このため、DTDを読まない事を前提に、数値文字参照で記述する必要があります。
XML世代より前のウェブブラウザでは、<? で始まるこれらの記述を生テキストと誤認してそのまま表示してしまうものがあります(ネットスケープ 3.xまでなど)。
また、酷いのになると、文書の冒頭に<?xml?>宣言がある場合には、その文書をHTML文書として処理出来ずにソースをそのまま表示してしまうものさえあります(マッキントッシュ版のインターネットエクスプローラ 4.5など)。
以上のような問題があるため、text/html 型で配信するXHTML文書には、これらの記述を用いてはいけません。(参照元 1)
この事から、以下の二つの結論が得られます。
<?xml?>宣言が使えない結果、当該文書は必ずUTF-8かUTF-16のいずれかでエンコードされていなければなりません。(参照元 9)
何故なら、XML文書で<?xml ?>宣言を省略した場合、UTF-8かUTF-16のいずれかでエンコードされているものと見なし、そうでなければバイナリレヴェルで壊れたリソースと見なされてしまうからです。
勿論、HTTPで配信する場合に限り、応答ヘッダの content-type フィールドに charset パラメータを与える事で、エンコーディングを正しく認識させる事は可能です。
しかし、そうした場合であっても、閲覧者が文書をローカル保存した後で正常に開く事が出来なくなる恐れがあります(ローカルファイルの参照にはHTTPは使われないため)。
以上のような理由から、<?xml ?>宣言を省略した場合は必ずUTF-8かUTF-16のいずれかでエンコードされていなければならないと言う事になるのです。
XMLでの処理命令が使えないと言う事は、当然<?xml-stylesheet?>処理命令も使ってはならないと言う事になります。(参照元 14)
そもそも、XHTMLで<link>要素でのスタイルシートのリンクは非推奨だとは誰も言っておりません。
蛇足ですが、XHTML 1.xは一般のXML技術との整合性が取れていない部分が多々あります。
例えば、id属性については、xml:id属性と言う一般のXMLで共通に使える属性があるにも拘らず、これについて全く考慮されておりません。
また、ハイパーリンクについても、本来はスタイルシートは<?xml-stylesheet?>処理命令で、その他一般のリンクはXLinkと呼ばれる専用の言語を組み合わせる事としておりますが、後者についてはやはり全く考慮されておりません。
これらの一般XML技術はいずれもXHTML 1.0より後に勧告されたから仕方がありませんが、それ故、XHTML 2.0では一般のXML技術を取り入れようとしました。ですが、XLinkについては導入をかなり早い段階で見合わせておりました。
XHTML文書中にクライアントサイドスクリプトやスタイルシート言語を記述する場合、注意が必要です。
在来HTMLでは、<script>要素や<style>要素の直下をコメントアウトすれば、対応していないウェブブラウザでも内容が表示されずに済ます事が出来ますが、XMLでは注釈宣言はどんな状況であってもコメントと見なしてしまうので、内容となるスクリプトやスタイルシートが無効になってしまうのです。
また、在来HTMLでは、<script>要素及び<style>要素の内容について、< など通常文字参照で記述しなければならない記号が文字参照になっていなくてもある程度は見逃してくれますが、XMLプロセッサはそのようは記述は容赦なくエラーとして取扱を拒否します。
従って文字参照を用いるべきなのですが、そうすると一部の旧型ウェブブラウザでは逆に文字参照をそのまま字面通りに解釈しようとしてエラーとなってしまいます。
以上の問題点から、XHTMLでは必ず<script>要素及び<style>要素の内容は <![CDATA[ 〜 ]]> セクションとして記述しなければならない事となります。(参照元 4)
しかし、その<![CDATA[ 〜 ]]>セクションのマーク宣言がやはり旧式のウェブブラウザでは認識出来ないので、それをスクリプト言語なりスタイルシート言語なりの文法でコメントアウトする必要があります。
例えば、JAVAスクリプトを<script>要素で埋め込むのであれば、
<script type="text/javascript">// <![CDATA[…//]]> </script>
CSSを<style>要素で記述するのであれば、
<style type="text/css"> /* <![CDATA[ */…/* ]]> */ </style>
とします。
但し、この方法にも問題があります。
それは、良く見るとお分かりいただけると思いますが、<script>要素なり<style>要素なりの開始タグ直後のコメントのトークンが、スクリプト言語なりスタイルシート言語なりに対応していない旧式の環境では、生テキストの一部と見なされて出力されてしまう恐れがあるのです。
更に、<![CDATA[ 〜 ]]>セクションの終わりとなる ]]> と同じトークンを記述する事が出来なくなります。
以上のような問題があるため、スクリプトやスタイルシート言語は極力別ファイルにして、src属性を附与した<script>要素で埋め込む或いは<link>要素で参照するようにする事を強くお奨めします。
尚、<![CDATA[ 〜 ]]> セクションは、在来HTML専用のウェブブラウザでは正常に扱われないため、上記のように<script>要素或いは<style>要素以外では使ってはいけません。(参照元 18)
XMLでは、属性内の半角空白文字(水平タブ及び改行を含む)は複数連続していても一つの半角空白文字に纏めてしまいます。
このため、意味のある空白文字や改行が無効になってしまいます。
また、旧式のウェブブラウザの中には、タグ内に改行が入ると誤作動するものがあるようです。
その点からもタグ内での改行は避け、半角空白文字はあくまでも区切り以上の使い方が出来ないものとするべきです。(参照元 5)
また、ガイドラインでは触れられていないようですが、<pre>要素や<textarea>要素の挙動にも在来HTMLとXMLとの間には大きな違いがあります。
在来HTMLでは、これらの要素の開始タグ直後及び終了タグ直前の改行は無視しますが、XMLではこれらの改行を有効にします。
従って、以下の記述は在来HTMLでは問題ありませんが、XMLとして処理した場合には先頭と末尾に空行が一行ずつ入る事となります。
<pre><code><?xml version="1.0" encoding="shift_jis"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja"><head><meta http-equiv="content-type" contnet="text/html; charset=shift_jis" /><title>文書の題名</title></head><body>(本文)</body></html></code></pre>
このように記述すれば、在来HTMLでもXML扱いのXHTMLでも正しく扱われるようになります。
<pre><code><?xml version="1.0" encoding="shift_jis"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja"><head><meta http-equiv="content-type" contnet="text/html; charset=shift_jis" /><title>文書の題名</title></head><body>(本文)</body></html></code></pre>
また、フォームフィードコード(0x000c)は在来HTMLでは半角空白の一つとされておりますが、XMLではそのように扱われておらず、これが含まれるとXMLプロセッサはエラーと見なすので使ってはいけません。(参照元 15)
在来HTMLで国際化に対応している規格(HTML 4.01やISO_HTML)では、文書の記述言語を明示するlang属性が定義されておりますが、XMLではxml:lang属性で記述言語を明示する事とされております。
このため、XHTML 1.0では在来HTMLとの互換性を守るため lang属性を残しておりますが、XHTML 1.1などでは在来HTMLの代わりに使う事を認めていなかったため、lang属性は廃止されております。
さて、XHTML文書を text/html 型で配信しようとした場合、ウェブブラウザは在来HTMLと見なしますので、当然 xml:lang属性を認識しない場合があります。
このため、lang属性が残されている規格であるなら、xml:lang属性とlang属性の双方を併記する事としております。(参照元 7)
XHTML 1.0以外のXHTML 1.xではlang属性は廃止されているので併記出来ないのは已むを得ないでしょう。
在来HTMLでは、旧くから<a>要素のname属性で文書内のフラグメント(切片)を指定出来るようにしておりました。
その後、HTML 4.01で文書中の特定の一要素への固有名としてid属性が導入され、文書内のフラグメントの指定にも用いられるようになりました。
一方、XMLでは、ID型の識別子とされている属性のみが文書中の特定の一要素への固有名として利用出来るものとされており、XHTMLではHTML 4.01同様id属性がそのように定義されております。
このため、在来HTMLとの互換性を持たせたXHTML 1.0では<a>要素のname属性を引続き認めておりますが、その後策定されたXHTML 1.1などではname属性は廃止され、文書内のフラグメントはid属性で参照する方法のみとなりました。
以上の理由から、仮令name属性が使える言語であっても、name属性を使わずid属性を使う事が求められております。(参照元 8)
但し、ガイドラインでは述べられておりませんが、<a>要素にname属性が用いられている場合には、XHTML 1.0であれば同じ属性値のid属性を併記する事で対応可能です(name属性を削除する必要はありません)。
DOMでの要素ノード名や属性名は、在来HTMLでは大文字に、XMLとしてのXHTMLでは小文字に変換されます(一部で実装がそうなっていないのもあるようですが)。
以上の理由から、在来HTML/XML兼用とした場合には要素名や属性名の大文字小文字を仮定するのは不可能と言う事になるので、大文字小文字を揃えてから評価するようにしましょう。(参照元 11)
例えば、JAVAスクリプトであれば、要素ノードのノード名(つまり要素名)を受け取ったら、toLowerCase() メソッドで小文字に揃えてから評価します。
document.write() メソッドはXMLとして処理されているXHTML文書ではエラーになります。
従って、document.write() メソッドを用いているJAVAスクリプトは修正する必要があります。(参照元 21)
innerHTMLプロパティについては、W3Cが標準と認めていない事からか「使うな」と書かれておりますが(参照元 22)、現状DOMが取扱えるウェブブラウザでinnerHTMLプロパティに対応していないのは既に利用者が皆無に近くなっているオペラ 6.xくらいであり、実際には問題はありません。
HTML 4.01では、<table>要素と<tr>要素の間には必ず<thead>要素, <tfoot>要素, または<tbody>要素が入るものとしております。
一方、XHTML 1.xでは、
或いは複雑な構造を認めていない基本テーブルと言う概念の導入
からか、<table>要素の直下に<tr>要素が在る事も認めております。
従って、HTMLとして配信した場合、<table>要素直下の<tr>要素はDOMとしてどちらの解釈となるか分からなくなります。
このため、<table>要素ノード直下については、
事を考慮してコードを書く必要があります。(参照元 23)
また、この<tbody>要素がない場合の挙動が不明となると言う問題を考慮した場合、マークアップの際に全ての<tr>要素を必ず<thead>要素, <tfoot>要素, または<tbody>要素のいずれかの直下に在るようにするべきであるとも言えます。(参照元 19)
在来HTMLとXMLとして扱われるXHTMLとでは、<noscript>要素の取扱いは大きく異なります。
このため、<noscript>はXHTML文書では使ってはいけません。(参照元 25)
今日ではDOMが使えるので、スクリプトに対応していない環境向けのテキストはわざわざ<noscript>要素として記述しなくてもそれだとスクリプトが分かるようにマークアップしておいて、スクリプトがHTML文書読み込み完了後に該当する要素ノードを除去するようにすれば良いでしょう。
CSSを書く場合には、以下の点に注意してください。(参照元 13)
こうしないと、XHTMLでセレクタが正しく撰ばれなくなります。
例えば、<table>要素の直下に<tr>要素が在る場合であっても、HTML 4.01ではその間に<tbody>要素が在るものとされます。
しかし、XHTMLではそのような扱いにはなりません。
そこで、CSSを記述する場合、どちらの扱いになってもおかしくならないようにセレクタを書く必要があります。
例えば、table>tr と言うセレクタにスタイルを当てるのであれば、併せて table>tbody>tr セレクタも併記するのです。
また、CSSの処理にも注意する必要があります。
少し旧式のHTMLブラウザでは<html>要素へのスタイルが無視されるものがありますが、XMLとして扱う場合はそのような事はあり得ません。
つまり、<html>要素へのスタイル指定が有効な場合と、そうでない場合を考慮する必要があります。(参照元 24)