これでできる! クロスブラウザJavaScript入門

第19回 CSSOM View Module解説

この記事を読むのに必要な時間:およそ 4.5 分

要素の位置情報

HTMLの各要素の位置情報は各要素のプロパティから取得できます。

CSSOM Viewで定義されているプロパティ・メソッドは次のとおりです。

Elementのインターフェース

           attribute long scrollTop;
           attribute long scrollLeft;
  readonly attribute long scrollWidth;
  readonly attribute long scrollHeight;

  readonly attribute long clientTop;
  readonly attribute long clientLeft;
  readonly attribute long clientWidth;
  readonly attribute long clientHeight;

  ClientRectList getClientRects();
  ClientRect getBoundingClientRect();

scrollTop・scrollLeftはその要素がスクロール可能な状態であったとき(その要素のスタイルにoverflow:autoとheightなどの値が適用されていて,その要素の中身がheight以上であった場合など)に,そのスクロール量を表します。このプロパティは代入が可能で,有効な値を代入することで実際にスクロールさせることができます。

標準のモードでは,document.documentElement(html要素)がデフォルトでスクロール可能な状態に相当するので,document.documentElement.scrollTopはページのスクロール量を表します。これは,前述のScreenViewにおけるpageYOffsetと一致します。

ただし,WebKit(Safari,Chrome)ではdocument.documentElement.scrollTopは常に0となり,document.body.scrollTopがスクロール量を表すので注意が必要です。

また,互換モードでは,どのブラウザもdocument.documentElementではなくdocument.body(body要素)がスクロール対象の要素となるため,document.body.scrollTop と pageYOffsetが対応することになります。

この部分はCSSOM Viewにおいて最も厄介なところです。まとめると,ページのスクロール量を取得したい場合は次のようなコードになります。

スクロール量の取得

var root = 'BackCompat' === document.compatMode ?
           document.body : document.documentElement;
var scrollY = window.pageYOffset || root.scrollTop;

IE 6~8以外は常にwindow.pageYOffsetが使えるのでそれを利用し,window.pageYOffsetが使えない場合は標準モードか互換モードかを見て,scrollTopを使用します。

scrollWidth・scrollHeightは表示領域から隠れた部分も含めた,その要素が占める領域を表します。

clientWidth・clientHeightはその要素の表示領域自体を表します。padding-widthは含みますが,border-widthとmargin-widthは含みません。

clientTop・clientLeftはその要素のスタイルに適用されたborder-widthの値を返します。

getClientRects・getBoundingClientRectはその要素のClientRectを取得するメソッドです。getClientRectsは折り返しを含むときに,その折り返しごとにRectオブジェクトを返します。getBoundingClientRectはその要素全体を含む領域を表します。

ClientRectはtop, right, bottom, left, width, heightといったプロパティを持ち,その要素の位置に関する情報をまとめて取得することができます。top, right, bottom, leftは現在の表示領域を基点とした値となるので,スクロール量を加算するとそのページでの絶対座標に相当します。

また,CSSOM ViewではHTMLElementのインターフェースも定義されています。ElementとHTMLElementの違いは,ElementがSVGなどHTML以外のDOMにも適用されるのに対して,HTMLElementは名前のとおりHTMLの要素のために用意されたインターフェースです。

HTMLElementはDOM Level 2 HTMLやHTML5などで定義されています。

HTMLElementのインターフェース

  readonly attribute Element offsetParent;
  readonly attribute long offsetTop;
  readonly attribute long offsetLeft;
  readonly attribute long offsetWidth;
  readonly attribute long offsetHeight;

まず,offsetParentはその要素の祖先を遡って,最初にスタイルにposition:static以外の値を持つ要素,もしくはdocument.bodyを示します(ただし,area要素の場合はmap要素を示します)⁠

offsetTop・offsetLeftはoffsetParentからみた,その要素の位置を表します。

offsetWidth・offsetHeightはその要素のborder-widthを含んだ表示領域のサイズを表します。

マウスの位置情報

マウスの位置情報はマウスに関するイベント(onclickやmousedown,mousemoveなど)で取得したEventオブジェクトのプロパティから取得できます。

MouseEventのインターフェース

  readonly attribute long screenX;
  readonly attribute long screenY;

  readonly attribute long pageX;
  readonly attribute long pageY;

  readonly attribute long clientX;
  readonly attribute long clientY;
  readonly attribute long x;
  readonly attribute long y;

  readonly attribute long offsetX;
  readonly attribute long offsetY;

screenX・screenYはモニターを基点としたマウスの座標を表します。

pageX・pageYはそのページ全体の左上を基点とした現在のマウスの位置を表します。IE 6~8は対応していません。

clientX・clientYおよびx・yは表示されている領域の左上を原点としたマウスの位置を表します。pageX・pageYからスクロール量を引いた値に一致します。

offsetX・offsetYはクリックした要素(eventのtarget)からみたマウスの座標を表します。ただし,FirefoxはoffsetX・offsetYに対応しておらず,代わりにlayerX・layerYというプロパティを持っています。このoffset・layerはブラウザによってborder-width・padding-widthを含む含まないの差があるため,正確に値を取得するのは非常に厄介です。そのため,要素のどの位置をクリックしたのかを使用すること自体を避けてしまうのが無難な判断と言えます(実際,ほとんどの場合でclientX・clientYだけで十分なはずです)⁠

なお,IEはpageX・pageYに相当するプロパティがないので,代わりにclientX・clientYにページのスクロール量を足して計算します。

IEでのpageY

var root = 'BackCompat' === document.compatMode ?
           document.body : document.documentElement;
var pageY = event.clientY || root.scrollTop;

まとめ

今回はCSSOM ViewからDOMの位置の扱い方を学びました。次回は今回学んだ内容を実際に使用する実例を中心に扱いたいと思います。

著者プロフィール

太田昌吾(おおたしょうご,ハンドルネーム:os0x)

1983年生まれ。JavaScriptをメインに,HTML/CSSにFlashなどのクライアントサイドを得意とするウェブエンジニア。2009年12月より、Google Chrome ExtensionsのAPI Expertとして活動を開始。

URLhttp://d.hatena.ne.jp/os0x/