アイフォンSEは「position:fixed」した要素のz-indexが効かない
兵庫県三田市でホームページ製作をしいているゴリラドットです。
「position:sticky」とっても便利ですよね。これまでjavascriptやjqueryでゴリゴリスクロールイベントを使って追従させてた部分がホントにcss一行「position:sticky」だけで実装できちゃうんだから。
ただ便利なものを使いだすとさらに欲が出てきて「んじゃposition:stickyが固定になったタイミングでイベントを取得してなんかちょっと半透明にしたり高さコンパクトにしたりしたい!」と思いますよね。つまりstickyイベントを取得したい、というケース。
というコトでここでは「position:sticky」のイベント発火をjqueryやjavascriptで検知してなんか処理する方法を紹介します。
そんなイベントはない
いきなり「そんなぁ~…」という阿鼻叫喚が聞こえてきますが、残念ながらstickyが発動した瞬間のイベント、つまりstickyイベントというのはjavascriptにもjqueryにも存在しません。
んじゃ結局position:stickyを使っててもそのイベントがないなら、これまでと同じようにスクロールイベント使って監視するしかないじゃん!ならstickyじゃなくてfixedとやってることなんにも変わらないじゃん…。と思ってしまいますよね。
んじゃどうやってstickyのイベントを取得するの?という解決方法を。このゴリラドットのホームページのヘッダーの白い所もこの方法に似た方法で実装しています(紹介する方法とはイベント取得のタイミングが少し違います)。
スマホだとsticky無効にしてるんでアレですがパソコンで見てる人ならヘッダーの白い半透明部分がスクロール追従してるし、途中でヘッダーの高さが低くなってコンパクトになってるのが分かると思います。
ここから下は解決方法というよりはこれのやり方になります。
Intersection Observerを使う
「Intersection Observer」という画面内にオブジェクトが表示されたかどうかでイベント取得できる仕組みがあるのでこれを使って解決しちゃいましょう。
スクロールイベントって1ミリでもスクロールしたらイベント発生するから、イベント数多すぎて処理重くなるのがものすごい嫌なんですよね。
「position:sticky」と「Intersection Observer」を組み合わせたstickyタイミング取得方法はこんな感じ。
①sticky要素の一個上の要素に「Intersection Observer」セット
「position:sticky」で固定したいオブジェクトの一個上の要素に「Intersection Observer」をセットします。
もしstickyで固定したいオブジェクトが一番上のオブジェクト(ヘッダーとか)なら、ダミーで高さ1pxのdiv要素とか作っちゃってください。そしてそのダミーのdivに「Intersection Observer」をセット!
こんな感じ。
HTML
<div id="intersection-observer-dummy" style="height:1px;"></div>
<div id="sticky-object"></div>
jquery
var observer = new IntersectionObserver(
myIntersectionFunc,
{
root: null,
rootMargin: "0px 0px 0px 0px",
threshold: 0
}
);
observer.observe( $("#intersection-observer-dummy")[0] );
1~8行目は「Intersection Observer」を使う際のおまじないみたいなもので、肝心なのは9行目。
9行目で実際にどのオブジェクトを監視するかを指定しています。この例では「intersection-observer-dummy
」が表示されたり消えたりするタイミングを監視するように指定しています。
また2行目の「myIntersectionFunc
」はコールバック関数で、イベントが発生したときにこの関数が呼ばれます。名前はなんでもOK。今回はわかりやすくmyIntersectionFunc
ていう名前にしてみました。
②消えたらsticky発動、表示されたら元の位置
上までのソースコードでとりあえず「#intersection-observer-dummy
」が画面に表示されたとき、それから画面外にいった時にイベントが発生するようになりました。
あとはこのイベント処理(ソースコードでいうと「myIntersectionFunc
」を書くってコト)を書いてあげればstickyになったタイミングにバッチリなんかしらの処理ができるわけです。ヘッダーの高さを変えたり文字を小さくしたり、コンパクトにしたり。
さ。それじゃあ肝心の「myIntersectionFunc
」はこんな感じです。
jquery
var myIntersectionFunc = function(entries){
entries.forEach(entry =>{
var target = $(entry.target);
if(entry.isIntersecting){
if( entry.target.id == "intersection-observer-dummy"){
$('#sticky-object').removeClass('sticky-on');
}
}else{
if( entry.target.id == "intersection-observer-dummy"){
$('#sticky-object').addClass('sticky-on');
}
}
});
}
こちらも6行目と10行目以外は「Intersection Observer」を使う上でのおまじないみたいなもの。
上の例では6行目と10行目でそれぞれ「sticky-on
」というクラスを付与したり外したりしてます。
あとはcssの方で「sticky-on
」がついてたら「sticky-object
」の文字サイズや高さを変えたりしてあげればOK。ここまでくればもうcssの世界だから簡単ですよね。
まとめ
position:stickyが固定になったタイミングでイベント取得してなんか処理をしたい!stickyイベントを取得したい!という場合の解決方法を紹介しました。
まとめるとstickyになったイベントというのはjavascriptにもjqueryにも残念ながらないので、「Intersection Observer」を組み合わせて疑似的にstickyイベントを作り出す必要がある、という感じ。
上の例ではヘッダーのstickyイベントを取得したいのでヘッダーの上の要素をダミーで作りましたが、例えばページ中央とかにあるならその一個上の要素に「Intersection Observer」をセットすればOK。
お試しくださいね。