画像の遅延読込でページ内リンクがずれる時の解決法【jQuery】

アンカーリンク(aタグ)を使って、メニューや目次からページ内の特定の場所にジャンプさせることってよくありますよね。

ところがそれにloading=”lazy”などの遅延読み込みを組み合わせると、ジャンプ先がずれてしまいます。

ランディングページでどうしても両者を共存させたかったので、色々調べて解決した方法をご紹介します。

目次

スムーススクロール用のjQueryの記述を変えよう

まずHTML側は、ざっくりこんな形だとします。

<ul>
  <li><a href="#link01">リスト01</a>></li>
  <li><a href="#link02">リスト02</a></li>
  <li><a href="#link03">リスト03</a></li>
</ul>

<div id="link01">
  <p>ブロック01</p>
  <img loading="lazy" src="demo.jpg">
</div>

<div id="link02">
  <p>ブロック02</p>
  <img loading="lazy" src="demo.jpg">
</div>

<div id="link03">
  <p>ブロック03</p>
  <img loading="lazy" src="demo.jpg">
</div>

解決したjQueryのソースコード

$('a[href^="#"]').click(function(e) {
	var href = $(this).attr("href");
	var target = $(href == "#" || href == "" ? 'html' : href);
	var position = target.offset().top;

	$.when(
		$("html, body").animate({
			scrollTop: position
		}, 400, "swing"),
		e.preventDefault(),
	).done(function() {
		var diff = target.offset().top;
		if (diff === position) {
		} else {
			$("html, body").animate({
				scrollTop: diff
			}, 10, "swing");
		}
	});
});

私と同じようにloading=”lazy”を採用したことで、いつも使っていたページ内リンクへのスムーススクロールが上手く動かなくなった…という方の記事を見つけて参考にさせていただきました。

参考:「loading=”lazy”とページ内リンクへのスムーススクロール(URLの#以降を表示させたくない)

ソースコードの解説もしていきます。

ずれる理由と、解決方法の解説

そもそもなんでずれるの?というところから。

画像の遅延読み込みをしていなかった時、ページ内リンクへのスムーススクロールは下記のようにしていました。
WEB制作会社で働いていた頃、しょっちゅう使ってましたね。

$('a[href^="#"]').click(function(){
	var speed = 400;
	var href= $(this).attr("href");
	var target = $(href == "#" || href == "" ? 'html' : href);
	var position = target.offset().top;

	$("html, body").animate({scrollTop:position}, speed, "swing");
	return false;
});

ページ読み込み時に、ページの一番上からアンカーリンク先の要素までの距離を、.offset().topで取得。
そしてメニューなどをクリックしたら、取得した値の分だけスクロールするイベントが発生します。

ただ、そのリンク先に飛ぶまでに配置されているimgタグに遅延読み込みが設定されていると・・・
imgの高さ分の値が取得されず、要素までの距離がおかしくなってしまうんですね。

そこで、.when()と.done()で二段階に分けてページ内遷移をしています。

①遅延読み込みされる画像はひとまず無視して、リンク先の要素の位置を.offset().topで取得(Xの値)

②スムーススクロール中、画像が次々と遅延読み込みされ、ずれた所で停止

③もう一回、リンク先の要素の位置を.offset().topで取得(Yの値)
※スクロールしてimgが読み込まれた後なので、正しい要素の位置が取得できる

④XとYの値が違うならYの位置にスクロールする

⑤正しい位置へ移動

という感じです。

さらに、固定ヘッダーの高さ分ずらしたい場合

position:fixedでヘッダーをページ上部に固定している場合は、ヘッダーの高さ分ずらしてあげましょう。

$(function () {
	var headerHight = $("header").height();

	$('a[href^="#"]').click(function(e) {
		var href = $(this).attr("href");
		var target = $(href == "#" || href == "" ? 'html' : href);
		var position = target.offset().top - headerHight;

		$.when(
			$("html, body").animate({
				scrollTop: position
			}, 400, "swing"),
			e.preventDefault(),
		).done(function() {
 			var diff = target.offset().top - headerHight;
 			if (diff === position) {
			} else {
				$("html, body").animate({
				scrollTop: diff
				}, 10, "swing");
			}
		});
	});
});
よかったらシェアしてね!
目次
閉じる