[IE6]ブロック要素を中央寄せにするために、text-alignを使う件
ブロック要素を中央寄せにレイアウトする場合、左右marginをautoに設定するのが正しいCSSの書き方ですが、IE6の過去互換モードではこれが正しく動作しないのは有名です。

そこで、IEのために親ボックスにtext-align:centerを適用し、中央寄せにするというバッドノウハウと呼べなくもないテクニックが当たり前のように使われています。
text-alignプロパティは継承されますから、親ボックスにtext-align:centerを設定した場合、子孫ボックスではtext-align:leftと改めて設定して値を上書きすることがほとんどです。このtext-alignの上書きが面倒なのはもちろんですが、意図しない子孫要素にまで影響が及んでしまうので、できるならこのテクニックは使いたくないなー、というのが私の考えです。そこで、text-align:centerを使わずになんとかしようというアイデアをご紹介します。
親ボックスが div#wrapper で幅400px、中央寄せにしたい子ボックスが div#content で幅300pxという例でコードを考えていきます。次のコードは、text-align:centerを使った一般的なものです。
div#wrapper {
width: 400px;
text-align: center;
}
div#content {
width: 300px;
margin: 0 auto;
text-align: left;
}
これを以下のようにすることで、text-align:centerを使わずに、同じ表現をすることができます。
div#wrapper {
width: 400px;
}
div#content {
width: 300px;
margin: 0 auto 0 50px;
}
実際に中央寄せにした場合に左右に空くmarginを計算し、子ボックスの左marginに設定してやり、右marginはautoにします。これで、text-align:leftのまま、主要なブラウザ全てで中央寄せを実現できます。
このコードをIE6の互換モードで表示したのが、次のスクリーンショットです。(実際は見やすくするためにbackground-colorやpaddingも併用しています)

ただし、弱点もあります。親ボックスが幅固定のレイアウトに限って有効なテクニックなので、リキッドレイアウトやエラスティックレイアウトでは使えないのはもちろん、body要素が直接含むボックスには使えない(body要素はウィンドウサイズによって幅が変わるため)という点です。
幅固定レイアウトでは絶大な(?)威力を発揮します。
ちょっとしたCSSのアイデアなのですが、あまり使ってる人見かけないな?と思ったのでご紹介しようと思いました。
IEのDOMで特徴的だと思ったこと3点
最近、職場で勉強がてらJavaScriptでプログラムを書いています。会社の案件では少しjQueryを触ったりしたのですが、こちらではライブラリは極力使わない方針で。
そんな中、いくつか気づいたことを書き留めておきます。今回はIEの挙動で、特徴的だと思った点を3点。
responseXMLされたテキストノードをappendChildしようとするとエラーになる
Ajax通信したものをresponseXMLで受け取り、そこからテキストノードを抜き出して、createElementしたコンテナ要素にappendChildしようとすると、IEでは何故かエラーになりました。
回避方法:
// hogeが該当のテキストノード
var fuga = document.createTextNode(hoge.nodeValue)
container.appendChild(fuga)
周りくどいですが、テキストノードのnodeValue(テキストそのもの)を取り出して改めてcreateTextNodeします。これだけで解決。
table要素をcreateElementする際、子要素にtbodyを作らないとダメ
FirefoxとかOperaは、こっちがわざわざ作らなくても仮想的にtbodyを作ってDOMツリーを構成してくれます。だけどIEの場合はtbodyもこっちが作らないとダメ。作らなかった場合は不完全な要素ノードとなるため、appendChildとかしても何も表示されません。
そんな情報を検索している時に発見した、珍しいメソッドがtBodies[]。
tBodies[]
table要素ノードのメソッド。tbody要素をノードリストで返す。
tableElement.tBodies[0]みたいにして使います。まぁ、tableElement.getElementsByTagName("tbody")[0]と書いても同じなわけですけど・・・。
要素ノードリストのアイテムにインデックス番号を振る際、 変数に格納した数値を入れるとエラーになることがある
解決方法:
とりあえずitem()メソッドで書けばOK
他のコードでも書いてみましたが、エラーが再現できず・・・どういう条件が重なると引き起こるのかよく分かりません。
hasLayout問題を解決するzoom:1;の落とし穴
IEのヘンテコなCSS解釈の原因と言われるhasLayoutプロパティ。
どうやらこのhasLayoutプロパティの値がfalse(デフォルト値)の場合に、いろいろとまずいことが起こるようです。IEだけfloatした要素周辺のmarginやpaddingがおかしかったり、相対配置/絶対配置した要素がどこかに消えてしまったりする・・・という経験はcssレイアウトの際に誰もがぶつかる問題です。
また、hasLayoutがTrueとFalseの要素が混在している場合には、IE7のズーム機能を利用した際に、隣あった要素が重なってしまったりします。
この辺はコリスさんのIEでのCSSのバグを回避するhasLayoutに分かりやすい説明があります。
このhasLayoutの問題を解決するためにzoomプロパティが利用されることがあります。(zoomプロパティはIEの独自拡張であるため、これを使うこと自体どうか、という意見もありますがここでは触れません)
具体的には次のように、
* {
margin: 0;
padding: 0;
zoom: 1;
}
ユニバーサルセレクタに指定したり、
body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,textarea,p,blockquote,th,td {
margin:0;
padding: 0;
zoom:1;
}
などとして、ブラウザスタイルをリセットする際に同時に指定するのが一般的なようです。しかし、zoom:1;をli要素に指定してしまうとマーカーの表示がおかしくなってしまう問題があります。
これに対しては
li {zoom: normal;}
としてzoomプロパティの値をデフォルトに戻すことで対処をできるようです。
ここまでは前提で、本題はここからです。
そんなわけで実際に業務で、スタイルリセットにzoom:1;を導入してみたのですが、さらなる落とし穴があることに気づいてしまいました。
STOPN' LISTENさんのclearfixに関するの記事をご覧いただくとお分かりになると思うのですが・・・そうです。zoom:1;はclearfixにも使われるのです。
つまり、何でもかんでもzoom:1;にしてしまうと、floatが意図しないところでclearされてしまう恐れがあります。具体的には次の図のような例で、問題が起こります。

XHTMLのコード
<p><img src="/img/2007/09/16_example_img.gif" alt="画像" width="120" height="90" class="photo" /> 段落1テキスト段落1テキスト段落1テキスト段落1テキスト段落1テキスト段落1テキスト段落1テキスト段落1テキスト段落1テキスト</p>
<p>段落2テキスト段落2テキスト段落2テキスト段落2テキスト段落2テキスト段落2テキスト段落2テキスト段落2テキスト段落2テキスト</p>
最初の段落に含まれている画像に対してfloat:leftを指定し、本文を右側に回りこませているという、何の変哲もないレイアウトです。回り込んでいる本文が途中で段落分けされていることがポイントです。
ここで* {zoom: 1;}を指定すると、以下の図のようになります。

図と同じサンプルページも用意しました(IE6/7で見てくださいね)。
段落分けされた途端、clearされてしまっているのがお分かりになるかと思います。これはp要素に対してzoom:1;が効いているからです。これを回避するにはp {zoom:normal;}のようにしてデフォルトの値を上書きするしかありません。個人的にこれは全くナンセンスだと思うのですが・・・。
スタイルリセットの段階でzoom:1;を指定してしまうと、そのサイトのコンテンツは全てがこの挙動になってしまいます。
サイトをリニューアルする際にzoom:1;を新たに導入する、という場合には注意が必要です。今まで正常に表示されていたコンテンツが、先述の例のようにレイアウトが変わってしまうことがあるからです。
サイトを一人で制作し運営していく分には、この挙動を理解した上で制作をすることになるので、全く問題はないと思います。しかし、複数人でチームを組んで一つのサイトを制作・運営する場合には状況が違います。
制作チーム全員がこの挙動を理解することが必須となるのです。人数の多いチームともなると、これはなかなかに簡単なことではありません。
よって、複数人でチームを組んで制作・運営をしている大規模サイトの制作においては、スタイルリセットにzoom:1;を組み込むべきではない、と言えます。
ただ、やはりzoom:1;の便利さは捨てがたいものがあります。idセレクタや子孫セレクタなどを使用して、特定の領域にだけ限定的に利用する分には問題はないでしょう。
zoom:1;は便利ですがご利用は計画的にということです。
IEの独自拡張を逆手に取って
CSS HappyLifeさんでまた気になる記事を見つけました。
ソレはhasLayoutというIE独自拡張の一つ。
・・・中略・・・
その結果、hasLayoutがIEの様々なバグの元凶(大袈裟?)だったみたいです。
hasLayoutは、ソコにレイアウトが有るのか無いのかってのを判断しているようで、デフォルトの値がfalseでレイアウト無しになっているので「背景色が指定された要素内でfloatがある時、要素内の文字が消える」とかって現象が起こるっぽいです。
そして、heightやwidthを指定することでトリガーとなりhasLayoutの値がtrueになり、レイアウトが有るとみなされ表示されるようになると。
うへぇー、なるほど。記事内でのお言葉をそのまま使わせていただくと、超GJな記事ですよ。目からウロコ落ちまくり。こういったIEの独自拡張を逆手に取ったコーディングができるようになると、また一味も二味もコーディングの奥深さが違ってくるでしょうね。ただ、独自拡張を使っていくと、W3Cの仕様的にはValidではなくなってしまう点に注意です。
CSS HappyLife 管理人さんがおっしゃる通り、IEではこれが仕様だということでしょう。少なくとも、私はそう解釈することで少しでも納得するようにしています。「バグ」と言ってしまうと、プログラム開発者の想定の範囲外で発生する不具合のことであり、ユーザーとしてはそれに遭遇したが最後、どうしようもないわけですから。
Web標準化という大きな流れの中で、Microsoftの独自仕様が鼻に付くようになった、という解釈で良いのではないかと思います。(IE7のリリースによってMicrosoftもWeb標準に大きく歩み寄ったわけですが)
その記事からリンクのあったMSDN(英語)のリファレンス、ちょっと覗いて見ただけですが、かなりすごいです。天下のMicrosoftだけありますね。
MSDNを本格的に見始めたりなんかしたら、さながらディベロッパーのようです。コーダーという職種は、デザイナーとディベロッパーの調度中間に位置しているような気がします。
IE の Stand Alone版
恥ずかしながら、自宅にMac機がありません。そのうちIntelMacを買ってParallelsを入れてブラウザチェック環境は完璧だ、イヒヒ・・・などと妄想していたりするのですが・・・。