表示が遅いWebサイトをつくらないために

スタッフブログ

こんにちは、マークアップエンジニアの尾高です。
Web制作者にとって、切っても切れない関係と言えるものにページの表示速度があります。私もどうすれば表示が速くなるのか、何が遅い原因なのかを考えて色々と試行錯誤しました。

ところでGoogleの調べによると、読み込み時間が3秒を超えると53%のユーザーがそのサイトを離脱すると言われていることはご存知でしょうか?

表示が遅いためにWebサイトを見てくれないユーザーがいるとしたらもったいないです。そして、言語仕様を守ってコーディングしても遅い原因を作ってしまう可能性があります。
そこで今回はHTML・CSSの基本は身に付けたコーダーへ向けて、表示の遅いWebサイトを作らないために、最低限おさえておくべき知識や手法をご紹介いたします。

HTML

デバイスサイズによる画像切替

閲覧するデバイスサイズによってページ内の画像を切り替えたい場合、次のようにしていないでしょうか?

<img src="./img/image-sp.jpg" class="sp_image"><!-- スマートフォン用 -->
<img src="./img/image-pc.jpg" class="pc_image"><!-- パソコン用 -->
/* パソコンのスタイル */
.pc_image {
    display: block;
}

.sp_image {
    display: none;
}

/* スマートフォンのスタイル */
@media (max-width: 480px) {
    .pc_image {
        display: none;
    }

    .sp_image {
        display: block;
    }
}

img要素を2つ並べて、デバイス幅によって表示と非表示を切り替えています。

実はこの例では、画像を1枚表示したいだけなのに2枚分のリクエストが発生してしまいます。CSSでdisplay: none;を指定しても、表示されないだけで画像は読み込まれてしまうのです。

この場合は次のようにすればムダなリクエストを減らせれます。

<picture>
    <source srcset="./img/image-sp.jpg" media="(max-width: 480px)"><!-- スマートフォン用の画像 -->
    <img src="./img/image-pc.jpg"><!-- パソコン用の画像 -->
</picture>

picture要素は条件(ここでは画面幅)に適合した画像だけを読み込みます。0個以上のsource要素と1個のimg要素を含むことができます。source要素のmedia属性の値を上から順に判定して、最初に条件が一致したものだけを読み込みます。一致するものがなければ最後のimg要素が読み込まれます。

他にもimg要素のsrcset属性とsizes属性を使った方法もありますが、どちらにしても最適な1枚のみを読み込むのでムダなリクエストは発生しません。

2つの違いについては、picture要素は表示デバイスごとに画像の比率が変わる場合に適しています。img要素のsrcset属性とsizes属性は同じ比率でサイズ違いの画像を表示させる場合に適しています。

画像の遅延読み込み

ページの閲覧時にスクロールせず見える最初の表示領域のことを「ファーストビュー」と言います。ユーザーに「遅いサイト」と感じさせないためには、ファーストビューを速く表示することが重要です。
しかしページ内に画像が多くある場合などでは、ファーストビュー以外のデータ読み込みのためにファーストビューの表示が遅れてしまいます。

そこでファーストビューの表示を優先させるために、ファーストビュー以外の画像は遅延させて読み込みます。読み込むきっかけはスクロールなどによって表示領域に近づいてきた時です。

遅延読み込みの方法はいくつかあるのですが、

  • img要素にloading属性lazyを指定する
  • JSプラグインを使用する

この2つが比較的簡単に実装できると思います。

loading属性は以下のように使用します。

<img src="./img/image.jpg" loading="lazy">

たったこれだけの記述で遅延読み込みを実装できます。しかし、Safariなど未対応のブラウザがある、読み込み始めるタイミングはブラウザ次第、と言った問題もあります。タイミングがブラウザ次第ということは、ファイルサイズが大きい画像の場合ページへの表示がスクロールに間に合わなくなる可能性があります。

JSプラグインは種類によって使用方法が違うのですが、大体このような使い方です。まずプラグインファイルを読み込みます。そして遅延読み込みさせたいimg要素に、プラグインごとのルールに基づいた属性を指定します。

<!-- 省略 -->
<head>
    <script src="lazyload.js"></script><!-- プラグイン読み込み -->
</head>

<!-- 省略 -->

<img src="dummy.jpg" data-src="image.jpg" class="lazyload"><!-- 適用させたい画像にプラグインが指定する属性を設定 -->
<!-- 省略 -->

この例では、遅延読み込みの対象であることを明示して、最初に読み込むダミー画像と遅延させて読み込む画像を指定しています。
JSプラグインによる方法はほとんどの場合どのブラウザでも動作しますし、読み込みに関する設定を変更できる場合が多いです。

loading属性とJSプラグイン、どちらの方法も一長一短ですが、どちらにしても画像が多いページほどかなり大きな効果が期待できます。

スクリプト読み込みの同期・非同期

外部ファイルのJavaScriptを読み込むにはいくつかの方法がありますが、大きく分けると同期読み込みと非同期読み込みの2つに分類できます。ここではどれが速いかではなく、どれが表示を遅くするかを説明します。

基本的な読み込みかたは、以下のようにhead要素内もしくはbody要素内の末尾に記述します。この方法は同期読み込みといい、記述した位置で読み込みと実行が行われて、DOMの解析を中断させてしまいます。ちなみにbody要素内でも末尾以外に記述した場合は、head要素内と同じようにその後のDOM解析を中断させます。
DOMはブラウザがページを表示するために必要なデータなので、中断される分ページの表示が遅れます

<head>
    <script src="./js/head.js"></script>
</head>
<body>
    <!-- 省略 -->
    <script src="./js/body.js"></script>
</body>

そして非同期読み込みは以下のように属性を指定して記述します。こちらは記述した位置で読み込みを開始しますが、指定した属性により実行タイミングは違います。asyncは読み込み終了後すぐに実行。deferDOMContentLoadedイベントが発火する直前に実行します。そして非同期読み込みではDOMの解析は中断されません。body要素内でasyncもしくはdefer属性を使用しても同じ挙動をします。

<head>
    <script src="async.js" async></script>
    <script src="defer.js" defer></script>
</head>

上記4パターンのDOM解析への影響はこのようになります。

読み込み方法 記述位置と属性 DOM解析
同期 head 中断する
body末尾 中断しない
非同期 head async 中断しない
head defer 中断しない

body末尾以外での同期読み込み、つまりここではhead要素内での同期読み込みだけがDOMの解析を中断してしまうので、基本的に他の方法で読み込むようにします。
たとえばですが、読み込み後すぐに実行する必要があるプログラムはasync属性を付けて読み込む。DOMを操作するプログラムの場合はbodyの末尾もしくはdefer属性を付けて読み込む。など読み込み方法はプログラムの処理に合わせて選択します。

CSS

使用していないスタイルの削除

ページの修正などによって使用しなくなったスタイルが残っていると、読み込みが遅くなってしまいます。これはテキストデータの容量分ムダがあるだけでなく、スタイルの解析に時間を取られてしまうからです。
基本的なことですが、CSSに限らず必要ないものは削除しておきましょう。

CSSの遅延読み込み

CSSの解析はファイルの始めから終わりまで一気に行われます。この時ブラウザはCSSの解析が終わるまでページを表示しません。ということはファーストビューに必要ないCSSの解析も行われているので、そのために待ち時間が発生しています。この問題を解決するには2つ手順を踏みます。

  • ファーストビューに必要なものだけスタイルシートから抜き出して、HTML内にインラインで記述。
  • スタイルシートをファーストビューの表示が終わってから読み込む。

具体的には以下のように記述します。

<head>
    <style>
        /* ファーストビューのスタイルを記述 */
    </style>

    <script>

        const loadStyle = function(){
            const link = document.createElement("link");// link要素を生成
            link.rel = "stylesheet";// rel属性を指定
            link.href = "./css/style.css";// href属性にCSSのパスを指定
            document.head.appendChild(link);// head要素内に、生成したlink要素を追加
        }

        // DOMの解析が終わったらCSSを読み込む関数を実行
        window.addEventListener("DOMContentLoaded", loadStyle);

    </script>
</head>

このようにすることでファーストビューの表示に必要ないスタイルの解析を後回しにできます。

おわりに

今回はHTML・CSSの2つに絞って、表示を速くする(遅くしない)方法をご紹介いたしました。一番効果がわかりやすいのは画像に関するもので、他のものはあまり効果がわからないかもしれません。ですが効果の大小にかかわらず遅くなる可能性を潰しながら制作を進めることで、ムダのない高速なサイトに近づけると思います。
どれも難しいことではないので、サイト制作をするにあたって参考にしてみてください。