作ったよ。
というお話。
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); })(); }, []);
実物は、ダミーに高さを持たせて、元の位置に戻るときのカクツキをなくしたり、
イベントハンドラを用意していたりしますが、
その辺は必須ではないため、省略しています。