Help us understand the problem. What is going on with this article?

今からでも間に合う! CLS対策 について

虎の穴ラボ Advent Calendar 2020 - Qiita 3日目の記事です。

JavaScriptで画像が挿入されるサンプルページを用いて、CLS対策の具体的な方法を紹介します。CLS対策が必要な要素の調べ方 の続きです。

Googleから2021年5月よりCWVをランキング要因に組み込むと発表がありました。今から取り組んでもまだ間に合うと思いますので、CLS対策が全然出来てないという方はぜひ参考にしてください。

サンプルページの準備

サンプルで利用する以下のHTMLファイルをサーバーにアップロードします。

sample.html
<h1 id="cls">クリスマスは同人誌が欲しい</h1>

<script>
 //初期表示されるh1要素の手前に画像を挿入します。
 var cls = document.getElementById('cls')
 cls.insertAdjacentHTML('afterbegin','<img src="緑髪園児">')
</script>

ちなみにサーバー上にHTMLファイルを置いた理由は、ローカル環境のHTMLファイルに対して、Light Houseによる監査を実行することが出来ないためです。

レイアウトが動くページの確認

ページを開くと、画面の左上に「クリスマスは同人誌が欲しい」と一瞬だけ表示された後、緑髪園児画像が割り込むように現れました。
レイアウトが動くページ.gif
※ページの一部を抜粋してキャプチャしています。

なお、最初からimg要素がHTMLに記述されている場合でも、上記と同じ動きをします。

sample.html
<img id="img" src="緑髪園児">
<h1 id="cls">クリスマスは同人誌が欲しい</h1>

CLSの確認

それでは、スコアを計測してみます。サンプルページに対して、Light Houseの監査を実行したところ 0.015 でした。

この値は、低ければ低いほど良好です。本来、対策するまでもない程度の小さな値ですが、対策手順を紹介するため 0 を目指していきます。

CLS対策前のスコア

Light Houseの結果画面を少しだけスクロールすると、CLSに関する以下の項目が見つかります。
CLS対策前のDiagnostics

ここで検出された項目に従って対処していくことで、CLSスコアを改善することが出来ます。大まかな流れは以下のとおりです。

1.Image elements do not have explicit width and height で検出されたimg要素を固定化

2.Avoid Large Layout Shifts が表示されなくなった事を確認

それでは、検出された項目を1つずつ確認していきます。

1.Image elements do not have explicit width and height

(画像要素には明示的な幅と高さがありません)

この項目で表示されているimg要素に対して、幅と高さを指定する必要があります。
しかし、外部CSSファイルに幅と高さを指定する方法では、この項目の対応として不適切です。
※詳細は後述します。
幅と高さ警告

2.Avoid Large Layout Shifts

(大きなレイアウトシフトを避ける)

ここで検出された要素を動かないようにすれば、CLSスコアが改善されます。
要素を完全に動かなくできた場合は0となり、Light Houseでこの項目が検出されなくなります。
動いている要素

上記において、h1が動いている要素として検出されていますが、
h1要素を動かす原因となっているのは、JavaScriptで挿入されるimg要素の方です。

img要素の幅と高さは、読み込まれた画像の幅と高さに合わせて決定される為、
画像の読み込み完了と同時に要素が動いてしまいます。

そこで、img要素に対してはじめから幅と高さを指定し、
画像読込み前に画像領域を確保することで、要素の動きを防ぐ事ができます。

CLS対策

CLS対策と謳ってますが、実際にやることは画像サイズの固定化です。
固定化の方法として大きく2パターンあります。

1.img要素に幅と高さを指定する(推奨)

<img id="img" width="512" height="768" src="緑髪園児">
<!-- 数字の後にpxは不要です。 -->

上記のようにimg要素に幅と高さを指定した状態でページを開いてみると、
「クリスマスは同人誌が欲しい」という謎のメッセージ(h1要素)が現れなくなりました。

tai.gif

その後、LightHouseで監査をかけるとCLSが0であることを確認出来ました。

cls対策後のスコア

先程検出されていた警告も消えており、この状態になればCLS対策として上出来です。
cls対策後のDiagnostics

ちなみに、img要素に幅と高さをインラインで記述しても同様の結果なります。

<img id="img" style="width:512px; height:768px;" src="緑髪園児">

2.CSSファイルに記述する (非推奨)

外部のスタイルシートに記述することでも、CLS対策が可能です。

style.css
img{
 width:512px;
 height:768px;
}
sample.html
<link rel="stylesheet" href="./style.css">

<h1 id="cls">クリスマスは同人誌が欲しい</h1>

<script>
 var cls = document.getElementById('cls')
 cls.insertAdjacentHTML('afterbegin','<img src="緑髪園児">')
</script>

CLSスコアを確認してみると、0になっているので改善効果はありました。
CLS対策2の結果
しかし、img要素に幅と高さを指定していない為、警告が残り続けてしまいます。
幅と高さ指定の警告が残る

なお今回の場合、CSS→JavaScriptの順で読み込まれているのでスコアは改善されましたが、JavaScript→CSSの順で読み込まれた場合はレイアウトの動きを防げませんので、こちらの方法は非推奨です。

まとめ

CLS対策は以下の理由から、img要素にwidthとheightを直接指定する方法を推奨します。

  • Light Houseの幅と高さが指定されてないという警告が消える
  • CSSの読み込みタイミングに関わらずimg要素を固定化できる
tora_oba
とらのあな通販サイトのSEO担当です。
https://yumenosora.co.jp/tora-lab
toranoana
とらのあな関連サービスのシステム開発を担う、エンジニア所属会社
https://yumenosora.co.jp/tora-lab
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away