jQuery でサイズや位置を取得する方法を図にしてみた(2)

更新履歴

2010-01-21
本エントリの内容も含めた最新の情報は下記エントリをご参照ください。

前回のつづきです。
前回同様 width の記述は省略してますが、height を width に置き換えれば幅も取得できます。

attr() メソッドでサイズを取得する際の注意点

attr('offsetHeight') や attr('clientHeight') でサイズを取得する際、対象要素が非表示状態だと 0 が取得されてしまいます。
要素を表示させる際、位置決め等のために表示処理前に対象要素を採寸することがあるかと思いますが、そのような場合注意が必要です。
対象要素が非表示だった場合、一時的に表示状態し、採寸後に非表示にするようなプラグインを定義しておくと便利です。(以下参照)

$j.fn.measur=function(f){
	var o=this,ret;
	var hide=o.is(":hidden");
	if(hide)o.show();
	ret=f();	
	if(hide)this.hide();
	return ret;
}
$j.fn.exClientHeight = function(){
	var o=this;
	return o.measur(function(){
		return o.attr('clientHeight');
	})
}

outerHeight() , innerHeight()メソッド

jQuery のリファレンス系のサイトでも見かけませんが、outerHeight() , innerHeight()メソッドというのがあります。
outerHeight() メソッドは、前述の attr('offsetHeight') と同様に要素の外寸が取得できます。
outerHeight() メソッドの場合、要素が非表示状態であっても正しく採寸されるので、こちらを使用した方が良いかと思われます。

innerHeight() メソッドは、要素の内寸を取得します。要素が非表示でも正しく採寸されます。
attr('clientHeight') と同じようですが、スクロールバーの幅が含まれるという点が異なります。(上図参照)

offsetParent() メソッド

CSS 的な意味合いでの原点位置を持つ親・先祖要素(position:relative or absolute な直近の先祖要素、それらが無い場合は html 要素)を返してくれます。

2008.2.18 追記
いろいろと問題点あるようです。詳しくはこちら。

offsetTop/offsetLeft/offsetParentの闇 - Backstage of theater.js

position() メソッド

CSS 的な意味合いでの自要素の位置を返してくれます。
前回のエントリで、

プラグインのように様々な指定のされ方を想定した処理の中で CSS 的な位置が欲しい場合は、自身の offset() メソッドの取得値と、relative , absolute な直近の親・先祖要素の offset() メソッドの取得値の差分で求めた方が確実です。

とか、ややこしいことを言ってますが、position() メソッドのみで簡単に取得できるようです。

2008.2.18 追記

親・先祖要素の擬似フレームがあるとスクロール量分、減算されてしまうようです。
下記のようなメソッドで代替する必要がありそうです。

$j.fn.exOffsetParent = function(){
	var o=this;
	return o.measur(function(){
	    var op=o.offsetParent();
	    return op.attr('tagName')=='BODY'&& op.css('position')=='static'?$j('html'):op;
	})
}
$j.fn.exPosition = function(){
	var o=this;
	return o.measur(function(){
		if(o.attr('tagName')=='HTML'||o[0]==window||o[0]==document)
			return {top:0,left:0};
		else{
			var pos=o.position();
			var container = o.exOffsetParent();
			if(container.attr('tagName')=='HTML')return pos;
			return {
				top:pos.top+container.exScrollTop(),
				left:pos.left+container.exScrollLeft()
			}
		}
	})
}

また、上記のメソッドでも body 要素に border、position:relative 等の設定があるとブラウザ別に差異が発生してしまうようです。