HTML上のある要素が見える範囲にあるかを JavaScript で判定したい。なんか1発で判定できるメソッドがあった気がしたが見つからなかったので、以下のようになった。

/**
 * element の一部でも見える位置にあるか
 * margin が指定された場合、その分上下左右にビューポートを拡大(または負の場合は縮小)しているとみなして判定する
 */
function isInViewport (e, margin) {
	const rect = e.getBoundingClientRect();
	if (!margin) margin = 0
	return (
		rect.bottom >= -margin &&
		rect.right  >= -margin &&
		rect.top    <= window.innerHeight + margin &&
		rect.left   <= window.innerWidth  + margin
	);
}

/**
 * element 全体が見えているか
 */
function isWholeInViewport (e) {
	const rect = e.getBoundingClientRect();
	return (
		rect.top    >= 0 &&
		rect.left   >= 0 &&
		rect.bottom <= window.innerHeight &&
		rect.right  <= window.innerWidth
	);
}

id:vantguarde 「なんか1発で判定できるメソッドがあった気がしたが」一発ではないかもしれないけどIntersection Observerかしら https://wicg.github.io/IntersectionObserver/

http://b.hatena.ne.jp/vantguarde/20170522#bookmark-338453319

とのこと!! 書いてみるもんだ〜 ありがとうございます。

IntersectionObserver の場合はたとえば以下のように。画像をスクロールに応じて遅延ロードさせたい場合を想定

const observer = new IntersectionObserver( (entries) => {
	for (let entry of entries) {
		const section = entry.target;
		const imgs = section.imgs || section.querySelectorAll('img');
		section.imgs = imgs;
		for (let img of imgs) {
			if (entry.isIntersecting) {
				const src = img.getAttribute('data-src');
				if (img.src !== src) {
					img.src = src;
				}
			} else {
				img.removeAttribute('src');
			}
		}
	}
}, {
	rootMargin: "1000px",
	threthold: 0.0
});
const sections = document.querySelectorAll('section.dir');
for (let section of sections) {
	observer.observe(section);
}
  1. トップ
  2. tech
  3. HTML要素が見える範囲にあるかの判定
▲ この日のエントリ