Opera用Hit-a-Hint作成記・経過報告 5
Opera で getClientRects と getBoundingClientRect の挙動がものすごく変
この前書いたの続き。なんとなく分かってきたので、詳しく書く。
新しい Hit-a-Hint が動かなかったこちらのページを検証していて発見した。
HTML ソースは切り詰めるとこんな感じになっていて、
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html dir="ltr"> <head> <meta http-equiv="Content-type" content="text/html; charset=UTF-8"> <style type="text/css"> .topic img { display: block; } </style> </head> <body> <DIV class="topic" > <A href="http://slashdot.jp/search.pl?tid=92" > <IMG src="http://images.slashdot.jp/topics/topicsecurity.gif" width="59" height="78" alt="セキュリティ" title="セキュリティ" > </A> <A href="http://slashdot.jp/search.pl?tid=51" class="topic2" > <IMG src="http://images.slashdot.jp/topics/topicmozilla.gif" width="80" height="64" alt="Mozilla" title="Mozilla" > </A> <A href="http://slashdot.jp/search.pl?tid=41" class="topic2" > <IMG src="http://images.slashdot.jp/topics/topicie.gif" width="64" height="64" alt="インターネットエクスプローラ" title="インターネットエクスプローラ" > </A> </DIV> </body> </html>
この .topic img { display: block; }
があるときに、下にのような変なことが起こる。
各要素に対して getClientRects と getBoundingClientRectを取る。括弧内の数字は、[left,top,right,bottom] の値。
テスト 1
(1) 最初のブロック
getBoundingClientRect() | getClientRects()[0] | |
---|---|---|
a | [0,0,0,0] (おかしい) | 失敗 |
img | [8,8,67,86] (正常) | [8,8,67,86] (正常) |
(2) 2番目のブロック
getBoundingClientRect() | getClientRects()[0] | |
---|---|---|
a | [0,0,0,0] (おかしい) | 失敗 |
img | [8,86,88,150] (正常) | [8,86,88,150] (正常) |
(3) 最後のブロック
getBoundingClientRect() | getClientRects()[0] | |
---|---|---|
a | [8,134,8,155] (幅がゼロ?) | [8,134,8,155] (幅がゼロ?) |
img | [8,150,72,214] (正常) | [8,150,72,214] (正常) |
「失敗」のときはエラーコンソールにも何も出ない。
Firefox では全部正常に取得できた。但し、HTML を詰めて書いていないため、ホワイトスペース (つまりテキストノード) の Client Rect も取得するらしく、getClientRect()[0] は幅がゼロの長方形を返し、getClientRect()[1] でやっと子要素の長方形を返すということがあったりする。
Opera でももしかしたらと思い、 (3) の a 要素で getClientRects().length としてみたら、ちゃんと(?)「1」でした。
テスト 2
次に、.topic img { display: block; }
を消してみる (つまり inline 表示)。この場合、最初のブロックとその他にレンダリングの性質上の違いはない。
getBoundingClientRect() | getClientRects()[0] | |
---|---|---|
a | [8,8,67,91] (画像+テキスト領域) | [8,70,67,91] (テキスト領域) |
img | [8,8,67,86] (画像領域) | [8,8,67,86] (画像領域) |
つまりこういうこと。(黄色が画像+テキスト領域、オレンジが画像領域、黄緑がテキスト領域)
こちらも案の上 a 要素のほうで getClientRects().length==1 だった。
Firefox だと、すべてにおいてテキスト領域を返した。インライン要素だからそういうことなのかもしれないけど、実際の表示では中の大きいの要素に合わせているのだから、Bounding (要素を「縛って」いる) Client Rect もそれに合わせて広がる気べきな気がする。
テスト 3
.topic img { display: block; }
を元に戻して、最初のブロックの img 要素を消す。つまり a 要素の innerHTML が無い状態にする。
すると、 その a 要素で、このようになる。
getBoundingClientRect() | getClientRects()[0] | |
---|---|---|
a | [0,0,0,0] (おかしい) | 失敗 |
テスト 4
テスト 3 の状態で、再度 .topic img { display: block; }
を消して、最初の a 要素の後に < br > タグを入れる。
結果はテスト 3 と同じ。
getBoundingClientRect() | getClientRects()[0] | |
---|---|---|
a | [0,0,0,0] (おかしい) | 失敗 |
テスト 4 は、実はこの前書いた場合と同じである。
結論
Opera では、要素の内部が何か知らないうちは getBoundingClientRect も getClientRects も使うな。
さて、Hit-a-Hint を修正しないと。
書いてみた。かなりその場凌ぎ的ではあるけど。
もうほぼ完成に近いと思うんだけどなあ。
まだあった。下のようなときに getClientRects が失敗する。
<A href="http://type.jp/s/navi/0801/index2.html?000207TU012733=PID" > <BR> </A>
こんな HTML 書くなよー!