Web の進化により、フロントエンドコーディングはデザインを再現するだけでは済まなくなりました。
「ふぅ~。デザイン通りにコーディングしてやったぜぇ~」
では終われません!
デザインを再現する以外にも注力することがいっぱい増えました…
というわけで、フロントエンドコーディングでやっておきたい表示速度対策をまとめてみました!
次世代画像形式
ページ内に表示する画像は圧縮率の高い、次世代画像形式を利用します。
一般的には、AVIF が一番圧縮率が高いですが、画像によっては、WebP や JPEG、または PNG の方が軽くなる場合があります。
AVIF
Alliance for Open Media(AOMedia)によって開発された新しい画像形式です。
- 高い圧縮率(WebP よりも高圧縮)
- 可逆圧縮と非可逆圧縮の両保存形式に対応
- 透過処理に対応
- アニメーションに対応
- HDR(High Dynamic Range)に対応
HDR(High Dynamic Range)は、従来の SDR(Standard Dynamic Range)に比べてより広い明るさの幅(ダイナミックレンジ)を表現できる表示技術です。「色深度(明暗差の階調)」を増やすことで、黒つぶれや白飛びしない、より自然でリアルな描写が可能になります。
対応ブラウザ
Safari 以外のブラウザであれば表示可能です。
Safari は macOS 13 Ventura 以降が利用可能となります
OS | リリース日 |
---|---|
macOS 13 Ventura | 2022年10月24日 |
2024年1月26日にリリースされた Edge 121 で、Edge も利用可能になりました
WebP
Google によって開発された新しい画像形式です。
- 高い圧縮率
- 可逆圧縮と非可逆圧縮の両保存形式に対応
- 透過処理に対応
- アニメーションに対応
- 対応ブラウザ
対応ブラウザ
Safari 以外のブラウザであれば表示可能です。
Safari は以下 OS 以降が利用可能となります
OS | リリース日 |
---|---|
macOS 11 Big Sur | 2020年11月13日 |
iOS 14 | 2020年9月17日 |
作成方法
JPEG or PNG を AVIF / WebP に変換して作成します。
Squoosh
ブラウザ上で AVIF / WebP を作成できます。
WebP Converter
WebP を作成できるアプリケーション。(Win / Mac 対応)
sharp
Node.js のパッケージ。
AVIF / WebP を作成できます。
sharp の利用例を記事にしたので参考にしてみてください。
表示方法
非対応ブラウザも考慮する必要があります。
1つの画像につき、3種類の画像形式(AVIF / WebP / JPEG or PNG)の画像ファイルを作成します。
画像のファイル名は、ファイル名の競合を防ぐため、元画像の拡張子も含めたほうが安全です。
元画像の拡張子を残さない場合、image.jpg
と image.png
がある場合に image.webp
と同じ名前になってしまいます。
作成した画像は以下の優先度で、ブラウザごとに振り分けます。
優先度 | ブラウザ | 表示する画像形式 |
---|---|---|
1 | AVIF 対応ブラウザ | AVIF |
2 | AVIF 非対応ブラウザ | WebP |
3 | AVIF / WebP 非対応ブラウザ | JPEG、PNG |
画像の振り分けは picture
要素、または .htaccess
で振り分ける方法があります。
picture 要素
picture
要素を利用して画像を振り分けます。
-
source
要素に AVIF / WebP 画像を指定 -
img
要素に AVIF / WebP 非対応ブラウザ用画像を指定
<picture>
<!-- 🥇優先順位1 -->
<source srcset="image.jpg.avif" type="image/avif">
<!-- 🥈優先順位2 -->
<source srcset="image.jpg.webp" type="image/webp">
<!-- 🥉優先順位3 -->
<img src="image.jpg">
</picture>
.htaccess
HTML は WebP 非対応ブラウザ用画像を読み込んでおきます。
<img src="image.jpg">
画像の振り分け処理を .htaccess
に記述します。
画像のファイル名に元画像の拡張子を含むか、含まないかで .htaccess
の記述が異なります。
<IfModule mod_rewrite.c>
RewriteEngine On
# AVIF の処理
RewriteCond %{HTTP_ACCEPT} image/avif
RewriteCond %{REQUEST_URI} (?i)(.*)(\.jpe?g|\.png|\.gif)$
# 元画像の拡張子を含む
RewriteCond %{DOCUMENT_ROOT}%1%2.avif -f
RewriteRule (?i)(.*)(\.jpe?g|\.png|\.gif)$ %1$2\.avif [L,T=image/avif,R]
# 元画像の拡張子を含まない
# RewriteCond %{DOCUMENT_ROOT}%1.avif -f
# RewriteRule (?i)(.*)(\.jpe?g|\.png|\.gif)$ %1\.avif [L,T=image/avif,R]
# WebP の処理
RewriteCond %{HTTP_ACCEPT} image/webp
RewriteCond %{REQUEST_URI} (?i)(.*)(\.jpe?g|\.png|\.gif)$
# 元画像の拡張子を含む
RewriteCond %{DOCUMENT_ROOT}%1%2.webp -f
RewriteRule (?i)(.*)(\.jpe?g|\.png|\.gif)$ %1$2\.webp [L,T=image/webp,R]
# 元画像の拡張子を含まない
# RewriteCond %{DOCUMENT_ROOT}%1.webp -f
# RewriteRule (?i)(.*)(\.jpe?g|\.png|\.gif)$ %1\.webp [L,T=image/webp,R]
</IfModule>
<IfModule mod_mime.c>
AddType image/webp .webp
AddType image/avif .avif
</IfModule>
<IfModule mod_headers.c>
Header append Vary Accept env=REDIRECT_accept
</IfModule>
確認方法
AVIF / WebP の表示確認はブラウザの開発者ツールで行えます。
その他に、Chrome の拡張機能「WebP and AVIF Highlighter」を利用すると簡単に確認できます。
個別の画像だけであれば、画像を保存しようとした時に表示される画像名の拡張子で確認できます。
開発者ツール
-
F12
を押して開発者ツールを表示 -
ネットワーク
を選択 -
webp
でフィルタ -
タイプ
列がoctet-stream or webp
になっているか確認する
AVIF のタイプは avif
ではなく、octet-stream
と表示されるようです。
WebP and AVIF Highlighter
WebP and AVIF Highlighter を有効にすると WebP 画像に枠線が表示されます。
線の色は3種類あり、色の違いは以下となります。
色 | 意味 |
---|---|
緑 | 非可逆圧縮 |
ピンク | 可逆圧縮 |
赤 | アルファチャンネルなど拡張を含む画像 |
リソースヒント
リソースヒントは、これから必要になるリソースを事前に読み込んでおくことで、ページ遷移時のパフォーマンスを向上させます。
リソースヒントは以下の4種類あり、ネットワークの流れによってタイミングが異なります。
dns-prefetch
rel="dns-prefetch"
を指定すると、事前に DNS の名前解決(ドメイン名をIPアドレスに変換)をしておきます。
<link rel="dns-prefetch" href="https://example.com">
preconnect
rel="preconnect"
を指定すると、事前に DNS の名前解決、 TCP の接続まで確立しておきます。
Google Fonts の利用コードには preconnect
が指定されています。
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
prefetch
rel="prefetch"
を指定すると、事前に静的リソースをダウンロードしておきます。
<link rel="prefetch" href="next-page.css" as="style">
<link rel="prefetch" href="next-page.js" as="script">
prerender
rel="prerender"
を指定すると、事前にページを表示できる状態にしておきます。
<link rel="prerender" href="https://example.com/nextpage/">
プリロード
rel="preload"
を指定すると、リソースを早く読み込むようになり、ページのレンダリングをブロックしません。
以下はよく利用しそうな as
属性の値です。
フォントの場合は CORS を有効にするために crossorigin
属性も指定します。
as 属性 | 内容 |
---|---|
font | フォントファイル |
image | 画像ファイル |
script | JavaScript ファイル |
style | CSS ファイル |
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="style.css" as="style">
<link rel="preload" href="script.js" as="script">
何でもかんでも preload させるのは逆効果です。
ページの表示に関わる主要なリソースを指定しておきましょう。
img 要素
width height 属性
width
と height
を指定すると、ブラウザが画像の幅と高さを直ぐ決定でき、コンテンツの再配置を行うことなく表示できます。
<img src="image.jpg" width="1000" height="1000">
decoding 属性
decoding="async"
を指定すると、画像を非同期でデコードし、他のコンテンツ表示の遅延を減らせます。
decoading
属性は以下の値が指定できます。
属性値 | 内容 |
---|---|
auto | 既定値。ブラウザが最適なものを決定する |
sync | 他のコンテンツと画像を同期的にデコード |
async | 他のコンテンツと画像を非同期的にデコード |
<img src="image.jpg" decoding="async">
loading 属性
loading="lazy"
を指定すると、ビューポート内にある画像のみを読み込み、それ以外の画像はビューポート内に入るまで読み込みません。
loading
属性は以下の値が指定できます。
属性値 | 内容 |
---|---|
eager | 既定値。画像をビューポート外でもすぐに読み込む |
lazy | 画像を遅延読み込みする |
<img src="image.jpg" loading="lazy">
メインビジュアルなどのファーストビューに表示される画像への指定は不要です。
レスポンシブイメージ
デバイスに応じた最適なサイズ、見た目の画像を表示します。
解像度で変更
解像度に応じて画像を変更する場合は、srcset
属性に画像のパスと画面の密度(デバイスピクセル比)を指定します。
<img src="image.jpg" srcset="image.jpg, image@2x.jpg 2x">
アートディレクション
画面幅に応じて画像を変更する場合は、picture
要素を利用します。
<picture>
<source media="(max-width: 500px)" srcset="small.jpg">
<source media="(max-width: 900px)" srcset="medium.jpg">
<img src="large.jpg" srcset="large.jpg, large@2x.jpg 2x">
</picture>
script 要素
script
要素に async
や defer
属性を付与することで、HTML パースを中断させないようにします。
async
と defer
属性の違いは以下となります。
属性 | 実行の順番 | 実行のタイミング |
---|---|---|
async | ダウンロードが完了した順 | ダウンロードが完了した直後 |
defer | コード順 |
DOMContentLoaded イベントの直前 |
JavaScript は DOM を操作することがほとんどなので、基本的に defer
を利用することになると思います。
<script src="script.js" defer></script>
JavaScript のバンドル
複数の JavaScript を1つにまとめることで、リクエスト回数が減り、ページの表示速度向上が期待できます。
バンドルするために Browserify 、 webpack 、Vite を利用することが多いと思います。
ミニファイ
ミニファイは、HTML、CSS、JavaScript などのコード中の不要な改行やインデントを削除し、ファイルサイズを小さくします。
HTML は、ソースコードを確認することが多いので、ミニファイしないほうが安全です。
プロジェクトにミニファイツールが導入されていない場合は、以下がオススメです。
gzip 圧縮
gzip 圧縮は、HTML、CSS、JavaScriptなどのテキストファイルを圧縮し、ファイルサイズを小さくします。
Apache の設定方法
gzip 圧縮 の設定内容は .htaccess
に記述します。
設定方法は以下の2通りあります。
mod_deflate
mod_deflate
は、クライアントからのアクセスによって、サーバがファイルを圧縮します。
サーバーに負荷がかかります。
SetOutputFilter DEFLATE
# 圧縮しないファイルの拡張子を設定
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png|webp|ico)$ no-gzip dont-vary
# 指定したファイル以外をすべてgzip圧縮する
Header append Vary User-Agent env=!dont-vary
mod_rewrite
mod_rewrite
は、クライアントからアクセスされた URL を gzip ファイルの URL に書き換えます。
gzip ファイルを作成し、サーバーに設置しておく必要があります。
ファイルを更新した場合は gzip ファイルも更新しないと、古いファイルが読み込まれたままになります。
頻繁に更新する HTML は gzip 圧縮しないほうが安全です。
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTP:Accept-Encoding} gzip
RewriteCond %{REQUEST_URI} (\.html|\.css|\.js)$
RewriteCond %{REQUEST_FILENAME}\.gz -s
RewriteRule .* %{REQUEST_URI}.gz [L]
</IfModule>
<IfModule mod_headers.c>
<FilesMatch "\.html\.gz$">
ForceType text/html
AddEncoding x-gzip .gz
</FilesMatch>
<FilesMatch "\.css\.gz$">
ForceType text/css
AddEncoding x-gzip .gz
</FilesMatch>
<FilesMatch "\.js\.gz$">
ForceType application/x-javascript
AddEncoding x-gzip .gz
</FilesMatch>
</IfModule>
確認方法
gzip 圧縮が有効かどうかはブラウザの開発者ツールで確認できます。
-
F12
を押して開発者ツールを表示 -
ネットワーク
を選択 - gzip 圧縮したファイルを選択
- レスポンスヘッダー内に
content-encoding: gzip
があるか確認する
ブラウザキャッシュ
更新頻度の低いファイルはブラウザキャッシュを使って表示させることで、ページの表示速度を早くします。
ファイル | ブラウザキャッシュの保存期間 |
---|---|
更新頻度低い | 長い |
更新頻度高い | 短い |
Apache の設定方法
ブラウザキャッシュの設定は .htaccess
に記述します。
Cache-Controlヘッダー
、Expiresヘッダー
2種類の設定方法がありますが、Google は Cache-Controlヘッダー
を推奨しています。
<IfModule mod_headers.c>
# 1時間
<FilesMatch "\.(html)(\.gz)?$">
Header set Cache-Control "max-age=3600, public"
</FilesMatch>
# 2週間
<FilesMatch "\.(css|js|gif|jpe?g|png|webp|svg|pdf)(\.gz)?$">
Header set Cache-Control "max-age=1209600, public"
</FilesMatch>
# 1年
<FilesMatch "\.(ico|woff|woff2)$">
Header set Cache-Control "max-age=31536000, public"
</FilesMatch>
# キャッシュさせたくない場合
# <FilesMatch "\.(css|js)$">
# 内容に変更があればキャッシュを使用してはいけないという意味
# 一切キャッシュを保存しない場合は、no-cache の部分を no-store にする
# Header set Cache-Control no-cache
# 古い環境に対応するための設定
# Header set Pragma no-cache
# </FilesMatch>
</IfModule>
確認方法
キャッシュの確認はブラウザの開発者ツールで確認できます。
-
F12
を押して開発者ツールを表示 -
ネットワーク
を選択 - キャッシュの有効期限を設定したファイルを選択
- レスポンスヘッダー内の
cache-control
に設定した秒数が反映されているか確認する
関連記事