画像の表示で画面がズレないよう変更したことで、はてなブログの何が改善されたのか

こんにちは。id:nanimono_demonaiです。はてなブログMediaのWebアプリケーションエンジニアをしています。2カ月ほど前になりますが、はてなブログで、はてなフォトライフの画像を貼り付けたときの表示方法が変わりました。

今回は、私がこの変更に加えた改善の内容を、故郷の両親にも伝えられるようにまとめてみました。

見た目は変わらないのに何が良くなったのか?

今回の変更では、はてなのWebアルバムサービスであるはてなフォトライフに保管した画像を、はてなブログに表示する方法を改善しました。と言っても、これによって画像の見た目が変わったワケではありません。目で見て変化がないのはもちろん、画像ファイルに変更を加えたワケでもありません。

しかし、大きな改善を加えました。それは画像を表示するまでに、画面のズレが起きなくなったということです。

画像が後から読み込まれて閲覧中の領域が下にずれてしまう問題を回避する はてなフォトライフの画像を表示する際に、画面にズレが生じないよう変更しました - はてなブログ開発ブログ

画面のズレは、Webページを表示する途中で起きます。そこで最終的な見た目は変えないで、その途中の処理を改善したことが、この変更の主旨です。

さて、皆さんが普段Webページを閲覧しているブラウザーでは、Webページを最終的な見た目で表示するまでに以下の処理が行われます。

  1. リクエスト
    ブラウザーから、Webページの表示方法をサーバー(はてな)に要求する
  2. レスポンス
    1.の要求にサーバーが応答し、Webページの表示方法をブラウザーに送る
  3. レンダリング
    送られたページの表示方法をもとに、ブラウザーがページの表示を組み立てる
    このときブラウザーは、必要に応じて画像ファイルなどの情報をサーバーに追加で要求する

今回の変更ではレスポンスに手を加えて、レンダリングを改善しました。具体的には、画像を表示するための情報に、画像の縦と横の長さを加えました。

imgタグに画像の縦横長を追加した

変更したところは、Webページの表示方法を定義するHTMLコード中のimgタグです。

変更前のimgタグは、例えば次のようになっていました(分かりやすいように改行を追加しています)。

<img src="https://cdn-ak.f.st-hatena.com/images/fotolife/s/sample/20210101/20210101000000.jpg"
 alt="f:id:sample:20210101000000:plain" title=""
 class="hatena-fotolife" itemprop="image"
 />

これを次のように変更しました。画像の縦横長(widthheight)が追加されていることに注目してください。

<img src="https://cdn-ak.f.st-hatena.com/images/fotolife/s/sample/20210101/20210101000000.jpg"
 alt="f:id:sample:20210101000000:plain" title=""
 class="hatena-fotolife" itemprop="image"

 width="画像の幅(数字が入ります)" height="画像の高さ(数字が入ります)"

 loading="lazy"
 />

変更前のimgタグでは、画像の縦横長が指定されていません。このときブラウザーはまず画像の縦横長を仮置きして、表示するための枠を確保します。それから画像を取得して、本当の縦横長で表示します。この仮置きと本当の縦横長の差が、画像が表示されるときのズレにつながります。例えるなら、必要な情報が設計書に全て書かれていなかったので、現場のブラウザーの仕事が増えてしまったといったところです。

ブラウザーの処理を改善することは、ブラウザー利用者のメリットにつながります。画像のズレを改善すべきだった理由を、利用者の視点から説明します。

表示のズレの改善を指標で表す

Webページを閲覧するときに画像の表示によるズレがあると、利用者にはどういったことが起きるでしょうか。

よくあるのが、読んでいる途中の文章が下方向にガクッとズレてしまって少し困ることです。ズレる幅はまちまちなので、読んでいた文にすぐに目を戻せるときもあれば、画面の外に出てしまって見失うことすらあります。

画像がたくさん使われているページでは、表示される画面をスクロールしてようやく目当ての文章が読めたと思ったら、文章が逃げるように画面の表示の外にズレてしまうこともあり、私もさすがにしょんぼりしてしまいます。

また、表示のズレは文章が読みづらいだけでなく、Webページの操作を難しくする原因にもなり得ます。ボタンやリンクをクリックするときに画面の表示がズレた結果、違うボタンを押してしまうこともあります。次の画像のように、望まない商品を買ってしまうことにもつながりかねません。

表示のズレが損害になりうる例
表示のズレが損害になりうる例

このような表示のズレが少なければ、文字を追うのが楽になり、さらに操作もしやすくなるので、一般的にWebページの閲覧が快適になります。つまり、表示のズレが少ないページのほうが良いページだと言えます。

この良し悪しは、CLSというスコアで評価することができます。

なお、この後で紹介するCLSのWebページには「望まないボタン」の例を表す動画もあります。上記の画像はその動画(CC-BY 4.0)に基づいて作成しました。

CLSとは何か?

CLS(Cumulative Layout Shift)は、Googleによって策定されたWebページの視覚的安定性(Visual stability)を表す指標です。今回はかいつまんで説明しますので、詳細な挙動は次のページを参照してください。

Cumulative Layout Shift (CLS) - web.dev

CLSの計算には、閲覧者にとって意図しない表示のズレである予期しないレイアウトシフト(Unexpected layout shifts)と、それを数値化したレイアウトシフトスコアが用いられます。なお、CLSは過去に算出方法が改訂されており、今後も改訂されるかもしれません。

ここで「予期しないレイアウトシフト」とは、ユーザーの操作を起点とせずに起きる表示のズレのことです。このため、ユーザーの操作から0.5秒以内に画面のズレが起きるときは、予期しないレイアウトシフトに含まれません。また、レイアウトシフトは画像に限らず、表示の途中で文章が追加されるなどによるズレも含まれます。

f:id:nanimono_demonai:20210805102004p:plain
レイアウトシフトの例

CLSでは、ページ閲覧中に起きるレイアウトシフトを、起きた時間によりいくつかのセッションウィンドウと呼ばれる区間に分けて計測します。セッションウィンドウそれぞれのレイアウトシフトスコアの合計を計算し、そのうち最大の合計値がそのページのCLSとなります。

セッションウィンドウは、予期しないレイアウトシフトが1秒未満の間隔で連続して起きている区間です。ただし最長でも5秒です。予期しないレイアウトシフトの間隔が1秒空くか、あるいはセッションウィンドウが5秒を超えると、次の予期しないレイアウトシフトは次のセッションウィンドウに含めて計算します。

レイアウトシフトスコアは、影響の割合(impact fraction)と移動長の割合(distance fraction)から計算されます。それぞれ画面に対する「画面の書き変わった領域」と「画面の中で最も移動した要素の移動の距離」の割合を掛け合わせた値を計算に利用します。

レイアウトシフトスコア計算に用いる画面上の変化
レイアウトシフトスコア計算に用いる画面上の変化

さらに詳細な説明は前述したリンクに委ねますが、WebページのCLSを計測するだけなら、ブラウザーがGoogle ChromeであればLighthouseを使って確認できます(デベロッパーツールに統合されています)。

Lighthouse によるウェブアプリの監査 | Tools for Web Developers

CLSは低ければ低いほど良く、理想の値は0です。ただし、調査に基づく実現可能かつ良好なCLSの目標値として、Googleは0.1未満を提示しています。この数値は現状のインターネットに基づいているので、将来的に例えば0.05になるかもしれません。

一方、現状では不良なスコアとして0.25以上という数字も提示されています。改善前のはてなブログでは、画像をたくさん使っている場合には惜しくも0.25を超えることがありました。

はてなブログでCLSがどのくらい向上したか?

はてなブログでは画像の表示を変更した結果、新しく作られた記事のCLSが改善しています。単純な例として、大中小の画像を貼り付けた次のような記事を作り、変更前後のCLSをLighthouseで計測しました*1

CLS検証ブログ
ブログの様子

このように画像をたくさん使った記事のCLSをLighthouseで見てると、次のような変化が見られました。いくつか出力された指標のうち、右下にあるCumulative Layout Shiftの項目に注目してください。

CLS改善前のLighthouseでのスコア
CLS改善前

変更前のはてなブログでは上記のように0.202で、Googleが提示する「0.1未満」という目標を達成できていませんでした。

CLS改善後のLighthouseでのスコア
CLS改善後

しかし、変更後は上記のように0.004と大きく改善され、目標を達成できました。

これは、画像の読み込み前後でレイアウトシフトが発生する有無で説明できます。画像の読み込み前後におけるレイアウトシフトはユーザーの操作を伴わないため、意図しないレイアウトシフトとなり、CLSを悪化させます。

変更以前は、画像が読み込まれる前後でレイアウトシフトが生じており、さらに画像の枚数が多かったり画像が大きかったりすると、レイアウトスコアも大きくなっていました。なぜなら画面の書き変わった領域が大きくなるためです。

一方、変更後では画像の読み込み前後でレイアウトシフトが生じなくなったため、画像の枚数や大きさにらずレイアウトシフトスコアが増加しなくなりました。このためCLSが改善されたのです。

SEOにおける改善も

CLSスコアを良くすると、SEO(検索エンジン最適化)の改善も見込まれます。SEOについては他の記事に説明を譲るとして、SEOが改善されると、皆さんの記事がより見つけられやすくなることでしょう。

なぜならCLSは、CWV(Core Web Vitals)というWebページの閲覧がいかに快適にできるかを計るスコアの計算に使われており、Googleは2021年6月中旬からCWVを検索ランキングの指標に使うようになっためです。

Google Developers Japan: Web Vitals の概要: サイトの健全性を示す重要指標

遅延読み込みによって閲覧も軽快に

表示のズレを改善することで、さらに別の改善もできました。

ブラウザーの標準の挙動では、Webページにある全ての画像を一度に読み込もうとします。そのため記事の途中で読むのをやめてもブラウザーの動作が重くなっていても、ページ中の全画像を読み込んで、その分の通信量を消費してしまいます。

遅延読み込み(lazy-loading)は、画面に表示されていない画像の読み込みを低減する機能です。この機能を有効化にすると、画像がたくさんある記事を軽快に閲覧することができます。

しかし、画像による表示のズレが起きる状態で遅延読み込みを導入すると、ページをスクロールして次の画像の場所に来るたびにレイアウトシフトが起きてしまいます。

今回、imgタグに縦横長を盛り込むことで遅延読み込みしても表示のズレが生じなくなったので、軽快かつ快適にブログを閲覧できる環境を整えることができました。

おわりに

はてなブログでは、はてなフォトライフの画像を貼り付けたときの表示方法を変更することで、ブログの閲覧を軽快かつ快適にすることができました。今後も、より新しいWeb標準に追従していきたいと考えています。

はてなでは、今の技術・この先の技術に積極的な仲間を募集しています

参考文献

*1:画像はそれぞれ、大=3024×4032px(1.9MB)、中=500×667px(610KB)、小=100×133(7KB)のサイズで, いずれも私が飼っている猫を自ら撮影したものでした。