LoginSignup
9
10

フロントエンドコーディングでやっておきたい表示速度対策

Last updated at Posted at 2023-07-10

Web の進化により、フロントエンドコーディングはデザインを再現するだけでは済まなくなりました。

「ふぅ~。デザイン通りにコーディングしてやったぜぇ~:smirk:
では終われません!

デザインを再現する以外にも注力することがいっぱい増えました…:persevere:

というわけで、フロントエンドコーディングでやっておきたい表示速度対策をまとめてみました!

次世代画像形式

ページ内に表示する画像は圧縮率の高い、次世代画像形式を利用します。

一般的には、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 以降が利用可能となります:expressionless:

OS リリース日
macOS 13 Ventura 2022年10月24日

2024年1月26日にリリースされた Edge 121 で、Edge も利用可能になりました:stuck_out_tongue_closed_eyes:

WebP

Google によって開発された新しい画像形式です。

  • 高い圧縮率
  • 可逆圧縮と非可逆圧縮の両保存形式に対応
  • 透過処理に対応
  • アニメーションに対応
  • 対応ブラウザ

対応ブラウザ

Safari 以外のブラウザであれば表示可能です。
Safari は以下 OS 以降が利用可能となります:expressionless:

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.jpgimage.png がある場合に image.webp と同じ名前になってしまいます。

作成した画像は以下の優先度で、ブラウザごとに振り分けます。

優先度 ブラウザ 表示する画像形式
1 AVIF 対応ブラウザ AVIF
2 AVIF 非対応ブラウザ WebP
3 AVIF / WebP 非対応ブラウザ JPEG、PNG

画像の振り分けは picture 要素、または .htaccess で振り分ける方法があります。

picture 要素

picture 要素を利用して画像を振り分けます。

  • source 要素に AVIF / WebP 画像を指定
  • img 要素に AVIF / WebP 非対応ブラウザ用画像を指定
HTML
<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 非対応ブラウザ用画像を読み込んでおきます。

HTML
<img src="image.jpg">

画像の振り分け処理を .htaccess に記述します。

画像のファイル名に元画像の拡張子を含むか、含まないかで .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」を利用すると簡単に確認できます。

個別の画像だけであれば、画像を保存しようとした時に表示される画像名の拡張子で確認できます。

開発者ツール

  1. F12 を押して開発者ツールを表示
  2. ネットワーク を選択
  3. webp でフィルタ
  4. タイプ 列が octet-stream or webp になっているか確認する

AVIF のタイプは avif ではなく、octet-stream と表示されるようです。

webp.png

WebP and AVIF Highlighter

WebP and AVIF Highlighter を有効にすると WebP 画像に枠線が表示されます。
線の色は3種類あり、色の違いは以下となります。

意味
非可逆圧縮
ピンク 可逆圧縮
アルファチャンネルなど拡張を含む画像

webp-and-avif-highlighter.png

リソースヒント

リソースヒントは、これから必要になるリソースを事前に読み込んでおくことで、ページ遷移時のパフォーマンスを向上させます。

リソースヒントは以下の4種類あり、ネットワークの流れによってタイミングが異なります。

resource-hints.png

dns-prefetch

rel="dns-prefetch" を指定すると、事前に DNS の名前解決(ドメイン名をIPアドレスに変換)をしておきます。

HTML
<link rel="dns-prefetch" href="https://example.com">

preconnect

rel="preconnect" を指定すると、事前に DNS の名前解決、 TCP の接続まで確立しておきます。

Google Fonts の利用コードには preconnect が指定されています。

HTML
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

prefetch

rel="prefetch" を指定すると、事前に静的リソースをダウンロードしておきます。

HTML
<link rel="prefetch" href="next-page.css" as="style">
<link rel="prefetch" href="next-page.js" as="script">

prerender

rel="prerender" を指定すると、事前にページを表示できる状態にしておきます。

HTML
<link rel="prerender" href="https://example.com/nextpage/">

プリロード

rel="preload" を指定すると、リソースを早く読み込むようになり、ページのレンダリングをブロックしません。

以下はよく利用しそうな as 属性の値です。
フォントの場合は CORS を有効にするために crossorigin 属性も指定します。

as 属性 内容
font フォントファイル
image 画像ファイル
script JavaScript ファイル
style CSS ファイル

HTML
<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 属性

widthheight を指定すると、ブラウザが画像の幅と高さを直ぐ決定でき、コンテンツの再配置を行うことなく表示できます。

HTML
<img src="image.jpg" width="1000" height="1000">

decoding 属性

decoding="async" を指定すると、画像を非同期でデコードし、他のコンテンツ表示の遅延を減らせます。

decoading 属性は以下の値が指定できます。

属性値 内容
auto 既定値。ブラウザが最適なものを決定する
sync 他のコンテンツと画像を同期的にデコード
async 他のコンテンツと画像を非同期的にデコード
HTML
<img src="image.jpg" decoding="async">

loading 属性

loading="lazy" を指定すると、ビューポート内にある画像のみを読み込み、それ以外の画像はビューポート内に入るまで読み込みません。

loading 属性は以下の値が指定できます。

属性値 内容
eager 既定値。画像をビューポート外でもすぐに読み込む
lazy 画像を遅延読み込みする
HTML
<img src="image.jpg" loading="lazy">

メインビジュアルなどのファーストビューに表示される画像への指定は不要です。

レスポンシブイメージ

デバイスに応じた最適なサイズ、見た目の画像を表示します。

解像度で変更

解像度に応じて画像を変更する場合は、srcset 属性に画像のパスと画面の密度(デバイスピクセル比)を指定します。

HTML
<img src="image.jpg" srcset="image.jpg, image@2x.jpg 2x">

アートディレクション

画面幅に応じて画像を変更する場合は、picture 要素を利用します。

HTML
<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 要素に asyncdefer 属性を付与することで、HTML パースを中断させないようにします。

asyncdefer 属性の違いは以下となります。

属性 実行の順番 実行のタイミング
async ダウンロードが完了した順 ダウンロードが完了した直後
defer コード順 DOMContentLoaded イベントの直前

JavaScript は DOM を操作することがほとんどなので、基本的に defer を利用することになると思います。

HTML
<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 は、クライアントからのアクセスによって、サーバがファイルを圧縮します。

サーバーに負荷がかかります。

.htaccess
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 圧縮しないほうが安全です。

.htaccess
<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 圧縮が有効かどうかはブラウザの開発者ツールで確認できます。

  1. F12 を押して開発者ツールを表示
  2. ネットワーク を選択
  3. gzip 圧縮したファイルを選択
  4. レスポンスヘッダー内に content-encoding: gzip があるか確認する

gzip.png

ブラウザキャッシュ

更新頻度の低いファイルはブラウザキャッシュを使って表示させることで、ページの表示速度を早くします。

ファイル ブラウザキャッシュの保存期間
更新頻度低い 長い
更新頻度高い 短い

Apache の設定方法

ブラウザキャッシュの設定は .htaccess に記述します。

Cache-ControlヘッダーExpiresヘッダー 2種類の設定方法がありますが、Google は Cache-Controlヘッダー を推奨しています。

.htaccess
<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>

確認方法

キャッシュの確認はブラウザの開発者ツールで確認できます。

  1. F12 を押して開発者ツールを表示
  2. ネットワーク を選択
  3. キャッシュの有効期限を設定したファイルを選択
  4. レスポンスヘッダー内の cache-control に設定した秒数が反映されているか確認する

cache.png

関連記事

9
10
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
10