lazyloadを使ったときにページ内リンクの着地ずれを解消する方法

こんにちは!のせっち@nosecchi01です。

サイトスピードアップに欠かせないlazyloadですが、ページ内リンクとは相性が悪く、意図した場所に着地してくれなくなることがあります。

今回はそちらの解消方法を解説します。

なぜlazyloadを使うとページ内リンクがズレるのか?

理由は下記です。

  • lazyloadを使うと最初は画像が読み込まれない。
  • ページ内リンクボタンを押すと指定idの位置(ターゲット)までスクロールが始まる。
  • 画像読み込みが始まる。
  • ボタンを押したときと、ページスクロール後のターゲット位置が画像分異なるため位置ずれが起きる

要は、画像がある、ないでY座標が異なるため、その分が位置ずれとなってしまうのです。

解決策① width, heightを指定する

解決策としては、<img>タグに必ずwidthheightを指定することです。

heightを書いておくことで、画像本来の高さが確保されるので位置ずれを防ぐことができます。

解決策② padding-bottomで高さを出す。

widthheightを指定するのが正攻法だと思いますが、この方法では対応できないケースがあります。

特にvanilla-lazyloadなど、srcの代わりにdata-src属性を使うものでは、残念ながら、widthheightが効きません。

<!-- vanilla-lazyloadを使ったimgタグの記述例 -->
<div class="image-wrapper">
  <img class="lazy image" alt="An image" data-src="lazy.jpg" />
</div>

srcの代わりにdata-srcを使っているのがわかります。

data-src属性を使うケースではheightの代わりにpadding-bottomで高さを確保します。

<div class="image-wrapper">
  <img class="lazy image" alt="An image" data-src="lazy.jpg" />
</div>

HTMLは変わりません。imgタグをdivタグなどで囲っておく必要があります。(cssの取り回しやすさの観点から常に何かしらのタグで囲っている人は多いかと思います。)

.image-wrapper {
  width: 100%;
  height: 0;
  padding-bottom: 150%;
  /* 👆 image height / width * 100% */
  position: relative;
}
.image {
  width: 100%;
  height: auto;
  position: absolute;
}

続いてcssです。

.image-wrapperの方でheight: 0とした上で、画像の比率をpadding-bottomで計算しています。

150%の部分は各画像の比率を計算して置き換えてください。

このやり方は、vanilla-lazyload公式のgithubに記載があります。

.imageの方ですが、reset.cssの方でキチンとresetしていればこの記述は不要です。

下記のような感じ

// reset.css
img {
  height: auto;
  max-width: 100%;
  vertical-align: bottom; // baseline以外を指定
}

// style.css
.image-wrapper {
  width: 100%;
  height: 0;
  padding-bottom: 150%;
  /* 👆 image height / width * 100% */
}

.imageの記述はなくなりました。

これで、data-srcを使ったとしても、高さを確保することができます。

画像ごとに全て書かないといけないのか…。

残念ながらそうです。各画像ごとに画像比率は違うでしょうから、共通化できる部分はありつつも、padding-bottomは各画像ごとに指定が必要です。

ただ、色々試した結果、こちらの方法が一番確実だったので是非試してみてください!

この記事を書いた人

のせっち

福岡県出身。早稲田大学卒。創業100年の鉄鋼商社でバンコク駐在最年少抜擢。毎日擦り切れるまで働かなくても幸せに生きている人々を見てフリーランスになりました。
現在は、主にバンコクでWeb制作、物販を中心に生きています。