CSSをやってはまる典型例は、「CSSせっかく使ってみたのに、横幅がIE6とMozilla Firefoxであわなくてレイアウトがうまくできないんだけど」ということではないか。言い古されているが、ADP流にまとめてみる。
原因は、Internet Explorerのwidth/height(ボックス)解釈に関するバグである。このことを知らない人は、ふつうIE6で見た目を調整してから他のブラウザ(FirefoxやOpera)を見るので、「なんだよずれてるじゃないかー」と怒り出す。よくある話。
ADPでの結論を先に書く。widthとpadding/borderを一緒に指定しない、特に、ピクセル単位で合わせるところではborderを使わない。これに尽きる。
IE6では、IE5.5までに存在したいくつかの致命的な解釈バグを直した「標準準拠モード」と、間違った解釈のままつっぱしる「後方互換モード」を、ページ制作者が選択することができる。実際には、HTMLのDOCTYPE宣言の有無や内容によってブラウザがどちらのモードで解釈するかを決定する。この「DOCTYPEスイッチ」は、OperaやFirefoxにも存在する。どういうDOCTYPEのときにどっちになるか、を覚えるのは大変である。
一番の問題は、IE6はHTMLのいちばんあたまにDOCTYPE宣言を書かないと必ず後方互換モードとして解釈してしまうことである。よくあるケースは、XHTMLで書く場合。通常、XHTMLではDOCTYPE宣言の前にXML宣言を書くため、IE6では有無を言わせず後方互換モードになってしまう。ページ制作者が標準にあわせて書いても、IE6が後方互換で解釈してしまうと思ったとおりに表示されないし、IE6の後方互換の見た目に合わせて書けば、標準準拠で解釈するFirefoxやOperaで思ったとおりに表示されない。はまる。
これのひとつの回避方法は、XML宣言を書かないことである。こうすれば、1行目がDOCTYPE宣言になり、IE6も標準準拠モードで解釈してくれる。Movable Typeのデフォルトテンプレートをはじめ、この回避方法が一般的だろう。
ただし、ADPでお奨めするやり方はちと違う。制作者が標準に従ってXHTMLを書いて、XML宣言もちゃんと書く。これだと、IE6は後方互換モードで解釈して、FirefoxやOperaは標準準拠モードで解釈するわけだが、ADPのやり方ならばまったく同じ表示になる。つまり、IE6で標準準拠モードで解釈させるのをすっぱり諦めて、後方互換でも標準準拠でも同じように表示させるように工夫するわけだ。
このメリットは、なにより、標準準拠で書けること、後方互換モードしかないIE5.5でも(たぶん)無事に表示されること、ブラウザがどのモードで解釈するかをいっさい考えずにすむことである。
ここでは、widthのみについて書く。その他、標準準拠と後方互換のおおまかな話は、文書型宣言とブラウザでの表示(訪問者に優しいWebサイト作り)がわかりやすい。
以下解説。
まず、width解釈に関する説明を
.box {
width: 240px;
padding: 30px;
border: 10px solid black;
}
の例でやってみる。
正しいCSS解釈におけるwidthは、図1のようにcontent(中身)の幅であり、paddingやborderはその外側に置かれる。上記の例の場合、borderまでを含めたボックス全体の幅は320ピクセルになる。
間違ったCSS解釈におけるwidthは、図2のようにborderまでを含んだボックスの横幅である。後方互換モードでは、こちらに従ってwidthを解釈する。
これを知らずにIE6(の後方互換モード)で見た目を調整すると、他のブラウザではボックスが大きくなってしまい、はみでたり、floatが崩壊したりする。
では、図1を、標準準拠な書き方で書いて、後方互換モードでもそのまま表示されるようにするにはどうするか。
解法。まず、大きなブロック要素を用意し、図3のようにwidth: 320pxを指定し、paddingは指定しない(=0にする)。
.boxA {
width: 320px;
}
その中のブロック要素で、図4のようにpadding: 40pxを指定し、widthは指定しない(=autoにする)。fontなどの書式は、ここに指定する。なお、paddingの代わりにmarginにする場合は、ADP: マージンの相殺と背景の話も気をつけなければならないので、paddingにしておいたほうが安全だ。
.boxB {
padding: 40px;
}
こうすれば、contentの幅はどちらのモードでも結果的に240ピクセルになる。大事なことはwidthとpadding/borderを一緒に指定しないことである。
えー、これじゃあ枠線がなくなっちゃうじゃん、と思うかもしれないが、必要ならばどちらかのボックスで背景画像を使ってborderを表現する。たとえば、左右は幅固定がいいけれど、上下は可変、だったら、上下にはborderを使ってもいいが、左右のborderは背景画像で代用する。
中のボックスにならborderをつけられるんじゃないか、と思っても、中のボックスにborderと背景画像をつけようとすると、ADP: ピクセル単位で合わせるところではborderを使わない(IE7でも!)で説明したように、背景画像の開始位置がIE6/7と他のブラウザで変わってしまう、という問題が出てくるので注意が必要だ。というより、ピクセル単位で合わせるべきところではborderを使わない、と覚えてしまったほうが楽だ。
2つブロック要素を用意するとなると、div要素の乱発になるのではないか、と心配する人もいるだろう。しかし、たとえば、ul/ol要素でwidthを指定しli要素でpaddingを指定する、dl要素でwidthを指定しdt/dd要素でpaddingを指定する、body要素はwidth: 100%のままでp要素でmarginを指定する、などとすれば、div要素をいっさい使わなくてもデザインが可能である。実際、現在のADPはそれでやっている。
お試しあれ。
トラックバックURL: http://adp.daa.jp/cgi/mt2/mt-tb.cgi/264
んがー。私はこの方法を無意識のうちにやり出して現在に至るんですが、こうゆう事だったんですねー。(ぉ゛)きちんとした説明にして下さって嬉しいです。やっぱ説明するという事は大切ですなー・・。
アサノさんありがとうございます。書くぞ書くぞ、と思ってから2ヶ月ぐらいかかっちゃいましたが、がんばって書きました。喜んでいただけてうれしいです。
自分用メモ:中のブロックにborderを指定しても別に問題なさそう(Windowsの3ブラウザで確認)。なんか、borderつけると背景画像の始まる位置がブラウザによって微妙に変わる、みたいな記憶が自分の中であったんだけれど、勘違いだったかも。
勘違い勘違い。ピクセル単位で合わせるべきところではborderを使わない、というのは理由が違うんだ。というわけで、結論としてはborderは使わないほうがいい。理由はのちほど。
以前の私のコメントのとおり、中のブロックにborderを指定できるかどうかの話は自分自身かなり混乱していましたが、後のエントリで問題点をちゃんと説明できるようになったので、リンクを追加しました。、
正解は「中のブロックでborderを使えるケースもあるが、うっかりしていると落とし穴に落ちるので、ピクセル単位で合わせるべきところではborderを使わない(使えない、ではなく)、と覚えてしまったほうが安全」です。