こんにちは。今回はimgタグのdecoding属性の適切な指定方法とその効果について解説していきます。
※2024/6/24追記 改めて調査、実験を行った結果decoding属性は現状不要という意見に変わりましたので内容を大幅に変更しました。
概要
画像のデコード(後述)方法を制御する属性です。この属性は以下の3つの値を取ることができます。ただし実際にブラウザで計測などをした結果、結論としては指定しなくても良いどころか逆効果の可能性すらあるようです。
async
: 画像のデコードを非同期に行うように指示します。これはページのレンダリングをブロックするのを防ぎ、ページの読み込み速度を向上させることができます。sync
: 画像のデコードを同期的に行うように指示します。画像がすぐに表示されることを保証しますが、大きな画像をデコードするとページのレンダリングがブロックされる可能性があります。auto
: ブラウザにデコード方法を自動的に決定するように指示します。ページの他の要素や画像のサイズや種類などの要素に基づいて最適なデコード戦略を選択します。
参考:https://developer.mozilla.org/ja/docs/Web/HTML/Element/img
デフォルトはautoで、何も指定しなければautoになります。
さて、非常にややこしくなってきましたね。笑
まず「レンダリングをブロックする」とは何なのか説明します。
画像のデコードとは
画像は通常、JPEGやPNGなどの形式でエンコードされた上で通信されます。ブラウザがこれらのデータを受け取ったとき、実はそのまま表示させているのではありません。画面の表示に適したビットマップ形式という別の形式にデコード(つまり、エンコードを解除して画像を再構成)する必要があります。このデコード処理は画像のサイズや複雑さによっては時間がかかる可能性があります。
デコード処理についての参考はこちらです。
「レンダリングをブロックする」とは
その文言の通り、レンダリング(=画面への描画)を止めてしまうことを言います。代表的なのは、画像、CSS、JavaScriptなどの外部リソースを読み込む時に発生することでしょう。例えば以下のようなHTMLがあったとします。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="./resources/styles/style.css" />
</head>
<body>
<!-- 省略 -->
</body>
</html>
7行目でlinkタグを使ってCSSファイルを読み込んでいます。この時、CSSファイルの読み込みが完了するまでHTMLの次の行以降が一切読み込まれません。もしCSSファイルの容量が大きいと、しばらくの間画面には何も表示されなくなります。これがレンダリングをブロックするということです。
そして先ほど説明した画像のデコードは、これと同様にレンダリングをブロックするとされています。
デコード処理が重いとページの読み込み速度に影響が出てしまうわけですね。
ここでdecoding属性が登場します。decoding=”async”を指定するとブラウザはレンダリング操作を停止せずデコードを並列的に行うことができます。非同期に処理をするとも言います。
デコードを待たずに他の要素を表示させるのでユーザーにとってはその方が良さそうですよね。
実際に試してみる
さて、「画像のデコードはレンダリング操作を停止させる」とされていますが実際には画像の表示が完了せずとも他の要素は表示されます。
これは実際に試してみればすぐに分かります。画像の描画が完全にできていなくとも、テキストが表示されています(下画像)。
より詳しく見るために、開発者ツールの「パフォーマンス」タブを見てみます。パフォーマンスタブには様々な情報が表示されていますが、いくつかのポイントに注目します。
- HTMLの読み込み完了(=DOMContentLoadedイベント発火)
- ページの読み込み完了タイミング(=loadイベント発火)
- デコード処理中タイミング
- 画像のレンダリング開始タイミング
の4つに注目します。decoding=”sync”の場合とdecoding=”async”の場合をそれぞれ見てみましょう。1つ目がsync、2つ目がasyncです。
さて、見比べてみてもほとんど違いがありません。目視による差もほとんど感じません。一応画像自体は4.7MBと、かなり大きめのサイズものを使用していますが人間にとってはほぼ同じですね。
キャッシュがある場合
色々調査したところ、キャッシュがある場合では結果が変わるという意見を見たのでそちらも試してみました。
さて、タイミングに関してはほとんど同じに見えますが決定的な違いが一つあります。asyncの方は画像が表示され始める前にテキスト部分が先に表示されています。上の画像のスクリーンショット部分を抜粋してみます。
テキストのみが表示されている瞬間が存在していますね。
一方syncの場合はテキストと画像は同時に表示されます。テキストのみ表示される瞬間が存在しません。
asyncの場合は明確にデコード処理の完了を待たずに他の要素を表示しているようです。
これも正直人間の目からすれば全く違いがわからないのですが、一応キャッシュがある時には効果があることがわかりました。
asyncにはデメリットもある
さて、ここまでを踏まえるととりあえずasyncは設定しておいても良さそうに思えます。しかしasync指定にはデメリットもあることに注意しましょう。
次のページにアクセスして、再読み込みを繰り返してみてください。左側のみちらつきが発生すると思います。
上記ページでは左側の画像がdecoding=”async”、右側がdecoding=”sync”となっています。
再読み込み時にはキャッシュが存在しているわけですが、上述の「デコード処理の完了を待たずに他の要素を表示」が影響してしまい必ず後から画像が表示されてちらつきの原因になるようです。
syncの方はちらつきがなくスムーズに表示されているため、これでは逆効果ですね。特に2回目以降のアクセスが頻繁に発生すると想定されるサイトの場合はやらない方が良い気がします。
ブラウザ対応状況
一応ブラウザ対応状況を確認しましょう。主要なブラウザはほぼ全て対応しています。
全体で見ると67.17%程度が対応されているようです。最新情報は以下より。
総合すると、設定しなくても良さそう
ここまで長々と解説してきましたが、
- 人間にとっては違いはほとんど感じられない
- 容量が大きい画像でも、デコードが原因で遅く感じられる可能性も低い
- キャッシュが存在し、かつdecoding=”async”の時は再読み込み時にちらつきが発生する
という理由で特に指定しなくても良いのではないかと思います。ブラウザの種類や今後のアップデートによって変わる可能性もありますので、定期的に挙動をチェックしてみるのが良いでしょう。
decoding属性以外にもimgタグに必要な属性はいくつかあります。それらを完全に解説し、よりimgタグを理解して使いこなすための本を発売中です!ぜひお買い求めください!
コメント