JekyllRubyGems で配布されている Ruby 製の静的サイト生成ツールです。 このブログも Jekyll を使用しています。

Jekyll での使用を想定した画像の遅延ロードため jekyll-lazy-load-image という RubyGems を作成しました。

今回は作成の意図とその使い方などを備忘として記載していこうと思います。

ライブラリ作成のモチベーション

重い画像があるとレンダリングが遅い

通常、ブラウザにおける HTML のページレンダリング時の画像の読み込みは、 レンダリングをブロック、つまり同期的に行います。

<!doctype html>
<html>
  <head>
    <script type="text/javascript" charset="utf-8" src="path/to/javascript"></script>
    <link rel="stylesheet" href="path/to/css">
  </head>
  <body>
    <img src="path/to/image">
  </body>
</html>

上記の HTML がブラウザでレンダリングされる場合、

  1. HTML をリクエスト
  2. HTML の取得
  3. HTML の DOM 生成
    1. path/to/javascript の JavaScript をリクエスト
    2. path/to/css の CSS をリクエスト
    3. path/to/image の 画像をリクエスト
  4. ページレンダリング完了

という挙動をします。

もし path/to/image が重いファイルだった場合、「ページレンダリング完了」までに時間がかかってしまいます。

一つの解決方法として img タグの src 属性にダミー画像やロード中の画像を指定しつつ、 JavaScript を使用して画像を非同期で読み込むことでページレンダリングをブロックしないようにすることができます。

たまたまこのブログで少々重めの gif を表示したいことがあり、体感的にレンダリングが遅かったため、非同期で画像を読み込みたいと考えました。

RubyGems に切り出すという選択

Jekyll のプロジェクトでは _plugins ディレクトリにファイルを設置することで、 自作の Jekyll Plugin を作成および導入が可能です。

しかし、 _plugins に設置する自作の Jekyll Plugin は、中々テストが書かれることがありません。

RubyGems に切り出せば、テストを記載するだろうと思い、切り出すことにしました。

ライブラリの作成方針

jekyll-lazy-load-image を作成する際に、以下のようなことを気にして作成を行いました。

Jekyll における画像非同期読み込みの課題

Jekyll ではしばしば HTML をそのまま記載するのではなく Markdown など別のファイルフォーマットで記載されたドキュメントを使用して静的サイトを生成します。 そのため、HTML 以外のファイルフォーマットで記載されたドキュメントを Jekyll のコンバーターでの処理が終わった後に img タグを変更する必要があります。

Jekyll の拡張の選択

Jekyll には拡張をするための機構が

の 5 つ用意されています。

今回は Jekyll のコンバーターの処理が終わったドキュメントに対して変更を行いたいため、「Hooks」を使用します。

Hooks にはドキュメントをレンダリングした後、静的 HTML を出力する前に呼び出される :post_render があります。 こちらを使用して生成された HTML を変更する方法を選択しました。

依存の最小化

RubyGems を作成する際には、依存するライブラリを選択することができます。 今回はなるべく軽量で汎用性が高いように作成したかったため、依存するライブラリを極力少なくすることにしました。

よくやりがちな、とりあえず ActiveSupport を入れるみたいなことを避けて、本当に必要なライブラリだけを利用することにしました。

もちろん、ActiveSupoort はとても便利です。 よく使われるメソッドや拡張が数多く用意されていて、かつテストが書かれているというのはとても魅力的です。

今回は HTML の編集と Jekyll の Hooks を使用するため、

の 2 つのみを依存に含めました。

設定項目の最小化

RubyGems へ切り出したため、様々なユーザーを想定しました。 特に Jekyll を使用しているサイトの作成者は、Jekyll や Ruby に詳しい人ばかりとは限りません。 細かい設定などは逆に使用者に負担をかける可能性があります。

そのため、最低限動作するに設計しました。 具体的には _config.ymlGemfile の変更と使用する JavaScript の追加のみで動作するようにしました。

遅延ロードの JavaScript の処遇

細かい設定を少なくすると言ったわりには、 jekyll-lazy-load-image では遅延ロードの JavaScript を使用者で設定してもらうようにしています。

Jekyll の Tags 拡張を使用することで遅延ロードの JavaScript の呼び出しを簡略化することも検討しましたが、 こと JavaScript に関してはサイトに寄って呼び出し方法がまちまちであるため、むやみに呼び出しを強制してしまうのは逆にライブラリとして使用されづらくなるのではないかと考え、このような形にすることにしました。

個別呼び出しへの対応

設定項目を最小化することで、 Jekyll や Ruby に詳しくない方でもすぐに効果が現れるようにしました。

もちろん Jekyll や Ruby に詳しい方もいるため、その人達用にメソッドを個別に呼び出せるようにしてカスタマイズできるようにしようと考えました。

メインとなる img タグの src 属性の変更に関しては個別でも呼び出せるように設計をしました。 しかし、まだ不十分な部分もあるため、 Issue としてタスクに積み、改善を行う予定です。

jekyll-lazy-load-image の使い方

カスタマイズせずに動かす

Gemfile の設定

Jekyll のプロジェクトの Gemfile に以下を追加します。

group :jekyll_plugins do
  gem 'jekyll-lazy-load-image', require: 'jekyll-lazy-load-image/auto-execution'
end

gem 'jekyll-lazy-load-image' のみでは拡張用に処理は走らないようになっており、 require: 'jekyll-lazy-load-image/auto-execution' を付与することで、自動で処理が走るようになります。

遅延ロードのライブラリの設定

遅延ロードライブラリはお好きなものを使用して構いませんが、

辺りが良いかもしれません。

Jekyll のプロジェクトのアセットに追加ソースを追加する、または CDN を指定を読み込むなどを行い、遅延ロードライブラリを読み込ませます。

例として lazysizes を CDN で読み込ませる場合は、テンプレートの任意の場所に

<script src="//cdnjs.cloudflare.com/ajax/libs/lazysizes/4.0.4/lazysizes.min.js" async></script>

を追加すれば完了です。

_config.yml の設定

Jekyll のプロジェクトの _config.yml に、このライブラリで使用する設定を以下のように記載します。

lazy_load_image:
  src_attr_name: data-src
  preload_image: /path/to/image
  class_attr_values:
    - lazyload
  ignore_selectors:
    - ".ignore-lazy-image-load"
  additional_attrs:
    "data-size": auto

各設定の内容は以下です。使用する遅延ロードライブラリに合わせて設定を行ってください。

設定名 必須 内容
src_attr_name required img タグの src 属性の代わりに設定する属性名
preload_image optional 画像のロードが終わるまでに表示させる内容、つまり img タグの src 属性にデフォルトで設定する内容
class_attr_values optional img タグの class 属性に追加で付与する値(複数指定可能)
ignore_selectors optional 処理を除外する対象のセレクタ(css または xpath で複数指定可能)
additional_attrs optional 追加で img タグに設定したい属性名と値の組み合わせ

カスタマイズして動かす

処理を実行するタイミングやコンテナの種類を変えることができます。 遅延ロードライブラリの設定は共通であるため省略します。

Gemfile の設定

Jekyll のプロジェクトの Gemfile に以下を追加します。

gem 'jekyll-lazy-load-image'

_plugins ディレクトリへファイルの追加

ドキュメントに対して処理を行いたいとした場合は、 _plugins ディレクトリに

require 'jekyll-lazy-load-image'

JekyllLazyLoadImage.configure do |config|
  config.owners = :documents
end

JekyllLazyLoadImage.execute

上記のようなファイルを任意の名前で追加することで実現することができます。

まとめ

今回は Jekyll で作成するサイトに対して画像を遅延ロードの設定を施すライブラリの作成についてと、その使い方について記載しました。 少しでも同じ課題を持っている方の助けになれば幸いです。

また、今回作成した jekyll-lazy-load-image は、ある程度考えて設計したものの、実際使用してみると使いづらい点などがあるかと思います。 OSS として公開しているので、是非 IssuePull Request いただければと思います。