【LazyLoad対策】遅延読み込みによるスクロール先の位置ずれを解決する方法

【LazyLoad対策】遅延読み込みによるスクロール先の位置ずれを解決する方法

LazyLoadで遅延読み込みをしていると、スムーススクロール先の位置がズレることなんてしばしばあります。

今回は、JavaScriptを使って簡単にできる対処法をいくつかご紹介します。

目次

LazyLoadは大きく分けて2種類ある

LazyLoadには大きく分けて、以下の2つがあります。

  1. JS不要のネイティブLazyLoad
  2. JavaScriptライブラリのLazyLoad

LazyLoadその①
JS不要のネイティブLazyLoad

こちらはネイティブLazyLoadです。

HTMLにloading="lazy"を加えるだけでブラウザが遅延読み込みしてくれるというものです。

<img scr="画像のパス" alt="" loading="lazy">

また、対応していないブラウザではloading属性は無視されるため、従来通りの画像表示が行われます。

loading属性の値は、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属性には「本来の画像パス」が記述されており、読み込まれるタイミングで「ダミー画像」が「本来の画像」に置き換わるというものです。

読み込まれるまでは、ダミー画像の大きさ(数pxの小さい画像)で計算されています。

つまり画像が読み込まれる前にスクロールしてしまうと、スクロール中に画像が入れ替わり、高さが変わって位置がずれるというわけです。

ズレを防ぐには、以下の方法が有効的です。

LazyLoad対策

対策方法は以下の2つで、いずれもJavaScriptで処理します。

  1. 任意のタイミングで遅延読み込みを解除する
  2. 再スクロール処理

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属性をsrc属性にコピーしたのち、data-src属性を削除するというもの。

data-src属性を削除する理由は、ライブラリによって再度処理されるのを防ぎ、パフォーマンスの無駄が生じる可能性を避けるためです。

実行するタイミングでremoveLazyLoad();を呼び出すと、画像が読み込まれます。

順序としては、

  1. クリックイベント
  2. 画像を読み込む(ここで実行)
  3. 少し時間を空けてスクロール位置を取得
  4. スクロール実行

というのが望ましいです。

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度目のスクロールがシュイーーーンとうまく繋がるように調整する必要があります。

HISA

イーズアウト系のイージングだと自然です

どれくらいずれているか確認する方法

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万円前後と業界最安値で、副業や転職に向けて十分なスキルを身につけることができます。

役に立ったら他の方にシェア

お気軽にコメントどうぞ

コメントする

目次