記事の目次によく使われるアンカーリンク(ページ内リンク)の移動先がずれる時の原因と対処方法です。
アンカーリンクがズレる原因は画像の遅延読み込み(Lazy Load)によるものですが、スムーススクロールとも相性が悪く、場合によっては画像遅延プラグインの仕様が原因となることもあります。
当サイトでも長らくこのズレに困らされていたのですが、つい先日ひょんなことで解決しましたのでまとめます!
環境はWordpressで「Easy Table of Contents」にて目次を生成しています。
この記事の目次
アンカーリンクがずれる原因と対処法
Wordpressではプラグインの「Easy Table of Contents」を使えば見出し(Hタグ)にジャンプやスクロールで移動できて便利ですが、移動先がズレるとその魅力も半減してしまいますよね…
当サイトではパソコンは問題なく、モバイル(iPhone)でズレが発生していました。
具体的な症状は以下のような感じです。
固定ヘッダー分ずれるという話ではなく、ジャンプ先がずれる時の話です。
プラグインの「Easy Table of Contents」で自動出力している目次(アンカーリンク)を押し、ジャンプしても見出しにピッタリと着地しないのです。
実際の動作をGIF化してみました。
盛大にズレていますね…
更にスクロール時にもガタつきが発生しています。
- 着地してほしい位置
- 実際に着地する位置
本来着地してほしい所は画面上部に見出しが来る位置です。
が、見出しを通り過ぎてしまって大幅にずれた位置に着地してしまいます。
スクロールしてもらえれば記事の閲覧には影響は出ないのですが、気持ちの良いものではありませんし、ユーザービリティ向上のための目次の魅力が無くなります…
ではなぜこんなにもズレてしまうのか?
ずれる直接の原因は画像の遅延読み込み
目次などのアンカーリンクがズレてしまう原因は画像の遅延読み込みにあります。
当記事をご覧の方は画像の遅延読み込みについてはご存だと思いますが、パソコンやスマホの画面(Viewport)外にある画像はページが開いた瞬間には読み込まず、画面が触れた(近づいた)タイミングでその都度画像を読み込むというものです。
Webサイトを高速化するにあたって有名で効果抜群の方法ですが、アンカーリンクとの相性は最悪です。
Webサイトが開いた瞬間、画面(Viewport)外にある画像は読み込みされておらず、画像分の高さが分からないのが相性が悪い理由です。
以下のような流れでアンカーリンクがずれてしまいます。
- ページ上部でアンカーリンクがクリックされる。
- ジャンプ先周辺の画像が読み込まれていない時のY座標が着地点。
- ジャンプ中に遅延読み込みで画像が次々と読み込まれ、Y座標がズレる。
- 見出しから読み込まれた画像分ズレた位置が表示される。
画像の遅延読み込みを無効化すれば、ページが読み込まれたと同時に全画像も読み込まれるのでズレは発生しません。
モバイルだけ顕著にズレが発生するのはおそらく回線速度が原因だと思われます。
なお、ブラウザや端末(Android)によってはズレが発生しないこともあるようです。
アンカーリンクがずれる時の対処法
原因が分かったところで、具体的な対処方法を見ていきましょう・w・
画像の遅延読み込みを無効化してしまえばズレは解消できますが、これでは根本的な解決にはなりません。ページの読み込み速度が低下し、SEO的にも良くありません。
PageSpeed Insightsのスコアもガタ落ちします。
そこで画像の遅延読み込みを有効にしたまま、アンカーリンクのズレを解消するには以下の方法が有効です。
- 画像にwidthとheightを指定する。
- スムーススクロールを無効にする、または改良する。
- 遅延画像の読み込みタイミングを見直す。
上の2つはよく紹介されていますが、当サイトではこれで解決できませんでした。
原因不明で数カ月詰まっていたのですが、画像遅延プラグインを変更したことで解決できました。
これらの内容を詳しく解説していきます!
画像にwidthとheightを指定する
先述の通り、ずれが発生する原因は遅延画像の高さが確定していないことです。
そこで画像のimgタグ内にwidthとheightを明記しておくことで、遅延読み込みされる画像の高さがブラウザに伝わります。
画像ごとに横幅と高さを指定しておくことでブラウザは予め画像表示分の領域を確保してレンダリング(画面描画)してくれるのです。
(確保される領域はCSSのmax-heightなどが無いと結構大まかになる様子。)
これは画像読み込み時のガタつき防止にも効果を発揮します。
必須の作業ではありますが、Wordpressの場合はそれぞれの画像に対して自動的にwidthとheightを付与してくれます!
上の画像はクラシックエディターで挿入した時のものですが、ブロックエディターで画像を挿入してみてもwidthとheightは付与されていました。
(Wordpress5.9にて検証済み)
ということでWordpressを使っている方はここはパスできます。
なお、広告画像については挿入にJavaScriptを使っているので影響は無さそうです。
ポイント
広告で表示される画像について検証したのですが、少なくともGoogle Adsenseで表示される広告画像はズレとは関係ないようです。
スムーススクロールを無効にする
画像を遅延読み込みしている場合、スムーススクロールも相性が悪いです。
アンカーリンクをクリックした際にジャンプする挙動を画面のスクロールに変更したものがスムーススクロールという動作です。
このスクロール処理が厄介らしく、ずれの原因となるようです。
定番の目次作成プラグインである「Easy Table of Contents」では設定画面から簡単にスムーススクロールを無効化できますので、試してみて下さい。
どうしてもスムーススクロールを利用しつつ、アンカーリンクのズレも解消したい時はJavaScript(jQuery)を使ってズレた分を修正する処理などが必要です。
ここではややこしくなるので、詳しい内容は後述します。
画像遅延プラグインを変更してみる
遅延読み込みする画像にwidthとheightを明記しており、スムーススクロールも使っていないのに当サイトではズレが発生していました。
調べても調べても原因が分からず、数カ月放置していたのですが画像遅延プラグインを「a3 Lazy Load」というものに変更することで解決できました。
何が原因だったのかというと、遅延画像を読み込むタイミングでした。
今まで「Smush」という画像圧縮プラグインに同梱されている機能を使って、画像を遅延読み込み(Lazy Load)を使用していたのですが、これが原因でした。
プラグイン自体の機能がダメという訳ではありません。
画像が画面に表示されるよりも少し早く読み込む設定が問題でした。
「a3 Lazy Load」ではプラグインの設定画面から「Image Load Threshold」というものが変更できます。これを0にするとズレが解決できました。
Image Load Thresholdの設定値が原因
この「Image Load Threshold」の設定はどのような設定かというと、画像を読み込むタイミングを早めることができる設定です。
「Threshold」は日本語で閾値という意味があります。
ポイント
a3 Lazy Loadでは「Image Load Threshold」という名前ですが、プラグインによっては別の名前で呼ばれることもあります。
文章では説明しにくいのでイメージ画像を作ってみました・w・
Thresholdの設定値が0の時は、パソコンやスマホの画面(Viewport)が画像に触れた瞬間に画像の読み込みが開始されます。
このThresholdにピクセル(px)数を指定すると、画面(Viewport)の上下が設定したピクセル分だけ"拡大"されたように扱われます。
この機能によって、実際の画面が画像に差し掛かるよりも少し手前で(少し早めに)画像が読み込まれるので、より自然に画像の表示が出来るわけですね。
話がそれていそうですが、当サイトの場合はこの機能が原因でアンカーリンクにずれが発生していました。
「a3 Lazy Load」の場合は設定画面からThreshold(閾値)を変更できますが、多くの画像遅延プラグインは"初期設定"されているんですよ…
今まで使っていた「Smush」というプラグインのコードを眺めるとこのThresholdが500px(多分)に設定されていました。
これが0じゃないとダメなんですが、プラグインの設定画面から変更できないようなので「a3 Lazy Load」に変更したという流れです。
まさかの原因ですが、遅延画像を読み込むためにViewportを無理やり拡大して扱っているならアンカーリンクの高さがズレてもおかしくないですね。
スムーススクロールと遅延読み込みを両立する
ここからはスムーススクロールと遅延読み込みを併用したい場合の対処法です。
当サイトでは上記の内容で問題のズレが解決したわけですが、スムーススクロールを有効化するとズレます。
ブラウザ側の処理のような気もするので、詳しい原因は分からないのですが画像にwidthとheightを指定していてもスムーススクロールだとズレが発生するようです。
追記
どうやらスムーススクロール時の“スクロール移動”という動作の中で、遅延対象の画像が読み込まれ始めてしまい、着地時にはその画像分の高さがズレているというのが原因のようです。
また、画像にwidthとheightを指定していても、画像の高さ分ピッタリの領域が確保されるわけではない事が後日分かりました。
今回たまたま使っていたscroll-padding-top
というCSSプロパティでスクロールした後に見出しに戻るという動作は確認でき、簡単に解決できそうだと思ったのですが…
パソコンで確認すると盛大にズレていました。
ジャンプ先の距離の問題なのでCSSだけではどうも対処できなさそうですね。
関連記事
scroll-padding-topについてはこちら。
アンカーリンクのジャンプ先の余白をCSSで調整する。見出し(Hタグ)上部にもう少し余白が欲しい!
スムーススクロールのズレに対応する方法
画像を遅延読み込みさせつつ、ズレを発生させることなくスムーススクロールを使いたいなら以下の方法が有効です。
- 画像遅延読み込みをやめる。(非推奨)
- ページ読み込み完了後、スクロールさせる。
- 移動前と移動後のY座標を計算し、差分を修正する。
- 画像のアスペクト比を計算、保持して高さの算出に使う。
アンカーリンクの移動前に全ての画像を読み込ませるか、スクロール処理時にズレた分を修正するという処理が必要です。これはよく使われる方法です。
また後述のプラグインの仕様から考えると、画像のwidthとheightと更にアスペクト比も使うことで、読み込み前の画像の正確な高さが割り出せるようです。
どの方法でもJavascriptやjQueryを使わないと実現できないので、プログラミングが分からない方には難易度が少し高めの内容ですね…。
WordPressならLazy Loaderで対応可能!
多くの方にこの記事を読んでもらっているので、後日ノーコードで何とかズレに対応できないか調べました。
するとWordpressユーザーの方限定の内容ではあるのですが、スムーススクロールでもズレが発生しない画像遅延プラグインを見つけました!
プラグイン名は「Lazy Loader」というものです。
このプラグインには遅延対象の画像のアスペクト比を事前に計算して保持する機能があり、これを使えば画像の読み込み前後で画像の高さがズレません。
機能も人気のプラグインである「a3 Lazy Load」と同等かそれ以上のものです。
-
- スムーススクロールのズレに対応できる画像遅延プラグイン「Lazy Loader」が超優秀!【WordPress】
続きを見る
プラグインの使い方、スムーススクロール時のズレについては新たに別の記事(↑)に詳しく書きましたので是非お読み下さい!
Javascript(jQuery)でズレを修正する方法
最後にJavaScript(jQuery)を使って、スムーススクロールの前後で発生したズレ分を計算し、修正するコードについてです。
画像の遅延読み込みもスムーススクロールも良く使われるので、情報は豊富です。
外部リンク
- jQueryで差分を再計算している方のサイト
画像の遅延読込でページ内リンクがずれる時の解決法【jQuery】 | KAITEKI CHOKIN - Easy Table of Contentsを改造している方のサイト
Lazy Loadで目次のジャンプ先がずれてしまう場合の対処方法 | オランダで生きていく
当サイトでは色々な理由もあって、スクロールよりもジャンプという動作の方が気に入っており、実際に使っていないのですがコードについては上記のサイト様が参考になりそうです。
自作したJavaScript(jQuery)をWordpressに追加する方法は別の記事に書いておりますので、分からない方は関連記事(↓)も是非どうぞ・w・
-
- Wordpressで子テーマにJSを追加して読み込む方法!親テーマのJSをカスタム、継承したい場合もこれでOK!
続きを見る
まとめ
目次などのアンカーリンクがずれる原因と対処法をまとめました。
今や画像の遅延読み込みは当たり前となってきており、目次も人気があるので多くの人が悩まされる内容だと思います。
僕が知っている限りを書きましたが、サイト環境や閲覧端末、ブラウザによって動作が異なることがあるので厄介な内容です。
今回の件でまた1つプラグインが増えてしまいましたが仕方ないですね~
SmushのLazy Loadは個人的に好きだったのでプラグインの設定かフィルターフックでも良いのでThresholdの値を変更できるようになれば良いのですが…