作ったよ。
というお話。
position: sticky;なstyleを持つコンポーネントを用意すればいいだけ。
と思っていたのですが、
position: sticky;はコンテナ(親要素?)の中でのみfloatするようで、
<div> <div style="position: sticky; ..." > aaa </div> </div>
のようなHTMLではstickyしてくれないようで、
汎用コンポーネントとしては非常に使い勝手が悪い。
そのため、stickyしたいところではposition: fixed;。
元の位置に来たらposition: static(|relative);になるコンポーネントを作ることとした。
このコンポーネントを作成する上でポイントとなるのは、Intersection Observerだ。
Observerが交差を判定したら、styleを切り替えれば良い。
しかしその前に確認が必要だった。
floatしている要素にObserverは判定するのか?
結論はNO。
仕方がないのでダミーのElementを置くことで判定することとした。
JSXはこう。
<div>
<div
className={classNames({
isStatic: isIntersecting,
})}
>
{children}
</div>
<div ref={dummyRef} />
</div>
あとはIntersection Observerでdummyを監視してあげれば良い。
useEffect(() => {
(async () => {
if (typeof window.IntersectionObserver === 'undefined') {
await import('intersection-observer');
}
if (!dummyRef.current) return;
observer = new IntersectionObserver(
entries => {
const dummyEntry = entries[0];
setIsIntersecting(dummyEntry.isIntersecting);
},
{ threshold: 1 }
);
observer.observe(dummyRef.current);
})();
}, []);
実物は、ダミーに高さを持たせて、元の位置に戻るときのカクツキをなくしたり、
イベントハンドラを用意していたりしますが、
その辺は必須ではないため、省略しています。