はじめに
Webサイトのコーディングでスクロール量が一定以上の場合に発火するロジックを作成したのですが、Chromeでは問題なく動作したもののSafariではうまく動作しないケースが発生しました。
この記事で発生した事象とその解決策を備忘録がわりに記載したいと思います。
作成したコードと発生した事象
「画面を読み込んだ時のスクロール位置」を基準にして、読み込み時にページ上部から一定以上のスクロール量があればclassを付与するロジックを作成しました。
function showItem(){
const deviceWidth = window.innerWidth;
const deviceHeight = window.innerHeight;
changePointInLoad = deviceHeight * 2.5;
showDurationMs = 300;
const scroll = window.scrollY;
if(scroll > changePointInLoad){
setTimeout(()=>{
document.querySelector(".container").classList.add("is-show");
}, showDurationMs)
}
}
window.addEventListener("load", ()=>{
showItem();
});
このコードを実装したところ、Chromeではローディング(再読み込み)時にスクロール量を取得できたものの、Safariではスクロール量を取得できないという現象が発生しました。
対策
ローディング量の取得関数を非同期処理にする(setTimeout
にする)ことで問題が解消された。
function showItem(){
const deviceWidth = window.innerWidth;
const deviceHeight = window.innerHeight;
// この部分のsetTimeoutを追加
setTimeout(()=>{
changePointInLoad = deviceHeight * 2.5;
showDurationMs = 300;
const scroll = window.scrollY;
if(scroll > changePointInLoad){
setTimeout(()=>{
document.querySelector(".container").classList.add("is-show");
}, showDurationMs)
}
, 10)
}
window.addEventListener("load", ()=>{
showItem();
});
複数の資料によるとスクロール位置の復元タイミングはブラウザ間で差異があると言われています。また、Safariではローディング時にスクロールの更新がされる前にDOMの更新が行われる例があるようです。
そのため、setTimeoutで遅延を入れることでスクロール位置とレイアウト描写のタイミングが意図した通りのタイミングで行われることになります。
ただしsetTimeout
で遅延させることでユーザー体験を損ねる可能性もあります。
あくまで応急処置的な方法で頭に入れておくと良いと思います。
参考資料
https://zenn.dev/akfm/articles/next-js-scroll-restore