ゆとり日記

心にゆとりを持って生きたいプログラマーの雑記です。気が向いたら書きます。

遅延読み込みの落とし穴を色々踏んだ話

フロントエンドカンファレンス福岡のCFPに残念ながら漏れてしまったので、発表しようと思っていた話を簡単にブログに纏めました。

と思っていたら前夜祭で話せることになったので、ここに書いた話をベースに話す予定です。

fec-fukuoka.connpass.com

概要

  • 「ユーザの体感速度を上げるために遅延読み込みを実装したが、実はユーザー体験を損なっていた。」
  • 「一見早くなったように見えて安心していたら、SEOにネガティブな要因を引き起こしていた。」

試行錯誤して実装した遅延読み込みが実はクローラーやユーザに優しくなかった。簡潔に言うとそんな話です。

今回は僕が実際にやってしまった体験談を踏まえつつ、反省点や対策を述べていきたいと思います。

前置き

自分が普段開発しているサービスがSingle Page Application(SPA)ではないので、SPAに関わる話はほとんど出てきません。また、クローラーに関する話には不確実な部分があります。100%失敗するパターンから50%失敗するパターンまで持ってこれた、くらいの話だと思って読んでください。

なお、遅延読み込みの実装にはIntersection Observerを用いており、ここでいう遅延読み込みでは画像だけに留まらず、他の要素を動的に生成しています。

遅延読み込みがユーザ体験を悪くするケース

よかれと思ってやったことがユーザ体験にネガティブな影響を与えることがあるという話です。

実際に実装が反映されていたページの一例がこちらです。初期表示時のカードUIパーツの表示数を少なくし、初期表示を少しでも早めるのが目的でした。

1ページに表示されるパーツ数は20個ですが、ブラウザのファーストビューに収まるのはPCでも2個だったので、初期表示には2個だけ表示する。減らした分(残りの18個)をページ表示後にAPIから取得し、JavaScriptでHTMLを生成して差し込む。このようなフローを踏んでいました。

という流れを踏んでいました。

やらかしたこと

ページ内要素を遅延読み込みしたことで、ブラウザバックで戻ってきた時にページの表示位置がズレるというケースです。

  • 上で例に挙げたページから、次のページに遷移する。
  • 遷移先からブラウザバックで戻る。
  • 戻った先のページで要素の遅延読み込みが始まる。
  • 読みこみが終わると、ページの構造が変化するのでスクロール位置がズレてしまう。

こういった事が起きていました。

このケースへの対策案

対策としては2つ考えられました。

1つめはブラウザバック時は遅延読み込みをしないこと。以前SPAを開発していた時はこのアプローチで対策を打ちましたが、今回はあSPAではないので同じ対策が使えず、別の対策を考えることにしました。

そこで考えた2つめは遅延読み込みを行う箇所にダミーのカードUIを配置しておき、スクロール位置のズレを防ぐというものです。

  • ダミーのカードUIを予め配置しておく。
  • 遅延読み込みが完了したら、ダミー要素の後ろに本来表示したい要素を差し込む。
  • ダミーUIを消す。

という流れです。このアプローチは概ね上手くいったのですが、この対策も完璧ではありませんでした。APIのレスポンスを見るまでは表示できる要素の個数が分からないので、予め配置しておくダミー要素の個数を必要に応じて変えることが出来ないのです。

また、DOMの構造を変えるタイミングが増えるので、ブラウザのリフローを誘発してしまう側面もあります。

SEOにネガティブな要因を引き起こすケース

遅延読み込みしたHTML要素がクローラーに認識されてなかった、という話です。体験談を交えつつ説明していきたいと思います。

やらかしたこと

遅延読み込みに時間がかかりすぎると、要素の表示が完了する前にクローラーが帰ってしまい、ページが正常にインデックスされない場合があります。ある程度の時間は待ってくれるようですが、待ってくれる時間がどの程度なのかは明言されていません。そのため、実際にやってみないと上手くいくかどうかは判断出来ないのです。

今回、僕がプロダクトで試した際も上手くいっているページといっていないページが存在していました。

ちなみに、実装した処理が正しく機能するかどうかは事前にpupperterでテストが可能です。 参照リンク: https://developers.google.com/search/docs/guides/lazy-loading

これが理由で遅延読み込みはひとまず止める方針に倒しました。

反省と振り返り

今回はプロダクト全体に実装してしまったのですが、今思うとチャレンジし過ぎだったなと思っています。テスト実装を試すページを絞っておけば、悪影響を最小限に留めておけました。

一部のページに絞って実装を試していたので、影響を大きくすることを抑えられたのは不幸中の幸いでした。元に戻すことを想定して戻しやすい実装にしていたことも手伝って、止める時に素早く戻せたのも良かったです。

まとめ

ページの一部分を遅延読み込みするというだけの話ではありますが、考慮しなければいけないことが案外多いことがわかりました。良かれと思ってやった事が良い結果に結びつくとは限らないという教訓ですね。今後も素早く実装して素早く検証するサイクルを繰り返し、問題解決につなげたいと思います。

僕と同じ轍を踏む人が出ないことを祈ります。