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

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

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

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

WordPressのおすすめサーバー

特徴
  • 料金が安い
  • WordPressが超高速
  • ドメイン永久無料
  • 安心の実績とサポート体制

新規も乗り換えも

目次

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

まず、LazyLoadの仕組みを簡単に解説しておきます。

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

  1. JS不要のネイティブLazyLoad
  2. 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対策

対策方法はいくつかあるのですが、おすすめの順にご紹介します。

  1. 関数で遅延読み込み解除
  2. スクロールイベントで遅延読み込み解除
  3. 再スクロール処理

いずれもJavaScriptに記述します。

LazyLoad対策その①
関数で遅延読み込み解除

画像を読み込むコードを関数で呼び出す方法です。

この方法が必要な時にのみ画像読み込みを行うので、LazyLoadとうまく共存できる一番良い方法かと思っています。

// LazyLoad対策(遅延読み込み解除)
function removeLazyLoad() {
  const targets = document.querySelectorAll('[data-src]');
  for (const target of targets) {
    target.addEventListener('load', () => {
      target.removeAttribute('data-src');
    });
    target.setAttribute('src', target.getAttribute('data-src'));
  }
}

コードの内容はdata-src属性を持つ画像要素を全て取得し、data-src属性の値をsrc属性にコピーするというもの。

ページが読み込まれた際に、 data-src 属性を削除していますので、同じ画像が2回読み込まれることを防ぎ、パフォーマンスの向上につなげています。

呼び出したい時には、以下の関数名を記述します。

// 呼び出し方
removeLazyLoad();

removeLazyLoad();は呼び出すとすぐに画像の読み込みが行われるので、条件分岐(アンカー付きのaタグを押したときなど)で使うようにします。

呼び出すべき箇所がよく分からないという人は、次の方法でも構いません。

LazyLoad対策その②
スクロールイベントで遅延読み込み解除

こちらはスクロールが行われたタイミングで、画像を読み込むというものです。
※コードの中身は上と同じ

// Lazy Load対策
window.addEventListener("scroll", function() {
  
  const targets = document.querySelectorAll('[data-src]');
  for (const target of targets) {
    target.addEventListener('load', () => {
      target.removeAttribute('data-src');
    });
    target.setAttribute('src', target.getAttribute('data-src'));
  }
});

こちらを記述しておけば、スクロール時に自動的に画像の読み込みが始まります。

ただしスクロールするたびにリソースが割かれるため、パフォーマンスはあまり良いとは言えません。

LazyLoad対策その③
再スクロール処理

こちらは、スクロールをしている最中にもう一度位置を取得し、最初に取得した位置と異なっていれば新しく取得した位置(正しい位置)にスクロールし直すというものです。

このコードは、スクロール実行の下に記述しておきます。

// スクロール実行
// ...Position

// 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制作のスクール「デイトラ」がおすすめです…!

カリキュラムは3ヶ月分ですが、受講生は卒業後もずっと見放題!常に最新のコンテンツに更新されるため、情報が古くなるなんてこともありません。

価格はどのコースも10万円前後と他のスクールに比べても格安です。
なのに副業・転職に十分なスキルが身につきます。

管理人

私はWeb制作とWebデザインを受講し、現在フリーランスWebデザイナーとなりました。

他にも様々なコースが充実しているので、身につけたいスキルがあったら是非覗いてみてください。

コースの一部をご紹介

よかったらシェアしてね!

コメント

コメントする

目次