【LazyLoad対策】遅延読み込みによるスクロール先の位置ずれを解決する方法
LazyLoadで遅延読み込みをしていると、スムーススクロール先の位置がズレることなんてしばしばあります。
今回は、JavaScriptを使って簡単にできる対処法をいくつかご紹介します。
LazyLoadは大きく分けて2種類ある
まず、LazyLoadの仕組みを簡単に解説しておきます。
LazyLoadには大きく分けて、以下の2つがあります。
- JS不要のネイティブLazyLoad
- JavaScriptライブラリのLazyLoad
LazyLoadその①
JS不要のネイティブLazyLoad
こちらはネイティブLazyLoadです。
HTMLにloading="lazy"
を加えるだけでブラウザが遅延読み込みしてくれるというものです。
<img scr="画像のパス" alt="" loading="lazy">
対応していないブラウザではloading属性は無視されるため、従来通りの画像表示が行われます。
このloadinng属性の値は、3種類指定可能です。
- lazy(遅延読み込みする)
- eager(すぐに読み込む)
- auto(遅延読み込みをするかブラウザに委ねる)
こちらの実装方法では、widthとheightが記述されていればスムーススクロールによるズレは見られませんでした。
ですので、こちらの対策は今のところ特に必要ありません。
LazyLoadその②
JavaScriptライブラリのLazyLoad
こちらはJavaScriptライブラリによるLazyLoadです。
付与されるクラス名やダミー画像などはライブラリによって異なりますが、大体同じ手法で実装されています。
// 読み込み前
<img src="ダミー画像のパス" data-src="画像パス" class="lazyload">
// 読み込み後
<img src="画像パス" data-src="画像パス" class="lazyloaded">
初期状態では、src
属性にダミー画像のパス、data-src
属性には画像パスが記述されており、読み込まれるタイミングでダミー画像のパスが画像パスに置き換わるというものです。
読み込まれるまではダミー画像の大きさ分しか取得できません。
つまり画像が読み込まれる前にスクロールしてしまうと、ダミー画像の大きさ分しか値が取得できない為位置がずれるというわけです。
ズレを防ぐには、以下の方法が有効的です。
LazyLoad対策
対策方法はいくつかあるのですが、おすすめの順にご紹介します。
- 関数で遅延読み込み解除
- スクロールイベントで遅延読み込み解除
- 再スクロール処理
いずれもJavaScriptに記述します。
LazyLoad対策その①
関数で遅延読み込み解除
画像を読み込むコードを関数で呼び出す方法です。
この方法が必要な時にのみ画像読み込みを行うので、LazyLoadとうまく共存できる一番良い方法かと思っています。
// 遅延読み込み解除
function removeLazyLoad() {
const targets = document.querySelectorAll('[data-src]');
for (const target of targets) {
target.setAttribute('src', target.getAttribute('data-src'));
target.addEventListener('load', () => {
target.removeAttribute('data-src');
});
}
}
// 実行するタイミングで以下を記述
removeLazyLoad();
コードの内容はdata-src
属性を持つ画像要素を取得し、data-src
属性の値をsrc
属性にコピーするというもの。
ページが読み込まれた後は、同じ画像が2回読み込まれることを防ぐために、data-src
属性を削除しパフォーマンスの向上につなげています。
removeLazyLoad();
は呼び出されると即座に画像の読み込みが行われます。
使用例としては、
- クリックイベント
- 遅延読み込み解除
- 少し時間を空けて位置を取得
- スクロール実行
というのが望ましいです。
LazyLoad対策その②
スクロールイベントで遅延読み込み解除
こちらはスクロールが行われたタイミングで、画像を読み込むというものです。
※コードの中身は上と同じ
// Lazy Load対策
window.addEventListener("scroll", function() {
const targets = document.querySelectorAll('[data-src]');
for (const target of targets) {
target.setAttribute('src', target.getAttribute('data-src'));
target.addEventListener('load', () => {
target.removeAttribute('data-src');
});
}
});
こちらを記述しておけば、スクロール時に自動的に画像の読み込みが始まります。
ただしスクロールするたびにリソースが割かれるため、パフォーマンスはあまり良いとは言えません。
LazyLoad対策その③
再スクロール処理
こちらは、スクロール中に再度位置を取得し、最初に取得した位置と異なっていれば新しく取得した位置(正しい位置)にスクロールし直すというものです。
このコードは、スクロール実行の下に記述しておきます。
// スクロール実行
...
// Lazy Load対策(再スクロール)
setTimeout(() => {
// スクロール中に再度位置を取得
const newPosition = target.getBoundingClientRect().top + window.scrollY - headerHeight;
// 最初の位置と新しく取得した位置が異なる場合
if (position !== newPosition) {
// 新しく取得した位置へスクロール
// ...newPosition
}
}, 200); // 遅らせる時間(ミリ秒)
newPosition
にはposition
と同じ値を入れ、「新しく取得した位置へスクロール」にはnewPosition
を指定します。
以下は記述例です。
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回行われ不自然な動きになり、早すぎると遅延読み込みしたコンテンツの位置がうまく読み取れず、正しい位置が取得できません。
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によるスクロールずれの対策を3つご紹介しました。
プラグインやライブラリによって当てはまらない場合があるので、検証しながら対策が必要です。
気になる箇所があればコメント頂ければ幸いです。
おすすめWEBスクール
WEB制作やWEBデザインを学びたいなら、SNSでも話題の「デイトラ
どのコースも10万円前後と業界最安値で、副業や転職に向けて十分なスキルを身につけることができます。
\ ここから飛べます! /
お気軽にコメントどうぞ