🌟

ReactでYouTube埋め込むとLighthouseスコア低下する問題の改善手法まとめ

2023/08/28に公開

YouTube埋め込みって、するだけでLighthouseスコアが低下して悲しい気持ちになりますよね。なので研究としてLighthouseスコアを低下させない対策を調べたり試しました。最終的に、特定のケースでのみ低下不可避という結論に至りました。

結論

YouTube埋め込みがファーストビューにあり、スマホ対応も必須な場合、Lighthouseスコアの低下は避けられない

※もし回避する方法を見つけている方がいれば教えてください

検証結果

以下のサイトとGitHub Repoに公開済みです。サイト内、コード内に説明は特に無いので本記事の内容と合わせて見ていただければと思います。

https://react-youtube-embed-lighthouse-test.vercel.app/

https://github.com/TeXmeijin/react-youtube-embed-lighthouse-test

前提知識

  • YouTubeをiframeで埋め込んだだけで、Lighthouseのスコアは大幅に低下する
    • Playerに関するJavaScriptがダウンロードされ、LCPに影響するため
      • しかもファイル数も多く、1ファイルあたりのサイズも500KBを超えているものもあり大きい
  • 以下の例では、まっさらなNext.js v13製アプリケーションに単一のYouTube動画を埋め込んだだけで、スコアが62点になりました。

https://react-youtube-embed-lighthouse-test.vercel.app/normal-youtube

参考: https://pagespeed.web.dev/analysis/https-react-youtube-embed-lighthouse-test-vercel-app-normal-youtube/ks1yxnkcla?form_factor=mobile

screenshot

有力な対応策

一般に、YouTube埋め込みによるLighthouseスコア低下を防ぐには、大きく分けて、以下の2つの方針が対策として挙げられます。

  • ビューポートに入った時点でiframeを生成することで、LCPを改善する
  • 動画のサムネ画像を最初に表示し、onClickでautoplayなiframeに差し替えることで、ユーザー体験としてはほぼ埋め込み動画の再生と同じ感覚で動画を閲覧する

ビューポートに入った時点でiframeを生成することで、LCPを改善する

結論
Lighthouseスコアを維持できる

前提

  • 動画がファーストビューに含まれていない状況を前提とします
  • 本記事の検証では、動画の位置をファーストビューに入れず、1スクロール分だけ下にします

方法

  • react-lazyload-youtubereact-player/lazyといったライブラリを使うことで、iframeを遅延読み込みします
    • Intersection Observerを使うことで、ビューポートに入ったことをトリガーにiframe要素を表示します

https://react-youtube-embed-lighthouse-test.vercel.app/react-lazyload-youtube
https://react-youtube-embed-lighthouse-test.vercel.app/react-player-lazy

https://pagespeed.web.dev/analysis/https-react-youtube-embed-lighthouse-test-vercel-app-react-lazyload-youtube/im5u52z1t5?form_factor=mobile

欠点
ただし致命的な欠点として、あくまでビューポートに入ったをトリガーにするため、ファーストビューにYouTube動画を埋め込む要件がある場合有効な対策ではありません。即時にiframe要素が読み込まれるため、結局Lighthouseスコアは低下したままです。

動画のサムネ画像を最初に表示し、onClickでautoplayなiframeに差し替える

結論
任意の端末でLighthouseスコアを低減できるが、PCブラウザでのみ自然に動作する。スマホではユーザーに2回タップを要求する

前提知識

  • YouTubeの再生にはautoplayという属性(オプション)があり、これをTrueにしておくことで、iframe表示と同時に動画の再生を始めます
  • YouTubeのサムネ画像は、https://i.ytimg.comというサイトにVideo IDを渡すことで得られます
  • これを応用(というか悪用)して、「最初はYouTubeのサムネ画像を表示し、その画像のonClick時にiframeかつautoplayに表示を切り替える」という手段があります
    • LCP測定時点ではサムネ画像しか表示されていないのでLighthouseスコアが改善します

動作事例・ロジック
https://react-youtube-embed-lighthouse-test.vercel.app/react-lite-youtube-embed

Performance
ほぼ100点です
https://pagespeed.web.dev/analysis/https-react-youtube-embed-lighthouse-test-vercel-app-react-lite-youtube-embed/y88y1rrzwi?form_factor=mobile

欠点
ただし致命的な欠点として、「 スマホ端末では(音声ありの)autoplayが禁止されているため、ユーザーにサムネ画像のタップと動画再生のためのタップの2回要求します 」。これはUXを大幅に低下させるので、多くのサービスでは採用できないでしょう。
これは実際にこのURLをスマホ端末で開いてみるとわかります。

ちゃんとIssueもライブラリ側に起票されているのですが、これはライブラリ側の問題ではないです(後述)。
https://github.com/ibrahimcesar/react-lite-youtube-embed/issues/50

補足

補足1
細かい補足ですが、禁止されているのは音声ありautoplayだけなので、要件的にmute再生でいいならLighthouseスコアを低減しつつ要件を満たす方法として本方法がありえます

補足2
以上から、User-Agentを見て、SafariやAndroid Chromeでの表示では通常のYouTube埋め込みをして、クローラーやPC、LighthouseのBotに対してはreact-lite-youtube-embedを使うという裏技自体は存在しますが、あまりやるべきではないかと思います。どうしてもスコア改善を求められている場合はやっても良いかもしれませんが、中長期的に見てUser-Agentの変更に弱い、正しいユーザー体験の計測にならないなど、良いことがないでしょう。

スマートフォン端末で動画の音声ありautoplayが禁止されている

以下のドキュメントにて明記されています。
https://developers.google.com/youtube/iframe_api_reference?hl=ja#Mobile_considerations

YouTube Player API

YouTube Player APIという、iframeを埋め込むのではなく最初から最後までJavaScriptで制御する方法があります。これを使えば、autoplayが禁止されている現状の抜け穴を見つけられるのではと、いろいろ模索しました。

Source

最終的には、react-lite-youtube-embedと同様、何らかの要素のクリックをトリガーにiframeを読み込み、それと同時に動画が音声ありで再生されたらいいので、代用としてボタンを画面に置いています。

結論
前述のドキュメントにも記載されている通り、YouTube Player APIplayVideo()関数も動作を制限されているので、無理でした。なお、mute状態では再生できました(なので、ドキュメントの記載は厳密には合っていないです)。

また、一応ダメ元で、プログラム上でmuteしたあとにplayVideo()を実行し、数秒後にunMute()を実行する案をやってみましたが、あろうことか、unMute()を実行した瞬間に再生が止まりました(3つ目のURL参照)。


まとめ

以上から、冒頭に記載の通り、「YouTube埋め込みがファーストビューにあり、スマホ対応も必須な場合、Lighthouseスコアの低下は避けられない」という結論となります。

参考文献


最後まで読んでいただきありがとうございました!記事が参考になったらプロテイン代(という名のバッジ)を恵んでください!

マナリンク Tech Blog

Discussion