ReactでYouTube埋め込むとLighthouseスコア低下する問題の改善手法まとめ
YouTube埋め込みって、するだけでLighthouseスコアが低下して悲しい気持ちになりますよね。なので研究としてLighthouseスコアを低下させない対策を調べたり試しました。最終的に、特定のケースでのみ低下不可避という結論に至りました。
結論
YouTube埋め込みがファーストビューにあり、スマホ対応も必須な場合、Lighthouseスコアの低下は避けられない
※もし回避する方法を見つけている方がいれば教えてください
検証結果
以下のサイトとGitHub Repoに公開済みです。サイト内、コード内に説明は特に無いので本記事の内容と合わせて見ていただければと思います。
前提知識
- YouTubeをiframeで埋め込んだだけで、Lighthouseのスコアは大幅に低下する
- Playerに関するJavaScriptがダウンロードされ、LCPに影響するため
- しかもファイル数も多く、1ファイルあたりのサイズも500KBを超えているものもあり大きい
- Playerに関するJavaScriptがダウンロードされ、LCPに影響するため
- 以下の例では、まっさらなNext.js v13製アプリケーションに単一のYouTube動画を埋め込んだだけで、スコアが62点になりました。
有力な対応策
一般に、YouTube埋め込みによるLighthouseスコア低下を防ぐには、大きく分けて、以下の2つの方針が対策として挙げられます。
- ビューポートに入った時点でiframeを生成することで、LCPを改善する
- 動画のサムネ画像を最初に表示し、onClickでautoplayなiframeに差し替えることで、ユーザー体験としてはほぼ埋め込み動画の再生と同じ感覚で動画を閲覧する
ビューポートに入った時点でiframeを生成することで、LCPを改善する
結論
Lighthouseスコアを維持できる
前提
- 動画がファーストビューに含まれていない状況を前提とします
- 本記事の検証では、動画の位置をファーストビューに入れず、1スクロール分だけ下にします
方法
-
react-lazyload-youtube
やreact-player/lazy
といったライブラリを使うことで、iframeを遅延読み込みします- Intersection Observerを使うことで、ビューポートに入ったことをトリガーにiframe要素を表示します
- iframe要素の生成によって大量のJavaScriptのダウンロードがトリガーされるため、遅延読み込みは有効な対策です
- Intersection Observer自体はこの手のユースケースで使われる常套手段です
- https://developer.mozilla.org/ja/docs/Web/API/Intersection_Observer_API
- Intersection Observerを使うことで、ビューポートに入ったことをトリガーにiframe要素を表示します
欠点
ただし致命的な欠点として、あくまでビューポートに入ったをトリガーにするため、ファーストビューに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スコアが改善します
動作事例・ロジック
-
react-lite-youtube-embed
というライブラリがデフォルトでこの挙動をサポートしています - とはいえ動作原理はいたってシンプルです
Performance
ほぼ100点です
- ちなみにreact-playerというYouTubeに限定しないライブラリでも同様の挙動をサポートしていますが、こちらはautoplayも自分で設定しないといけない
欠点
ただし致命的な欠点として、「 スマホ端末では(音声ありの)autoplayが禁止されているため、ユーザーにサムネ画像のタップと動画再生のためのタップの2回要求します 」。これはUXを大幅に低下させるので、多くのサービスでは採用できないでしょう。
これは実際にこのURLをスマホ端末で開いてみるとわかります。
ちゃんとIssueもライブラリ側に起票されているのですが、これはライブラリ側の問題ではないです(後述)。
補足
補足1
細かい補足ですが、禁止されているのは音声ありautoplayだけなので、要件的にmute再生でいいならLighthouseスコアを低減しつつ要件を満たす方法として本方法がありえます
補足2
以上から、User-Agentを見て、SafariやAndroid Chromeでの表示では通常のYouTube埋め込みをして、クローラーやPC、LighthouseのBotに対してはreact-lite-youtube-embedを使うという裏技自体は存在しますが、あまりやるべきではないかと思います。どうしてもスコア改善を求められている場合はやっても良いかもしれませんが、中長期的に見てUser-Agentの変更に弱い、正しいユーザー体験の計測にならないなど、良いことがないでしょう。
スマートフォン端末で動画の音声ありautoplayが禁止されている
以下のドキュメントにて明記されています。
YouTube Player API
YouTube Player API
という、iframeを埋め込むのではなく最初から最後までJavaScriptで制御する方法があります。これを使えば、autoplayが禁止されている現状の抜け穴を見つけられるのではと、いろいろ模索しました。
- https://react-youtube-embed-lighthouse-test.vercel.app/player-api
- https://react-youtube-embed-lighthouse-test.vercel.app/player-api-mute
- https://react-youtube-embed-lighthouse-test.vercel.app/player-api-mute-unmute
Source
- https://github.com/TeXmeijin/react-youtube-embed-lighthouse-test/blob/main/src/app/player-api/page.tsx
- https://github.com/TeXmeijin/react-youtube-embed-lighthouse-test/blob/main/src/app/player-api-mute/page.tsx
- https://github.com/TeXmeijin/react-youtube-embed-lighthouse-test/blob/main/src/app/player-api-mute-unmute/page.tsx
最終的には、react-lite-youtube-embedと同様、何らかの要素のクリックをトリガーにiframeを読み込み、それと同時に動画が音声ありで再生されたらいいので、代用としてボタンを画面に置いています。
結論
前述のドキュメントにも記載されている通り、YouTube Player API
のplayVideo()
関数も動作を制限されているので、無理でした。なお、mute状態では再生できました(なので、ドキュメントの記載は厳密には合っていないです)。
また、一応ダメ元で、プログラム上でmuteしたあとにplayVideo()を実行し、数秒後にunMute()を実行する案をやってみましたが、あろうことか、unMute()を実行した瞬間に再生が止まりました(3つ目のURL参照)。
まとめ
以上から、冒頭に記載の通り、「YouTube埋め込みがファーストビューにあり、スマホ対応も必須な場合、Lighthouseスコアの低下は避けられない」という結論となります。
参考文献
- https://vumbnail.com/examples/srcdoc-iframe-for-lighthouse
- https://robertmarshall.dev/blog/on-click-lazy-load-video-iframe-in-react/
- https://react-lazy-youtube.vercel.app/
- https://www.c-sharpcorner.com/article/improve-page-speed-with-lazy-loading-for-youtube-embeds/
- https://www.4696.co.jp/blog/022
- https://iwb.jp/javascript-iframe-youtube-player-autoplay-howto/
- https://stackoverflow.com/questions/48601937/safari-mobile-youtube-iframe-api-autoplay
最後まで読んでいただきありがとうございました!記事が参考になったらバッジお願いします!
オンライン家庭教師マナリンクを運営するスタートアップNoSchoolのテックブログです。 manalink.jp/ 創業以来年次200%前後で売上成長しつつ、技術面・組織面での課題に日々向き合っています。 カジュアル面談はこちら! forms.gle/fGAk3vDqKv4Dg2MN7
Discussion