スマホで画像表示が止まる原因は?Astroの画像最適化で改善した方法

PCでは問題なく読めたページが、スマホでは画像付近で止まったように見えた経験から、重い画像がモバイル表示へ与える影響を確認します。ゆまラボでAstroの画像最適化、srcset、WebP、遅延読み込みを適用した実測も振り返ります。

公開:更新:
スマホで画像表示が止まる原因は?Astroの画像最適化で改善した方法

PCでは普通に読めるのにスマホでは、 「画像のところで止まったように見える」 「スクロールしても先へ進みにくい」 「画面上は小さい画像なのに、なぜ重いのか分からない」 と困っていないでしょうか。表示サイズが小さくても、元の大きなPNGをそのまま転送していれば通信量は減りません。

ゆまラボでも実際にスマホで画像付近から進みにくくなる状態を経験しました。当時はNetworkログを保存していないため、画像の重さだけを原因とは断定できません。ただ、本文画像はpublic/images/の大きなPNGで、確認したimgにはsrcset、sizes、loading、width、heightがありませんでした。その後Astroの画像最適化を適用し、スマホ表示は軽くなっています。

この記事では、確認できた事実と推測を分けたうえで、なぜモバイルでは重い画像の影響が出やすいのか、ゆまラボで何を変えたのかを整理します。

その後、Astroで画像を最適化する方法|WebP・srcset・遅延読み込みを実装で本文画像の配信方法を変更した。

画面で小さく表示しても転送する画像は小さくならない#

修正前のゆまラボでは、本文画像を次のような通常のimgとして出していた。

<img
  src="/images/blog/.../screenshot.png"
  alt="..."
>

画像はCSSで本文幅に収まる。

PCでもスマホでも、見た目だけならレスポンシブに表示できる。

ただし、表示幅をCSSで小さくすることと、ブラウザが取得するファイルを小さくすることは別になる。

例えば元画像が1,500px幅でも、スマホ画面では300px台で表示できる。

その状態で候補画像が1つしかなければ、ブラウザは大きな元画像を取得してから画面幅へ縮小表示することになる。

MDNのResponsive Imagesでも、狭い画面でデスクトップ向けの大きな画像をそのまま取得すると帯域を無駄にしやすく、srcsetとsizesによって端末に合う候補をブラウザへ選ばせる方法が案内されている。

修正前の実画面をDevToolsで確認すると、本文画像は通常の画像URLを直接参照する形。

画像最適化前の記事本文とDevToolsでimg要素を確認した実画面

スマホだから画像ファイルが自動的に軽くなるわけではない。

ここは表示サイズだけを見ていると気付きにくい。

スマホでは画像の待ち時間が目立ちやすい#

重い画像があるからページのHTML解析そのものが必ず止まる、という話ではない。

ブラウザはHTMLを読みながら画像の取得も進める。

ただ、本文に大きな画像が何枚もあり、必要以上に大きなファイルを転送していれば、モバイル回線では画像が表示されるまでの待ち時間が長くなりやすい。

PCで高速な回線につないでいると問題に見えなくても、スマホでは条件が変わる。

MDNも、モバイル端末は大きな画像を必要としないケースがあり、回線速度や通信量の面でも大きな画像をそのまま取得するのは無駄になり得るとしている。

もう一つ、修正前の本文画像にはwidthとheightもなかった。

画像の寸法をHTMLで先に示しておけば、ブラウザは画像取得前から表示領域を確保できる。

寸法がなければ、画像を読み込んだ後に周辺要素の位置が変わることがある。ページが重い状態では、このような動きも「読み込みが終わらない」「途中で引っ掛かる」という感覚につながりやすい。

今回の実体験では、端末側のメモリ使用量やデコード時間までは測っていない。

そこまでを原因として書くことはしない。

確認できているのは、大きなPNGをそのまま配信していたことと、その配信方法を変更した後にスマホ表示が軽くなったこと。

ゆまラボでは本文画像をAstroの画像処理へ移した#

対策では、本文画像をpublic/images/からそのまま返す方式をやめた。

現在は画像をsrc/assets配下へ置き、Markdownから相対パスで参照する。

src/
├─ content/
│  └─ blog/
│     └─ ...
└─ assets/
   └─ images/
      └─ blog/
         └─ ...

Astroの公式ドキュメントでは、可能な限りローカル画像をsrc/へ置くことが推奨されている。

src/内の画像はAstroが変換・最適化できる。

一方、public/内の画像はビルド時にそのままコピーされ、画像処理の対象にならない。

ゆまラボでは、本文画像用のrehype処理からAstroの画像処理へ渡すようにした。

生成された候補幅は代表ページで、

320w
480w
640w
720w

の4段階。

sizesは以下。

sizes="(min-width: 720px) 720px, 100vw"

ブラウザ側が表示条件に合わせてsrcsetから画像を選べる。

WebPも生成する。

ビルドでは大量の最適化画像が生成される状態に変わった。

Astroのビルドで本文用の最適化画像が生成されている実画面

さらに、画面下の本文画像にはloading="lazy"が付く。

loading="lazy"

修正時の確認では、下方の画像が最初から全部取得されず、スクロールするまで読み込みが保留されることも確認した。

ページを開いた直後に必要のない画像まで一斉に取りに行かない。

画像が多い技術記事では、この差も大きい。

代表ページの対象画像は122,901 bytesから26,698 bytesになった#

サイト全体では、実ファイル278件、本文内281参照を対象にした。

元画像の合計は、

44,399,561 bytes

Astroで生成した本文画像候補の合計は、

11,315,090 bytes

削減率は74.52%。

ただし、これは「サイトが74.52%速くなった」という意味ではない。

生成候補画像の容量比較であり、HTML、CSS、JavaScript、フォント、通信待ち時間などは含まない。

実際のページでは、カスタム404の記事を代表ページとして確認した。

修正前に対象としていた画像は合計、

122,901 bytes

Luna版を本番採用した後、PCで実際に選択された画像は合計、

26,698 bytes

78.28%減っている。

この数字もページ全体の速度改善率ではなく、対象画像の転送量。

それでも、同じ見た目の画像を出すために取得するバイト数が大きく減ったことは確認できる。

スマホ相当では、

390 × 844

で表示を確認した。

本文幅343pxに対して画像幅も343px。横スクロールは発生せず、縦横比やスクリーンショット内の文字も確認できた。

対策後、実際のスマホ表示も以前より早く感じられる状態になった。

ここは容量の計測値とは分けて、実使用時の体感として扱う。

画像を軽くするときは圧縮だけを見ない#

画像対策というと、PNGをWebPへ変換してファイルサイズを減らす話だけになりやすい。

今回のゆまラボでは、それだけではない。

大きなPNGをそのまま配信
↓
src/assetsへ配置
↓
Astroで複数幅のWebPを生成
↓
srcset / sizesで端末に合う候補を選択
↓
width / heightで表示領域を確保
↓
画面外の画像はlazy loading

という流れへ変更した。

スマホでは、必要以上に大きな画像を送らないことと、まだ見えていない画像を急いで取得しないことが効く。

今後ゆまラボへ追加する本文画像もsrc/assetsへ置く。

この単発記事の画像も、

src/assets/images/blog/web-development/design/mobile-heavy-images/

へ配置し、Markdownから相対パスで参照している。

public/images/へ戻すと、その画像だけ現在の本文画像用の処理から外れるため注意が必要になる。

PCで正常に見えているだけでは、画像配信が軽いかどうかまでは分からない。

スマホで表示が遅い場合は、画像の見た目だけでなく、Networkで実際に何bytes取得しているか、srcsetがあるか、画面外画像が最初から読み込まれていないかを見る。

今回のゆまラボでは、ここを変更した後に転送量が減り、スマホでも表示が軽くなった。

参考#