トップ «前の日記(2007-02-05) 最新 次の日記(2007-02-07)» 編集

2007-02-06 [長年日記]

_ DOM で要素の絶対的な位置を計算してみる

※ 長さの割に内容はありません。先にあやまっておきますごめんなさい。

ことの発端はある部分のデータ量が多くてそこだけ縦に長くなっちゃってレイアウトが見苦しいので調整したいという要望だった。

んなもん紙じゃねーんだからバランス取ろうとする方がおかしいんだ

と思ったけれども、CSS(overflow: auto) + JavaScript(style.height をごにょごにょ)でなんとかなるかなーと思ってやってみた*1ら HTML の組み方によっては厳しいことが分かってきた。要は

旧石器時代に滅んだはずの table レイアウトってやつ

だ。あれは難しい。なぜなら table は内容全体に応じてセルの大きさが伸縮しちゃうからセルの大きさそのものは計算してもみんな同じなんだな、これが。中身がスカスカで見た目のバランスが崩れているかどうかは、セルの大きさを比較しても分からないわけ。

じゃあってんで内容の方に注目してその height を比較して調整すればいんじゃね?と思ったんだけど、デフォルトの margin なんかがあって意外とうまくいかない。マジックナンバーを投入するとなんとなくうまくいってるように見えるんだけど、ちょっと変更が入っただけで簡単に破綻してしまった。

じゃあ height じゃなくて注目している要素の bottom を比較できればいいんだなと思ったけれど、これをすんなり取得する方法は DOM にはないっぽい。offsetTop, offsetLeft てのはあるんだけどこれは親要素を原点としているので、ページレイアウト上の絶対位置は取得できない。

あれまーと思ったんだけどこういう方法で取得してみた。ある要素の上辺の、ページ内における絶対的な位置を取得する関数*2

function top( obj ) {
  var pos = 0;
  if ( obj ) {
    pos = obj.offsetTop;
    if ( obj.offsetParent ) {
      pos += top( obj.offsetParent );
    }
  }
  return pos;
}

※ 横着してますが obj は DOM の HTMLElement オブジェクトが入ってきていると思ってください。

offsetTop が親要素に対する相対位置なのだから、てっぺんの要素まで再帰でさかのぼって行けばいいじゃんていう話。試したところ狙い通りの値が取れてるみたいなんだけど、なんかおかしいこと考えてるかもしれないんで、気づいた方はツッコんでください*3。一応 Opera 9, MacIE 5, WinIE 6/7, Safari 1.3, Firefox 1.5/2, iCab 3.0.2(build 382) で大丈夫みたい。つか今どきのフレームワークにはこういう機能すでにあるんかもしれんなぁ。

bottom の方は top + height を計算すればいいだけなので割愛。left, right も同じ要領なのでこれまた割愛。というかたぶん調整したいと言われるのは縦方向だけだと思う。

*1 ページング処理すれば?ってのはこの場合デザイン上ナシの方向で。

*2 実際にはこんながっつりグローバルな関数じゃないんだけど。

*3 親要素をはみ出しちゃうようなダイナミックな CSS レイアウトは考慮してません。つかそういうデザインなら今回のようなことは考える必要ないもの。たぶん。