Cross Browser のための DHTML

StyleSheet の落し穴

〜 DHTML の食えない事情 〜

HTML はドキュメントの表現に関する仕様の割りには充分に明確な仕様でないらしく、 同じ CSSP の仕様に従っているといってもブラウザ毎に実際の表現が微妙に異なります。

そこで、ここでは Microsoft Internet Explorer と Netscape Navigator の HTML、 特に DHTML で必須とも言えるスタイルシートに関して、 実際に遭遇した両者の微妙な(時には全く異なる)表示について 不思議に思ったこと・Cross Browser DHTML 実現の障害になった記述を記すことにします。


目  次

StyleSheet のよくやる間違い
こんな間違いをするとアセります
StyleSheet のやってはいけないこと
こんな記述をすると悲しい目にあいます
総称ファミリのお粗末
IE っていつになったら日本語対応されるのぉ?
ウィンドウサイズのレイア
こんな基本的な部分ですら同じでないとは...
absolute と relative レイア
ふたつのレイアが重なる時...
DIVのサイズ
思い通りのサイズのレイア、作れる?
DIV のサイズ2
クリップされたレイアのサイズは見かけ通りか?
DIV のサイズ3
クリップ領域を比率で指定する時、何が起きる?
DIV のサイズ4
やっぱ IEって、実装がヘンだわっ!
DIV のリサイズ
リサイズすると中のレイアウトはどうなる?
DIVタグの怪・1
DIVタグの指定位置で何かが起きる
DIVタグの怪・2
DIVタグの食い合わせ
レイアの狭間に
absolute指定 の DIVタグの間に入れた改行はどう処理されるか?
レイアの背景色
IE4 と NN4 の background-color の意味するもの
レイアのネスト
レイアはどれぐらいネストできるか?
フォームって何?
NN4 のフォームってなんか特殊

StyleSheet のよくやる間違い

<style type="text/css"><!--
p { color:#ff0000; } //// --></style>

JavaScript風のコメントを付けてしまう。コメントは "/*" ... "*/" で書く。
昔の IE では通用したが、今ではどちらも不幸になる

color:"#ffff00";
color=#ffff00;

思わず HTML と同様にダブルクォートを付けたり "=" で書いてしまう。
間違っていても意外と気が付かない。

font-size:18;

単位を書き忘れる。IE では px として扱われるが NN4 では無視される。

clip:rect(0 50% 50 0);

clip の %表記は IE と NN4 では異なる結果を生む。

※ rect の "%" 指定は W3C CSS2 の範囲外(CSS3 で予定?)


StyleSheet のやってはいけないこと

border-width:3px;

NN4 で border を使用するとムチャクチャになる
(単純なケースは良いが、入れ子にしたレイアで使用すると座標計算が狂う)
absolute な場合は table を併せて使用し、 absolute でない場合は一緒に margin も指定する

source-include:url("external.htm");

よもや、これを使用する人はいないと思うが、この指定をすると NN4 は異常終了する
よく見ると Netscape のサンプルには

include-source:url("external.htm");

と記述されている

然し、これを指定すると無視される(あれっ?反対かな?)
因みに、この指定は W3C で公認されていない。従って IE でも無視される

pre { border:1px solid #ff0000; }

PREタグに border 指定すると NN4 では pre-formatting タグではなくなる
どうしても PREタグにボーダ枠をつけたければ PREタグを DIVタグの入れ子にして DIVタグに border指定をする

但し、NN4 ではブロック要素の入れ子は不自然なスペースが生じるので覚悟がいる(笑)

<div style="margin-left:100px">
inline element string
<div style="position:absolute;">
long long string...
</div>
</div>

IE では、コンテナブロックの中にインライン要素と position:absolute で left指定をしていない長い文字列を含むブロック要素が混在すると 見苦しい横スクロールバーが表示される

※ W3C の仕様ではコンテナとして使用するブロック要素の中にインライン要素がある場合、 匿名のブロックボックスを設定することになっているが、そのような動作になっていない

因みに、Pタグなどで明示的に補うと Pタグの marginが適用されるので注意 ( margin:0px; にすると良いかも )


総称ファミリのお粗末

スタイルシートの font-faimly 属性に指定できるフォントセットには フォントファミリの他に総称ファミリ( generic-family )と呼ばれる最終手段(笑)があります。

これは、指定したフォントがないプラットフォームで表示する際の代替えフォントの意味合いで、 抽象的な概念としてのフォントを提供するための名称です。

このフォント名には "serif"(明朝体相当), "sans-serif"(ゴシック体相当), "cursive"(草書体相当), "fantasy"(装飾文字), "monospace"(等幅フォント) の5種類があり、ブラウザが提供すべきフォント名です。

まあ、CSS2 を知らない NN4 は別格(評価対象外)として他のブラウザは大丈夫だろうと思うと、 そうでもありません。

IE はさすがに英語環境なら問題ないのですが日本語環境では惨憺たる結果になります。

ファミリ名IE4IE5IE5.5IE6
serif
sans-serifかな、カナは×
漢字は文字化け
cursive×数字以外×数字以外×
fantasy××
monosapce英数字は等幅ではない△

※ NN4 は別格と言っても、指定した書体にならないだけで、 少なくとも Win版では全ての指定で日本語が表示されます。

また NN6 はこれら全ての総称ファミリを指定できますので、 間違っていていたとしても問題にはなりません。

IE の評価は総称ファミリ名で示す書体が表示されるかどうかは除外しています。

ひょっとすると IE の文字化けはフォントや IE のインストール環境によって 現象が異なるかもしれません。 f(^^;

問題が総称ファミリなだけに回避策と言ってもたいしたものはないのですが、 IE ですから Windowsマシンに必ず入っているフォント名を 総称ファミリに先行して指定しておくくらいでしょうか

そー言えば IE には Mac版と Soralis,HP版があったよなぁ... 大丈夫だろうか...

... 確認用サンプルはこちら


ウィンドウサイズのレイア

レイアを配置したり表示領域のサイズに合わせてレイアウトしたりする場合、 座標系の原点やレイアのサイズの計算方法を知っておく必要があります。

例えば、表示領域( ウィンドウ )のサイズいっぱいのレイアをスタイルシートで指定するには どう記述すれば良いでしょうか?

<div style="postion:absolute;
            left:0;top:0;
            width:100%;height:100%;"></div>

と記述すれば良いように思えますが、答えは「不十分」です。

まず、"left:0;top:0" はどこを指すでしょうか?

NN4,NN6(Mozilla)ではウィンドウの左上コーナを指しますが、 IE4〜IE6 ではドキュメント( document.body )のマージンの内側を示します。

また、div タグのどこに "left:0;top:0" になるかと言うと NN,IE いずれも マージン枠の外側の左上コーナになります。

次に、"width:100%;height:100%;" の記述ですが、 "100%" とは何に対してのサイズでしょうか?

NN4 は幅が親の描画領域( padding枠の内側 )で高さがウィンドウ幅、 IE は親の描画領域( padding枠の内側 )、 NN6( Mozilla )ではウィンドウ幅( document.body の場合 )に対しての比率になるようです。

おまけに、IE5( 多分 IE5.00 )には高さ方向の計算にバグがあるようで ボーダ領域の内側になるようです。
#> ひょっとすると NN4 の挙動のマネ? f(^^;

また、指定したサイズがどこのサイズを指定しているかと言えば、 NN4 ではマージン枠を含むサイズのようで、 IE はバージョンによりマージン枠を含んだりボーダ枠のみだったりします。 ちなみに、NN6( Mozilla )はマージン、ボーダ、パディング枠全てを含みません。

で、結局、どのように記述すれば良いかと言うとこんな風にでしょうか...

<style type="text/css"><!--
BODY{
  /* 現在のブラウザでは初期値が 0 なので省略
  border-width:0px;
  padding:0px 0px 0px 0px;
  */
  margin:0px 0px 0px 0px;
}
--></style>
    :
<div style="position:absolute;
            left:0px; top:0px;
            width:100%; height:100%;
            clip:rect( 0 100% 100% 0);"></div>

※ 参考までに上記動作のどれが W3C的に正しいかと言うと、 IE の BODYタグの border の扱いは間違いですが、 その他のドキュメントの幅や座標系に関しては未定義、 レイアのサイズや位置に関しては NN6( Mozilla )が正しいようです。
#> 但し、現状での NN6( Mozilla )にはバグがありますし、 この仕様が Webデザイナに対して扱いやすいかは別の問題です。 f(^^;


absolute と relative レイア

レイアは位置指定(position)の方法により、 絶対座標(absolute)と相対座標(relative)の2種類のレイア ( W3C的にはもっとありますが、ここでは省略 )があります。

この2種類のレイアが重なったとき、どのようになるでしょうか?

<div style="position:absolute;
       width:200; height:50; clip:rect(0 200 50 0);
       border:1px solid #99ccff;
       background-color:#99ccff;
       layer-background-color:#99ccff;">
<table border=0 cellspacing=0 cellpadding=0
       width=200 height=50><tr><td></td></tr></table>
</div>
<div style="position:relative;
       width:200; height:100;">
<table border=0 cellspacing=0 cellpadding=0
       row=2 width=200 height=100 bgColor="#ffcc99">
<tr><th>
  <a href="" onClick="alert('click'); return false;">
    Click Me
  </a>
</th></tr>
<tr><th>
  <a href="" onClick="alert('click'); return false;">
    Click Me
  </a>
</th></tr>
</table>
</div>

このコードは 200×50 pixel の absolute レイアの上に 200×100 pixel の relative レイアを表示しているように見えますが、実際の表示はこれと逆になり、 下の absolute レイアは relative レイアに隠れて見えなくなります。

実際の表示は以下のようになります。

 
Click Me
Click Me
relative レイア
absolute レイア

もし、 relative レイアにクリッカブルなオブジェクトがある場合、 表示は同じでも IE と NN4 では動作が異なります。

NN4 では absolute レイアが下にあって表示されていないにもかかわらず、 重なっている部分のリンク(上の「Click Me」)は選択できません。 IE4 は通常選択できますが、何らかの理由により、 重なっているレイア全体が選択できなくなる場合(*1)があるようです。

*1 一般的にはバグと呼んで差し支えないでしょう。 色々試してみると、どうも IE4 のキャッシュ管理で更新漏れのタイミングがあるようです。

IE5 以降については未確認です f(^^;


DIVのサイズ

レイアのサイズ指定はレイア生成時のヒントとして使用されますが、 あえて指定しなくても自動的に調整されます。

然し、この調整動作はブラウザ依存になります

ブラウザ 文字列の長さ
短い場合 長い場合(最大)
IE4 absoluteでなければ、コンテナブロックの幅まで。
absoluteな場合は left指定しなければ現在位置からコンテナブロックの幅まで。
left指定した場合はコンテナブロックの右端からコンテナブロックの margin-left値を コンテナブロックの右端から引いた値まで(?)。
IE5
IE6.0
absoluteな場合は必要な幅だけ
それ以外はコンテナブロックの幅
absoluteでなければコンテナブロックの幅まで。
absoluteな場合は left指定しなければコンテナブロックの幅まで。
left指定した場合はコンテナブロックの座標系でのleft位置から コンテナブロックの右端までの幅。
( 但し、コンテナブロックが absoluteでない場合は位置は BODY部の座標からの位置になる )
NN4 position属性がなんであっても必要なサイズのみ
NN6 absolute,fixed指定時は必要な幅だけ
その他はウィンドウの端まで
left位置からウィンドウの端まで

また、absolute な場合 IE では width を指定すればその幅になりますが、 NN4 では clip を指定しなければサイズは自動調整されます。

IE4 の仕様はフォントサイズを指定したとしても、ブラウザ依存になりますから コンパクトなレイアを作成しようとする場合は難しい問題となります。

NN4 の仕様は IE のように致命的ではありませんが、 実質的に clip を指定する必要があるため、コードが煩雑になります。

実際のクロスな対処には普遍的なものはなく、 ケースバイケースで工夫することになりそうです。 f(^^;

確認した HTML はこちら( NN4 では一部おかしな表示になります f^^; )。

※ IE5以降のバージョンでは absolute指定時 width 指定をしないと 一見 NN と同様にタイトなレイアが作成できるように見えますが レイア内部に含まれる文字列が自動調整により折り返される場合、 摩訶不思議なレイア幅になる場合があるので注意が必要です。

まあ、いずれにしても absoluteでないコンテナブロック内に absolute なものを配置しない方が良いでしょう。

※ W3C CSS2の仕様から見れば、この幅の動作は NN6 が最も近いように見えます。

また、この仕様では absolute なレイアの座標系は 「直近の親の absolute なコンテナブロック」としています。

そこで absolute なレイアがない場合 body の座標系に従って配置されますが、 「bodyタグは absolute なブロックか?」なんて感じたりして(笑)
#> まあ、いずれにしても現仕様の方が助かるんですが f(^^;


DIVのサイズ2

absoluteなレイアに clip 指定をした場合、レイアのサイズはどのようになるでしょうか?

これはブラウザ依存の結果になり、NN4 では clip指定のサイズになりますが、 他の IE や NN6 では clip指定されない場合の領域を専有します。

つまり、たとえ clip した結果の表示領域がウィンドウ内にあっても clipされた領域がウィンドウ外にあれば、 不可解なスクロールバーが表示されることになります。

例えば、以下のような HTML を width=300 height=100 のウィンドウに表示した場合 NN4 以外ではスクロールバーが表示されますが、 スクロールしても何も表示されません(※)

<style type="text/css"><!--
body {
  margin:0px 0px 0px 0px; padding:0px 0px 0px 0px;
}
h3 {
  margin:5px 1em 5px 1em;
  padding:5px;
  background-color:#ffffee;
  text-align:center;
  border:1px solid #333399;
  font-size:18pt;
}
.cp{
  position:absolute;
  width:500px; height:200px;
}
#cp1{
  left:0; top:0;
  clip:rect(0px 300px 100px 0px);
  background-color:#eeeeff;
}
--></style>
<div class="cp" id="cp1">
<table cellspacing=0 cellpadding=0 border=0
       width=500 height=200 bgColor="#ffeecc">
<tr><td>
<h3>クリップされたレイアのサイズ</h3>
<hr align=center width=95%>
<div align=center>
Copyright(c) 2001 ShinSoft. All rights reserved.
</div>
</td></tr></table></div>

※ 「スクロールしても何も表示されません」と言っても、 IE5.0 では clip された領域にもボーダ枠を描画するバグがありますので このサンプルではボーダ枠のみ表示される場合があります(笑)。


DIVのサイズ3

スタイルシートでレイアのサイズなどを比率(%)で指定する場合、 何に対する比率を指定することになるのでしょうか?

調べてみると一応結果は以下の通りになりました。

ブラウザleftwidthclip
IE4/5/6 ウィンドウ(body部)(*1) 上位のコンテナブロック
NN4 ウィンドウ(body部)(*2) 上位のコンテナブロック(*3)
NN6 ウィンドウ(body部) absoluteな場合はウィンドウ(body部)
その他は上位のコンテナブロック
無視

*1 もちろんabsoluteな場合です。

*2 NN4は複雑な指定をするとまともに表示されないので類推です。

*3 実際には clipと併用して指定しないとサイズが自動調整されます。

※ W3C CSS2的に言うと、どれも間違った描画になると思います。

W3C CSS2 の仕様そのものについては従来仕様との互換がないため、 これを採用しているブラウザはありませんので、 clip:rect 仕様そのものについてはおいといて(笑)...

まず、IE は absolute な場合の座標系が混在していますし、 NN4 は論外、NN6 は、まあ、近いと言えば近いのですが 本来は absolute な場合は上位の absoluteなコンテナブロックの座標系に従うハズなので %指定もこれを基準にする必要があると思われます。

また、clip:rect指定は IE,NN4 共に使用できますが、W3C CSS2 では%指定はありません(笑)。

因みに、確認に使用した HTML は こちら


DIVのサイズ4

まず、下の HTML で生成されるレイアを想像してみてください。

<div style="position:absolute;
            width:1px; height:1px;"></div>

1×1ピクセルのレイアが表示されると想像できましたか?

しかし NN6 を除いて実際は違います。

NN4 では DIVタグの表示するものがないため、何も表示されませんし、 IE では横幅は 1pixel であるものの、縦は異なります。

一体 IE のこの縦の長さは何なのか、と言うとその時適応されているフォントの高さです(笑)。
そこで、今度は表示する内容として 1×1pixel の画像を指定してみましょう。

<div style="position:absolute;
            width:1px; height:1px;"
><img src="1x1.gif" width=1 height=1></div>

この場合は NN4, IE 共に 1×1ピクセルのレイアになります(*1)

*1 1×1画像を貼付けるならレイアの width,height 指定は無くてもOKです。

NN4 は当たり前としても、IE で正常に表示されるとなると、 どの様な実装をしているか興味が湧いてきます。 f(^^;

このような現象を避けるには、しょーがないので、 意味もなくレイアにフォントサイズを指定してやります。 f(笑;

でも、このままでは NN4 では表示されませんから クロスにするなら clip 指定も必要かな f(爆;

<div style="position:absolute;
            width:1px; height:1px;
            clip:rect(0 1 1 0);
            font-size:1px;"></div>

因みに、再現できる HTML はこちら


DIVのリサイズ

NN4 ではウィンドウをリサイズした時 レイアのレイアウトやデザインが崩れることは有名です(笑)。

また、レイア自体には resizeTo,resizeBy というメソッドがあり、 このメソッドを使用すればレイアのサイズを変更することができます。

しかし、このメソッドはサイズを変更してはくれるのですが、 タグ内の HTML のリサイズ・再配置はしてくれません(*1)

もし、何らかの都合で HTML を含むレイアのリサイズが必要になった場合は 単に初期表示時のレイアウトの問題であれば HTML の読込時に STYLEタグを直接 document.write するか、 ロード後のリサイズであれば内容物を書き替えた方が得策でしょう。
因みに IE や NN6 では style の pixelWidth(IE4), width(IE5+,NN6)を変更すれば 内容物の再配置も自動的に行われます(*2)

*1 resizeTo,resizeBy メソッドは clip.width/height を変更するメソッドなので 名称は "resize" ですが、機能は "clip" でしょう(笑)

*2 IE ではウィンドウのリサイズを行った場合、 例えば、一旦小さくして元に戻したりしても元のレイアウトにはならないかもしれません。

この問題のサンプルはこちら


DIVタグの怪1

まず、次の HTML を見てください。

開始
<div class="pr1">block element</div>
終了

W3C CSS2 では「匿名BOX」という考え方で、 以下のように解釈されることを期待します。

<p>開始</p>
<div class="pr1">block element</div>
<p>終了</p>

事実 IE, NN 共にこのような表示になります。

しかし、"pr1" クラスが position:absolute である場合には ブラウザ毎に解釈が異なります。

W3C の仕様を知らない NN4 は absolute 指定を無視して匿名BOXを生成しますが、 他のブラウザは P要素に関して以下の HTML と等価に解釈します。

開始
終了
<div class="pr1">block element</div>

DIV要素に関しては IE, NN6 で解釈が異なり、 IE は left位置を display:inline 扱いに、 NN6 は left位置を display:block 扱いします。

* まあ、こんな記述は避けるのがシアワセと言うものでしょう。 f(^^;


DIVタグの怪2

DIVタグ以外のブロック要素タグ内に absolute な DIVタグを混在させた場合は 「DIVタグの怪1」の通りですが、更に PREタグ内で absolute な DIVタグを使用すると IE4 でちょっと困ったことになります。

<pre>
1行目<div class="pr1">block element</div>
2行目
3行目
</pre>

とした場合、IE4 では以下のような解釈になり、PREタグの状態が解除されます(*1)

<pre>
1行目
</pre><div class="pr1">block element</div>
2行目
3行目

※ この問題は IE5 で修正されています。


レイアの狭間に

まず、次の HTML を見てください。 このコードは異なるフォントサイズの absolute なレイア間に BRタグをはさんだものです。

<style type="text/css"><!--
.betweenDiv{
  position:absolute;
  font-family:Arial,sans-serif;
}
--></style>
<div class="betweenDiv" style="font-size:48px">
JavaScript
</div><br>
<div class="betweenDiv" style="font-size:24px">
JavaScript
</div><br>
<div class="betweenDiv" style="font-size:12px">
JavaScript
</div><br>

このコードで期待する表示は、 作成した親となるドキュメントのフォントで決定される行間隔の表示 ( レイア間が間延びしたり重なったり )です。

実際、IE,NN6 ではそのようになります。
しかし、 NN4 の場合は綺麗に並びます。

ためしに BRタグの前に &nbsp;( no break space )を挿入してやると IE と同様の表示になります。

&nbsp; なし
JavaScript

JavaScript

JavaScript



&nbsp; あり
JavaScript
 
JavaScript
 
JavaScript
 


※ 「そんなヤツぁいねぇ〜よ!」って言われそう f(^^;;;


レイアの背景色

スタイルシートに限らず IE と NN のプロパティには同名であるが異なる意味の物があります。

background-color もこの1つです。

スタイルシートで background-color を指定すると IE ではその要素の背景色の指定になりますが NN4 ではフォントの背景色の意味になります。

NN4 でも同様に absolute なレイアに背景色を指定するには layer-background-color を指定する必要があります。
そこで、クロスにするために background-color 及び layer-background-color を 指定することになりますが、 レイアを入れ子にする場合には backround-color属性が継承されるので注意が必要です。

この問題の対応策としては幾つかの方法がありますが、 最も簡単な方法は透明色を指定する方法でしょう。

<div style="position:absolute;
            width:100px; height:100px;
            clip:rect(0 100px 100px 0);
            background-color:#000000;
            layer-background-color:#000000;
            font:bold 24pt Arial,sans-serif;
            color:#ffffff;">
  <div style="position:absolute;
              left:20; top:20;
              width:50px; height:50px;
              clip:rect(0 50 50 0);
              background-color:#ff9999;
              layer-background-color:#ff9999;
              color:#ff0000;">JS</div>
  <div style="position:absolute;
              left:30; top:30;
              width:50px; height:50px;
              clip:rect(0 50 50 0);
              background-color:transparent;
              color:#9999ff;">JS</div>
</div>

※ background-image についても NN4 では layer-background-image であり、 同様の現象になりますので注意して下さい


レイアのネスト

レイアはどれくらい入れ子にできるのだろうか?

これを実験してみると以下のようになりました(*1)

ブラウザネスト数備考
IE46465個目で異常終了する
IE54040以上生成しても描画されない
IE64040以上生成しても描画されない
NN4不定いくらでも生成できるようだが多いと描画が崩れたりマウスイベントで異常終了する
NN6197198以上生成しても描画されない

*1 実験は DIVタグの HTML を document.write して測定したものです

※ まあ、クロスブラウザを目指すなら、 レイアのネストは 2 〜 3個までにした方が賢明でしょう f(^^;


レイアの背景色

どうも NN4 では FORM は特殊なレイアの位置づけのようで、 IE, NN6 ではレイアのスタック( zIndex )に基づいて表示されますが、 NN4 では必ず FORM要素が表示されます(*1)

*1 但し、ボタン操作はできません(笑)

NN4 は最も酷い例ですが、他の IE, NN6 でも油断はできません(笑)。

例えば、IE では、何故かリスト( SELECTタグ )は NN4 と同様表に表示されますし、 その他の FORM要素でも要素の一部が隠れているような場合には表示されるものもあります。

対策としては FORM の上にはレイアを重ねないようにする以外にはないようです。

※ FORM要素自体をレイア内にして、レイアの表示非表示を制御するのはアリです。 (^^)v



普通のチェックボックス
普通のラジオボタン


Copyright(c) 1998 - 2001 ShinSoft. All rights reserved.