Twitter と Instagram の遅延読み込みで WordPress を高速化
はじめに
WordPress に Twitter のツイートやタイムラインを埋め込んでいるサイトは多いと思います。また、Instagram の投稿を埋め込んでいるサイトも多く見かけます。
ただ、Twitter や Instagram の埋め込みがある場合は、PageSpeed Insights のスコアが低下します。実際のサイトの表示速度も遅くなると思います。
これを手間をかけずに改善するカスタマイズの紹介です。
検証
WordPress 公式テーマ Twenty Twenty-Two を使いカスタマイズの効果を検証します。計測は Lighthouse で行います。計測対象のデバイスはモバイルです。
まず、文字だけしかないページの計測結果です。おおよそ 85 点が出ます。
次に、文字に加えて、Twitter のツイートを 3 つ、Instagram の投稿を 3 つ追加した計測結果です。おおよそ 75 点とスコアが 10 点減りました。
Twitter のツイートが 3 つ、Instagram の投稿が 3 つがある状態のまま今回のカスタマイズを行った計測結果です。スコアが 85 点に回復しました。文字だけしかない時とほぼ同じスコアが出ると思います。
尚、検証結果は、あくまで目安です。どのサイトでも効果は出ると思いますが、サイトやページによってカスタマイズの効果は異なります。
対象
今回のカスタマイズの対象としている埋め込みは、以下のものです。
- ブロックで埋め込んだ Twitter の投稿とタイムライン
- Twitter Publish で生成した埋め込みコードをブロックかウィジェットの「カスタム HTML」に追加した Twitter の投稿とタイムライン
- 埋め込みコード をブロックかウィジェットの「カスタム HTML」に追加した Instagram の投稿
また、以下のテーマで動作を検証しました。
- 公式テーマ Twenty Twenty-Two
- 公式テーマ Twenty Twenty-One
- 公式テーマ Twenty Twenty
- 人気テーマ Cocoon
コード
カスタマイズはコピペするだけです。使用中のテーマの functions.php に以下のコードを追加します。
// get_headerではTwenty Twenty-Twoで遅かったためwpを使う
add_action( 'wp', function() {
ob_start( function( $html ) {
// カスタムHTMLでasyncがasync=""になるため空の値を削除し、ブロックのasyncと統一する
$html = str_replace(
'<script async="" src',
'<script async src',
$html
);
$twitter_script = '<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>';
$instagram_script = '<script async src="//www.instagram.com/embed.js"></script>';
$twitter_pos = strpos( $html, $twitter_script ) !== false ? true : false;
$instagram_pos = strpos( $html, $instagram_script ) !== false ? true : false;
$js = '';
if ( $twitter_pos || $instagram_pos ) {
$js .= "
const loadEmbed = (scriptId, scriptSrc, targets) => {
const observer = new IntersectionObserver(entries => {
for (const entry of entries) {
const embedJs = document.getElementById(scriptId);
if (entry.isIntersecting && !embedJs) {
const script = document.createElement('script');
script.id = scriptId;
script.src = scriptSrc;
document.body.appendChild(script);
observer.disconnect();
}
}
}, {
rootMargin: '1250px 0px',
});
for (const target of targets) {
observer.observe(target);
}
};
";
if ( $twitter_pos ) {
$html = str_replace( $twitter_script, '', $html );
$js .= "
const twitterSrc = 'https://platform.twitter.com/widgets.js';
const twitterTargets = document.querySelectorAll('.twitter-tweet, .twitter-timeline');
loadEmbed('twitter-load-embed-js', twitterSrc, twitterTargets);
";
}
if ( $instagram_pos ) {
$html = str_replace( $instagram_script, '', $html );
$js .= "
const instagramSrc = '//www.instagram.com/embed.js';
const instagramTargets = document.getElementsByClassName('instagram-media');
loadEmbed('instagram-load-embed-js', instagramSrc, instagramTargets);
";
}
$html = str_replace(
'</body>',
'<script type="module">' . $js . '</script></body>',
$html
);
}
return $html;
});
});
add_action( 'shutdown', function() {
if ( ob_get_length() > 0 ) {
ob_end_flush();
}
});
説明
今回のカスタマイズで行っているのは、Intersection Observer API を使った Twitter と Instagram の <script>
の遅延読み込みです。これは画像の遅延読み込みと同じです。
このようなことを行っています。
- ページの全ての HTML を取得する。
- その HTML の中に Twitter とInstagram の
<script>
があるかを調べる。 - Twitter とInstagram の
<script>
がある場合は、その<script>
を全て削除する。 - 代わりに、
</body>
の直前に JavaScript を追加する。
</body>
の直前に追加する JavaScript では、このようなことを行っています。
- Twitter と Instagram の埋め込みが ビューポート に入ってきた時に動き始める。
- ビューポートに入ってきたのが Twitter のツイートかタイムラインであれば、Twitter の
<script>
を<body>
の最後に追加する。 - ビューポートに入ってきたのが Instagram の投稿であれば、Instagram の
<script>
を<body>
の最後に追加する。
Twitter か Instagram の <script>
が <body>
の最後に追加された後は、カスタマイズ前と同じです。Twitter と Instagram の JavaScript が、埋め込み要素を <iframe>
に変換します。
調整
コードの中に以下の部分があります。これはビューポートを上下に 1250px
拡大する指定です。
rootMargin: '1250px 0px',
この指定により、埋め込みが画面内に入ってくる 1250px
手前で Twitter や Instagram の <script>
を追加します。
手前で <script>
を追加する理由は、Twitter や Instagram が表示されるまで少し時間がかかるためです。もし、rootMargin
を指定していない、もしくは値が小さい場合は、Twitter や Instagram が表示されるまでユーザーを待たせてしまいます。
rootMargin
が 0px
の場合です。埋め込みが画面内に入ってきてから、Twitter の <script>
を追加します。そのため、Twitter が表示されるまでユーザーを待たせます。
一方、1250px
手前で <script>
を追加した場合は、埋め込みが画面内に入ってきた時には、すでに Twitter や Instagram は表示されていると思います。
rootMargin
が 1250px
の場合です。埋め込みが画面内に入ってきた時には Twitter が表示されており、ユーザーを待たせません。
ユーザーに不快な思いをさせないために、ある程度手前での <script>
の追加をおすすめします。もし、Twitter や Instagram の表示が遅いと感じる場合は、rootMargin
の値を大きくします。
rootMargin
の指定方法は、CSS の margin
とほぼ同じです。ただ、0
であっても単位が必要です。
ただし、ビューポートの拡大は、ページの上部に埋め込みがある場合に影響が出るかもしれません。もし、ページを表示した時に最初からビューポート内に埋め込みがある場合は、すぐに Twitter や Instagram の <script>
を追加します。追加する <script>
は非同期で動作しますが、ページの表示速度に影響が出るかもしれません。
rootMargin
の値の参考として、loading="lazy"
属性がある場合の Chrome の動作を書いておきます。<img>
に loading="lazy"
属性がある場合、Chrome における画像の遅延読み込みの動作は以下のとおりです。
- 4G 回線などの高速回線の場合は、画面内に入ってくる
1250px
手前で画像を読み込む。 - 3G 回線などの低速回線の場合は、画面内に入ってくる
2500px
手前で画像を読み込む。
画像より読み込みに時間がかかる <iframe>
の場合は、さらに手前から読み込みます。
- 4G 回線などの高速回線の場合は、画面内に入ってくる
2500px
手前でインラインフレームを読み込む。 - 3G 回線などの低速回線の場合は、画面内に入ってくる
3500px
手前でインラインフレームを読み込む。
参考情報
テスト環境で試し限り、最低でも 800px
は必要のように感じました。