Chromeが画像の遅延読み込み(lazy-loading)をネイティブでサポートしました。
実装も実にシンプルで、
<img src="hello.png" loading="lazy" />
と、loading属性を追加するだけで、簡単に遅延読み込みに対応できます。
「めっちゃ簡単やん、よし全部の画像タグに loading="lazy"
つけたろ」と思って、imgタグにひたすらlazyつけたら、一部画像が表示されなくなってハマったので、ここに記録を残しておきます。
loading="lazy"をつけると画像が表示されなくなった
lazy-loadingしたことで、画像が正しく表示されない例を以下ページに置きました。
画像があることをわかりやすくするために、画像のまわりに赤い枠線を配置してます。
以下のように、ただひたすらにネコ画像を並べたサイトです。パット見うまく表示されているように見えますが...
スクロールしてみると、おやおや...
画像がでてませんね.
なぜ画像がでないのか
なぜ画像がでてこないのか。これはCSSの書き方に問題がありました。
以下のようなcssで画像を表示してます。
<style>
.wrapper {
width: 500px;
margin-left: auto;
margin-right: auto;
min-height: 1000px
display: flex;
flex-wrap: wrap;
}
.element {
margin: 20px;
overflow: hidden;
border: 2px solid red;
}
.element img {
width: 100%;
height: auto;
}
</style>
<div class="wrapper">
<div class="element"><img src="../img/0.png" loading="lazy"></div>
<div class="element"><img src="../img/1.png" loading="lazy"></div>
ひたすら同じエレメントが続く...
</div>
問題は element にある overflow: hidden
と imgの height: auto
にあります。
遅延読み込みの画像は、最初は読み込まれていないので高さ0pxのままとなって表示され、
そのまま画像ダウンロードが完了しても0pxのままレンダリングされてしまうのです。
よって、画像はダウンロードされてはいるが、高さ0pxで表示が隠れてしまう 状態になっていました。
どうすればよいか
対応案1. 幅高さをちゃんと指定する
https://web.dev/native-lazy-loading に記載されている注意書きをちゃんと読んでませんでした。
幅高さ(width/height)を上記のように指定していないと、遅延読み込みのタイミングで画面がガタガタ揺れてしまいます。
また、今回のようにoverflow: hidden; で消されてしまう可能性もあるのと、幅高さを指定しないとパフォーマンスにも影響があるようなので、width/height をちゃんと指定しましょう。
とはいったものの、レスポンシブなサイトで画像の大きさを固定にするのは厳しくない? というのもありますよね。
対応案2. overflow: hidden を消す
画像の親にある overflow: hidden;
がそもそも悪さをしているので、こいつを消せば解決です。
でもデザインの関係で消せないかも?
対応案3. min-height: 30px とか指定しちゃう
これはちょっと危ないコードな気がしますが、とりあえず画像が一部表示されるスペースが有れば、画像遅延読み込み完了時にheight: auto
がちゃんと効いてくれます。
CSSで書くと、以下のようになります。
.element img {
width: 100%;
height: auto;
min-height: 30px; // 30px でなくても良い
}
この実装は以下のようになります。
しかし高さの指定がちゃんと無いので、スクロールがガタガタ揺れますよね... あまり良くない実装です。
まとめ
単純にimgタグにlazyってつければ良いというわけではなく、CSS・デザインへの影響もちゃんと考えてlazy属性をつけましょう。というお話でした。