exB - extreme B-AREA -

無敵の中年男性!的確な中年男性!難攻不落の中年男性!

ウェブ制作 - XHTML Markup Tips

流行りだからってDOCTYPE宣言にXHTML使うのはやめなYO、って話とか、荒捜しの好きなヒマ人に笑われないソースの書き方みたいなもの。

初稿:2004年くらい

XHTML2がどこかに行ってしまったのでこのドキュメントを更新する予定はありません。内容はOut of dateとお考えください。

きほん

要素=エレメント(Element)、属性=アトリビュート(attribute)、値=ヴァリュー(value)。タグは<と>で囲われた、要素を記述するための符号。従って「タグを書く」という表現は誤りではないが、「タグ解説」や「タグリファレンス」という表現は適切でない場合が多い。一般にタグの厳密な定義を理解している必要などさらさらないのだが、偉そうな解説サイトでもタグとエレメントをごっちゃにしてるような記述があれば、そのサイトの内容は信頼できないという判断材料になると思われる。

DTD

SGMLにおける仕様書のこと。文書型定義、というのが日本語になるらしいがかえってわかりにくい気がするのでDocument Type Definitionのままでいいだろう。HTMLもSGMLのひとつ。HTMLを書くのに必要最低限のDTDの読み方さえ知ってればとりあえずおkジャマイカ。

主要なDTD

ISO-HTMLのDTDをhttp Reachableなところに設置してないのは厨房除けのためなんだろか。

Block要素とInline要素

ぶっちゃけBODY要素の直下に記述できるのがBlock要素であり、Inline要素はBlock要素を子要素にできない、と考えると理解しやすいかもしれない。しかしBlock要素を子要素にできないのがInline要素と誤解しそうだ(ADDRESS、Hn、P etc.)。それにBlock要素の子要素に何が使えるかも要素ごとに異なることに注意しないといけないね!

XML宣言について

文書タイプを示すDOCTYPE宣言がXHTMLであるなら先頭行にXML宣言が必要になる。当たり前でしょ、XMLなんだから。しかし先頭行がDOCTYPE宣言でない場合強制的に互換モードとなるというIE6におけるDOCTYPEスイッチのバグを回避するためにXML宣言を省略していると思われる例を数多く見かける。これは特にブログサービスで顕著。

但し、一定の条件を満たせばXML宣言の省略は認められている。省略が必ずしもイレギュラーというわけではないことに注意。

PHPやSSIが利用できる環境であればブラウザ変数で振り分けることも可能だが(refer)、そうでない場合、XHTML1.0はHTML4.0をXMLに適合させたもので基本的に使用可能な要素や属性に変わりはないのだから、本来例外であるはずのIE6に合わせる形でXML宣言を省略するくらいならHTML4.01を使うべきではないかな。それでもXHTMLでDOCTYPE宣言したい理由がオレにはわからんが、例外に最適化すると後で苦労するのは自分だYO

そんなわけで、IE6のシェアが1%切るまでは、ソース的にあまり美しくないのだけれども、XML宣言の有無の振り分けを有効にしておく(2010年夏の段階で5%弱である)。

XHTMLでのおやくそく

これくらいみんな知ってるよねっ!

  • 先頭でXML宣言はしてるよな!
  • 要素名や属性名はすべて小文字。いい加減解説サイトも凡例で要素や属性名を小文字で書こうよ、文中に出てくるのは構わないからさ。
  • 属性値はたとえNMTOKEN型だろうが必ずダブルクォーテーションで囲まないといけないYO
  • さらに列挙型の属性においては値も大文字小文字が区別され、この場合は小文字で記述。例えばdir属性やinput要素のtype属性、form要素のmethod属性など。
  • 終了タグの省略はできなくなりました。空要素タグについてはブラウザが混乱しないよう省略形(... />)を使いましょう、というのが勧告での言い分です。
  • ID属性とCLASS属性では値として使用可能な文字が若干異なる(ID値はフラグメント識別子としても機能するためXMLとCSS両方の制約を受けることになる)。
  • 面倒を避けるならIDもCLASSも半角英数、アンダースコア、ハイフンに留めるのが無難。また先頭文字はアルファベットで数字や記号で始めない。

ほかにもいろいろあるが、これくらいは序の口ということで。

iframe

iframeはPHPやSSIが使えない環境で外部ファイルを読み込むのに一般的に用いられるが、XHTML1.0 Strictでは使用不可、Transitionalでも非推奨となっている。このため外部ファイルの読み込みにはobject要素を用いるのがよいらしい。確かにそのほうがソースの後方互換には優れるのでベターなやり方に思える(ベストはiframe使わないといけないようなコンテンツの作り方をやめることだって)。

<object type="text/html" data="./navi.html">
<p>alternate text</p>
</object>

しかしこのままだとIEでは表示されない。どうもobject要素に対してスタイルでサイズを指定してあげないといけないっぽい。

<object type="text/html" data="./navi.html"
 style="width:100%;height:120px;overflow:auto;margin:0;padding:0;">
<p>alternate text</p>
</object>

もちろん実際にはインラインじゃなく外部ファイルに書くべきよ。

iframe相当の動作なら当然なのだけど、PHPやSSIのincludeと違って読み込まれた外部ファイルには読み込み元のスタイルは適用されない。またimgにおけるalt属性と同じく、代替テキストは等価の内容かアクセス手段などを記述すること。「IE6.0以上でご覧下さい」とか書かないように。まあ、iframeと全く同じ振る舞いをしてくれることを保障するものでもないので完全にobject要素で置き換えるにはいろいろブラウザハックなど工夫しないといけない。どうしてもXHTMLでiframeを使いたい場合はStrictなDOCTYPE宣言をしないように。

PHPやSSIが使えない場合を除いて、iframeを使わないといけないようなコンテンツってのが何だか、オレは本当にわからない。

包含規則

入れ子にできない要素の関係について。みんな理屈で考えたら当然なんだけど。

a
他の a エレメントを包含できない。
pre
img, object, big, small, sub, sup エレメントを包含できない。
button
input, select, textarea, label, button, form, fieldset, or iframe エレメントを包含できない。
label
他の label エレメントを包含できない。
form
他の form エレメントを包含できない。

正直、XHTMLに限らずこれに引っ掛かるようなマークアップはどうなのかと。

実体参照とか

XMLでは<!--と-->でコメントアウトされた部分もPCDATAとして扱われるため、&や<、>、"などを直接書いてはいけない。特に&に対する制約がより厳密となっているため、href属性やsrc属性、cite属性などにおけるURIも

http://b-area.org/hoge.cgi?id=username&pass=password

ではなく

http://b-area.org/hoge.cgi?id=username&amp;pass=password

と書かないといけない。HTML-lintで高得点を目指すStrictでValidなソースを目指すなら要注意。

フラグメント識別子

ページ内アンカーのためのid属性及びname属性の値を指す。フラグメントは断片のこと。ウェブの最小構成単位であるはずのファイル≒ページをさらに細かく区切ることが、W3Cの中の人にはあたかも断片のように感じられるのだろう。日本語の正式名称は素片識別子らしいが、部分識別子のほうがわかりやすいと思う。フラグメント識別子としてのname属性(*)はXHTMLでは廃止の方向だから、上位互換以外に使うのはナンセンスである。レガシーなコンテンツからの過渡期間に限定すべき。

そのような前方互換のために用いる場合、タグ内でid属性とname属性に同一の値を併記することになるのだが、XMLにおけるID型の制約上、name属性の値もこれに準ずる必要がある。要するに数字だけのid、アルファベットで始まらないidなどはNGなのよ。name属性にこれらを用いていたなら、単純にname属性の値をコピーしてid属性を追記するような置き換えはできないので、結局Strictに作り直したほうが後々楽ではないだろうか。

* もちろんフォームコントロールにおけるname属性は別の話である。

本編(何)でも触れた「本来のclass属性/id属性」について

うちのソースの見直しも必須。すべてはコンテンツの後方互換性維持(後で自分が楽する)のため。

クラス属性は多くのサイトでは「スタイルシート(CSSなど)のスタイルを適用する対象の目印」といった解説がなされている。確かにスタイルシートoffの状態ではclass属性はほとんど意味をなさないわけだから、間違いではないのだろう。しかしどうも違和感がある。

クラスはClassification、つまりそれに続くvalueで“分類”をするわけだ。じゃあどんな基準でもって分類するんだって話。例えばclass="red"(.red {color:red})あるいはclass="float"(.float {float:left})のように物理的な内容を値に指定するのはfont要素やインラインスタイルを使うのと何も変わらない。少なくとも後者はclass="image_inline"(.image_inline {float:left})とするのがいい。つまり、結局のところ、見かけのスタイルではなくアウトライン、構造化を意識して値を決定すべきなのだ。

そしてid属性である。id属性は一意な要素に対する名前付けではなく、要素を一意に定義するためにある。さらにRFC3986ではフラグメント識別子もURLに含まれるように定義が変更されている。これは実に重要なポイントだ。スタイルシートのidセレクタとして安直にid属性のネーミングを決定すると、いつかフラグメント識別子としてのネーミング、すなわちURIの永続性で後悔することになる。

そうはいっても、“たかが”HTML程度でここまで徹底的に名前空間を意識しなければいけないというのはどこか納得し難いところはある。オレは別に構わんのだが。

話をまとめるが、ウェブづくりの理想としては、考えられるclass属性とid属性の値というか名前をコーディング前にリストアップするのが望ましい。class名については文書構造と出現要素の意味に基づいて、id名についてはフラグメント識別子の必要性に基づいて、将来に渡って変更の無いよう決定する。そこまでやってほんとのサイト設計ジャマイカ。全員にそれを望むつもりはない。後で困らない人、手間を増やしたくない人、いつまでもコンテンツを残しておきたい人は迷わず実践してほしい。まあ、ネーミングセンスの問題といってしまえばそれまでなのだが。

付け加えるなら、基礎設計の段階ではスタイルシートというかスタイルのことやSEOについてはあんまり考えないほうがいいと思うぞ。

おまけ

HTML/XHTMLにおけるオレ自身注意しないといけないこととか。

ulとolの使い分けに関して

リスト要素のうちolはOrder Listであるように順序付きのリストを生成するわけだが、アルバムの収録曲などのように明示的に順序通りに並べることが必要である場合に使うべきで、単に紹介する順番といった番号付けのためにolでマークアップするのはいかがなものかと思う。任意の番号付けをしたいならulでマークアップして直接1なりAなり記述すれば済む話。

新着情報等における日付はdtか、Hnか

新着/更新情報などでよくある「日付」+「更新内容」を列記していく際、「日付」をdt、「更新内容」をddとするのは妥当なマークアップなのだろうか。多くの場合、文書内での新着や更新情報における「日付」の位置づけは、dt本来の使い方である定義語ではなく見出しの一種と考えるのが自然だろう。であるならdtではなく出現する階層に応じたHn要素がふさわしいということになる。

早い話がdtをdfnに置き換えてもおかしくないかどうか、ということ。

しかし。新着/更新情報といった類のものは主たる文書の内容とは直接関係が薄い。位置づけはRSSに近く、論理構造の外に存在しているといってもよい。また現行仕様におけるHn要素が6階層までという制約がどうしても引っ掛かるのである。これより階層が深くなるような文書はそれほど多くないであろうという仮定なのだろうか?あるいはそんな階層が深くなるようなマークアップは避けるべきという見解がW3Cのエロい人にあるのかもしれないが、そんなことは大きなお世話である。

論理構造や階層に依存しない見出しと内容のマークアップにはHn要素は不向きではないか。この答えが出るまでは、新着/更新情報をdl要素でマークアップしてもよいのではないかと思う。

2008-01-18追記

HTML5ではページと関連性の薄い部分を示すaside要素が新たに追加される予定である。ただHTML5は下位互換を重視しているのはともかく、新要素盛りだくさんで詰め込みすぎな印象を受ける。WAHTWG「ユーザエージェントに適用されるルールと、適合文書を作成する際のウェブ制作者に適用されるルールとを区別をすることが大事です。それらは完全に直角なのです。」という主張そのものは評価できるが、せっかくXHTMLで見えてきた相互運用への道を逆行しているのではないかと思う。

ちなみにXHTML2ではsection要素とh要素が追加され、これにより階層制限は事実上存在しなくなる(現行のHn要素も使用可能)。慣れないうちはレイアウトのためのtable要素同様、ネストのレベルがわからなくなるというジレンマが起きそうだが。

参考:Web標準と(x)HTML 5とXHTML 2.0と - これからのWebはどうなるのだろう?

ここはよい。トゲのある言い方もなければ知ったかぶった書き方もしていない。どこかの誰かさん(誰)とは大違いである。

meta要素のhttp-equiv属性について

equivはequivalent(等価)の略で、HTTPレスポンスヘッダフィールドと等価、それゆえContent-Typeはhttp-equiv属性で指定するわけ。拡大解釈すればHTTPレスポンスヘッダで指定できる項目は何でも値になるわけだが、ブラウザの挙動が保証されるとは限らないことに注意したい。

またスタイルシートやJavaScriptを利用したHTML/XHTML文書では、

  • <meta http-equiv="content-type" content="text/html; charset=EUC-JP" />
  • <meta http-equiv="content-style-type" content="text/css" />
  • <meta http-equiv="content-script-type" content="text/javascript" />

の3つを指定するよう仕様書には書かれているが、text/htmlなどのMIME TYPEのエンコーディングはサーバ側で容易に指定できるから省略することもできる(そっちが本筋)。

そんなわけで、apache_response_headersを利用して、現在表示しているこのページの素のレスポンスヘッダを取得してみた。

まずコード。

<?php
print_r(apache_response_headers());
?> 

んでこれが出力結果。

Array
(
    [X-Powered-By] => PHP/5.2.17
    [Connection] => close
    [Transfer-Encoding] => chunked
    [Content-Type] => text/html; charset=UTF-8
    [Content-Language] => Ja
)
 

雑感

「こうあるべき」と宗教的に押し付けるつもりはぜんぜんないんだけど、長く続けるなら論理構造重視(StrictなDTD準拠、とほぼ同義)で記述するほうが効率がよい、というのが自分の経験則。腐ってもエンジニアである以上、ブラウザのフェイルセーフに救われてることに甘んじるわけにもいかないし。そんなオレからすると、コンテンツの後方互換やメンテナンス性、オーサリング環境やCMSのようなミドルウェアを伴わない記述の容易度(これは、実に、重要なのである)などを考えると現時点ではXHTML1.0 Strictが最適な解ではないかと。論理的に整合性の取れたclass/id属性が用いられていればXSLT経由でメタ情報を抽出なんてこともやりやすいし。GRDDLがまさにそれだ(このへんがオレの課題)。

20世紀から存在するようなページでの用法の誤りを誇らしげに指摘してる連中をたまに見かけるけど、おそらく黎明期のネットをよく知らない21世紀デビューなんだろう。それくらい笑ってスルーしてあげなよ、良くも悪くも彼らが今日のウェブにけっこう貢献したのは事実なんだから。むしろXHTML1.0が勧告されて以降に作られたにも関わらずDTDなんて知ったこっちゃないような解説サイトを弾劾しなよ、こっちは存在自体が罪なんだから。お手本にされるサイトが根本的に誤解したままというのは悲劇でもあり喜劇でもあるような(XMLが整形式って時点で起こるべくしてなのかね)。

訪問者のことを考えるということ

様々な訪問者や環境を考慮することはアクセシビリティと呼ばれている。ブラウザ依存みたいな記述はよろしくない、というわけだ。しかしどの程度アクセシビリティを確保する必要があるかについては、コンテンツの内容によって変わってくる。よく「目の見えない人にも考慮してどうのこうの」というお叱りを見かけるが、カメラマンが自分の作品を公開するのに目の見えない人を、ミュージシャンが自分の楽曲を配信するのに耳の聞こえない人のことを考えないといけないのか?そうじゃない、写真が好きな人、音楽が好きな人に対して最適化すべきだろ?

すべてのページが公共情報を発信してるわけじゃあるまいし、アクセシビリティを押し付けるのではなく、環境依存な作りは訪問者を限定するということ、そしてどんな訪問者に対して情報公開したいのかを意識させることのが大事なんだよ、きっと。

まあ、往々にしてアクセシビリティ以前に構造化とか論理的なマークアップって?な作り手のが多そうではある。おかげでブラウザがフォローしないといけない→複雑化してバグ内包というジレンマに陥るのであろう。どうしても見栄えにこだわるならPDFで作ってみてはどうかしら。みんなの大好きなGooooooogle大先生もちゃんとインデックスにマップしてくれるしね。

で、オレのホンネはどうなのかと

ぶっちゃけ、XHTMLといっても“XMLとして”扱えるページなんて極わずかで、ほとんどはHTML4相当なんだろうね。だから普通にウェブ作るだけなら無理にXHTMLを選ぶ必要はないし、XHTMLを選ぶからにはセマンティック志向・・・データ交換を意識する≒より一層の構造化を心掛けるべきと思うんだよね。

まあ、そのことに気づいているのといないのとではずいぶん違うと思う。それでいいんじゃないの。オレの場合はRSSやらUTF-8やらの対応に迫られてるうちに自然とXHTMLに近づいたって感じかなあ。特にXHTML1.0 Strictはルールが厳密なぶん、曖昧さの残るHTMLやTransitional系よりむしろ扱いやすいと感じたので完全移行した、と。

裏を返せば、たぶんHTMLのほうがHTMLとしてできることの幅は広いと思うよ(意味わかるかな?

W3CがXHTML2放棄しちゃったよ!

XHTML2とHTML5の並立による混乱を避けるためXHTML側が譲歩した、ということなんだと思う。というか、市場のわがままに押し通されたのほうが近いか。あとは先にも触れたように、実際にはHTMLで十分なページばかりでXHTMLのメリットを具体的に実装してるwebがあまりにも少なく、XHTMLをやめたところで影響はさほどないとかね(XHTMLでやりたかったことはXHTMLが消えてもXMLとして実現できるから?)。

せめてHTML5がモジュール化されてれば、俺も移行する気になれるんだけど・・・正直もてあますよ。

脚注

XML宣言の省略
XHTML1.0においてXML宣言を省略できるのは次のいずれかに該当する場合。
  • 文字符号化方式にUTF-8を使う。
  • 文字符号化方式にUTF-16を使う。
  • 上位のプロトコル(この場合HTTPレスポンスヘッダ)で文字符号化方式(Content-Typeフィールドのcharsetパラメータ)を指定する。
B地区exのXHTMLドキュメントはすべてUTF-8でエンコーディングされており、かつApacheでDefaultCharsetにUTF-8を指定しているため省略しても仕様上問題はないものの、念のため宣言をしている。但しIE6では宣言しないよう設定しているためソースを見ても確認できないが。
ID型
文字通り該当ドキュメントでユニークな値、かつ先頭の文字は英字、アンダーバーのいずれかでなければならない。
NMTOKEN型
アルファベット、数字、ハイフン、アンダーバー、コロン、ピリオドのみで構成された文字列。先頭に数字、ピリオド、ハイフンを指定することも可能。HTMLにおけるフラグメント識別子としてのname属性はNMTOKENであるが、互換性のためID型としておくのが望ましい。