【LazyLoad対策】遅延読み込みによるスクロール先の位置ずれを解決する方法
LazyLoadで遅延読み込みをしていると、スムーススクロール先の位置がズレることなんてしばしばあります。
今回は、JavaScriptを使って簡単にできる対処法をいくつかご紹介します。
LazyLoadは大きく分けて2種類ある
LazyLoadには大きく分けて、以下の2つがあります。
- JS不要のネイティブLazyLoad
- JavaScriptライブラリのLazyLoad
LazyLoadその①
JS不要のネイティブLazyLoad
こちらは、imgタグにloading="lazy"
を加えるだけで、ブラウザによる遅延読み込みが実行されます。
<img src="画像のパス" alt="" loading="lazy">
loading
属性の値は、3種類の指定可能です。
- lazy(遅延読み込みする)
- eager(すぐに読み込む)
- auto(遅延読み込みをするかブラウザに委ねる)
こちらでは、widthとheight属性を実際の画像サイズに基づいて適切に指定しておくと、画像が表示される前にその領域が確保されるため、スムーススクロールによるレイアウトのズレが防げます。
<img src="画像のパス" alt="画像の説明" loading="lazy" width="600" height="400">
LazyLoadその②
JavaScriptライブラリのLazyLoad
JavaScriptライブラリによる遅延読み込みは少し工夫が必要です。
例えばよく使われる「lazysizes.js」では、以下のような形になっています。
<!-- 画像が読み込まれる前 -->
<img src="ダミー画像のパス" data-src="実際の画像パス" class="lazyload">
<!-- 読み込まれるタイミングでパスとクラスが変わる -->
<img src="実際の画像パス" data-src="実際の画像パス" class="lazyloaded">
画像が読み込まれる前には、「軽量なダミー画像」が表示されており、画像が表示される領域に入るとdata-src
属性の値がsrc
属性にコピーされ「実際の画像」に置き換わるという仕組みです。
ダミー画像は数ピクセルの非常に小さな画像なので、実際の画像に置き換わった際に高さが変わってしまい、スクロール前に計算された位置と異なってしまうというわけです。
このようにJavaScriptライブラリの場合、別途以下の処理が必要です。
LazyLoad対策
対策方法は、主に以下の2種類。
- 任意のタイミングで強制的に画像を読み込む
- 再スクロール処理
LazyLoad対策その①
任意のタイミングで強制的に画像を読み込む
今回は「lazysizes.js」に合わせてdeta-src
を指定していますが、使用するライブラリによっては属性名が異なるため、適切に変更してください。
// 画像の強制読み込み
function loadImages() {
const targets = document.querySelectorAll("[data-src]");
for (const target of targets) {
const dataSrc = target.getAttribute("data-src");
const currentSrc = target.getAttribute("src");
// data-src と src が異なる場合のみコピーする
if (dataSrc !== currentSrc) {
target.setAttribute("src", dataSrc);
}
}
}
// 実行するタイミングで以下を記述
loadImages();
コードは単純で、data-src
属性の値をsrc
属性にコピーする処理を、読み込みたいタイミングで実行するだけです。
またdata-src
の値がsrc
の値と異なる場合にのみ処理を行っているので、無駄な処理を防ぐことができます。
実行するタイミングは、
- アンカーリンクをクリック
- 画像を読み込む(ここで実行)
- 少し時間を空けてスクロール位置を取得
- スクロール実行
という順序で行えば、正しいスクロール位置を計算できます。
LazyLoad対策その②
再スクロール処理
こちらは、スクロールの最中に再度位置を取得して、新しい位置にスクロールし直すというものです。
// Lazy Load対策(再スクロール処理)
setTimeout(() => {
// スクロール中に再度位置を取得
const newPosition = target.getBoundingClientRect().top + window.scrollY - headerHeight;
// 最初の位置と新しく取得した位置が異なる場合
if (position !== newPosition) {
// 新しく取得した位置へスクロール
// ...newPosition
}
}, 200); // 遅らせる時間(ミリ秒)
このコードは、1回目のスクロール実行処理の下に記述する必要があります。
jQuery('a[href^="#"]').click(function() {
let header = jQuery("header").innerHeight();
let speed = 300;
let href = jQuery(this).attr("href");
let target = jQuery(href == "#" || href == "" ? "html" : href);
let position = jQuery(target).offset().top - header;
// スクロール実行
jQuery("html, body").animate({ scrollTop: position }, speed);
// Lazy Load対策(再スクロール処理)
setTimeout(() => {
// スクロール中に再度位置を取得
const newPosition = jQuery(target).offset().top - header;
// 最初の位置と新しく取得した位置が異なる場合
if (position !== newPosition) {
// 新しく取得した位置へスクロール
jQuery("html, body").animate({ scrollTop: newPosition }, speed);
}
}, 200); // 遅らせる時間(ミリ秒)
return false;
});
仕組み
setTimeout()
で、位置の再取得を数ミリ秒遅らせて処理しています。
位置の取得時間が遅すぎると、スクロールがシュイーン…シュイーンと2回行われ不自然な動きになり、早すぎると正しい位置がうまく読み取れず実行されません。
1度目と2度目のスクロールがシュイーーーンとうまく繋がるように、秒数を調整する必要があります。
イーズアウト系のイージングだと自然です
どれくらいずれているか確認する方法
const newPosition
の下に、以下のconsole.log
を追加することで、検証のコンソールから2つの位置を把握することができます。
// ...
const newPosition = target.getBoundingClientRect().top + window.scrollY - headerHeight;
// アンカー位置の確認
console.log('最初に取得した位置' +position);
console.log('新しく取得した位置' +newPosition);
// ...
この数値を見ながら遅らせる時間を調整すると、正確性が増します。
現在の位置は以下のコードで確認することができます。
// 現在のスクロール位置の確認
window.addEventListener("scroll", scroll);
function scroll(){
scroll_position = window.scrollY;
console.log( window.pageYOffset );
}
対策してもずれる場合の確認事項
- アンカー要素にアニメーションをつけている
- widthとheightを指定していない
これらが原因でずれる可能性があります。
アンカー要素にフェードインアップのようなアニメーションを行なっている場合は、要素が動いてしまうので当然スクロール位置もずれてしまいます。
親要素を作ってそこにアンカーをつけるなどの工夫をしましょう。
まとめ:自分に合ったLazyLoad対策を
今回はLazyLoadによるスクロールずれの対策を2つご紹介しました。
プラグインやライブラリによって当てはまらない場合があるので、検証しながら対策が必要です。
気になる箇所があればコメント頂ければ幸いです。
おすすめWEBスクール
WEB制作やWEBデザインを学びたいなら、SNSでも話題の「デイトラ
どのコースも10万円前後と業界最安値で、副業や転職に向けて十分なスキルを身につけることができます。
\ クリックしてジャンプ! /
お気軽にコメントどうぞ