何かしらの機能を作る時、画面内の要素に関連した何かを表示することがあります。例えば、画像と画像の間を線で結んだりとかそういったものです。その様な機能を作る時、参照先が非表示だと画面上で虚空に何かを伸ばしたり、エラーになったりと不都合なことが起こりやすいです。これに対処するための方法として表示、非表示の判定があり、その方法を紹介します。
よくある方法はクラス名などの属性で状態を管理する方法です。React の state や Vue.js の data などでも同様に管理できます。クラス名の場合はなにかしらで非表示状態になっている時はクラス名に hide が増え、表示状態の時は hide がない、といった具合です。これはその非表示状態を示すものに非表示用の CSS を割り当てる意味でも便利です。
この方法の問題点として、開発者側で表示、非表示の制御をすべて取り扱う必要がある点があります。なんらかの副作用で表示、非表示が切り替わって制御できなくなると奇妙な状態が出来上がりやすくなります。また、今ある状態を知りたいのみで制御まで取り扱いたくない場合もあり、そういった場合においてこの方法は不適切です。
おすすめの方法は要素のoffsetParent
プロパティを参照する方法です。offsetParent は位置に関連する直近の親要素への参照を返してくれます。
HTMLElement.offsetParent – Web API | MDN
位置に関連する要素というのは、position: fixed, position: absolute, position: relative などのスタイルを持つ要素です。なければ body への参照が返ってきます。とはいえ、この記事において親要素そのものはさして重要ではありません。重要なのは上記 MDN ページより引用した次の部分です。
メモ: 次の状況では、offsetParent
は null
を返します。
- 要素またはその親要素の
display
プロパティがnone
に設定されている。 - 要素の
position
プロパティがfixed
(固定位置指定) に設定されている (Firefox は<body>
を返します)。 - 要素が
<body>
または<html>
要素である。
要素自体や親要素が display:none で非表示になっている場合、offsetParent は null を返します、このため次の様な関数が作れます。
/** 要素が display: none 由来で非表示の場合、true を返す */ function isHiddenByDisplayNone(element){ return element.offsetParent === null; }
ここでは display: none に注目しましたが、もしスクロールなどによる画面内にいるか、いないかといった表示、非表示の判定ならば IntersectionObserver や getBoundingClientRect で座標を計算するのが便利です。
交差オブザーバー API – Web API | MDN
Element.getBoundingClientRect() – Web API | MDN