レスポンシブ Web デザインは、現代の Web サイトや Web アプリケーションの標準となり、さまざまなデバイス間で一貫したエクスペリエンスを提供すると同時に、各デバイスの表示を最適化します。 ただし、最近のデバイスは画面サイズだけでなくピクセル密度も異なります。 HTML5 img
タグには、サーバーが複数のバリエーションを提供する場合にブラウザが最も適切なアセットを選択できるようにするさまざまな機能が用意されています。 ウェブサイトが同じ画像の複数の異なるサイズを展開する場合、ウェブブラウザは現在の環境に最適なサイズを選択できます。
したがって、レスポンシブ イメージを使用すると、Web ブラウザーはデザイナーの意図に近いレンダリングを生成できるようになります。 これによりユーザー エクスペリエンスは向上しますが、デフォルトのイメージに加えて多数のイメージ アセットのバリエーションを作成して展開する必要があるため、開発チームと運用チームには追加の負担がかかります。
このブログ記事では、NGINX および NGINX Plus のImage‑Filter モジュールを使用して、無数のイメージアセットのバリエーションを作成および管理する手間をかけずにレスポンシブなイメージを配信する方法を紹介します。代わりに、NGINX または NGINX Plus がオンザフライでサイズを変更する各イメージの単一の「ソース」バージョンをデプロイできます。 この記事の情報は、NGINX Open Source と NGINX Plus の両方に適用されます ( Image‑Filter モジュールのインストールの個別の手順を除く)。簡潔にするために、全体を通じて NGINX Plus について言及します。
srcset
属性レスポンシブな画像を配信するための主なツールは、HTML5 img
タグのsrcset
属性です。 これを使用して、さまざまなピクセル密度とビューポート サイズの画像アセット バリアントの数を指定できます。 ビューポートとは、デスクトップ上のウィンドウやモバイル デバイス上の全画面アプリなど、Web ブラウザーで使用できる表示スペースの総称です。
次の例では、 src
属性はsrcset
属性をサポートしていないブラウザのデフォルト画像を定義し、 srcset
属性は 2 つのバリアントを指定します。1 つは標準ピクセル密度のディスプレイ用 ( 1x
)、もう 1 つは Apple Retina™ ディスプレイや一部の 4K モニターなどの 2 倍ピクセル密度のディスプレイ用 ( 2x
) です。
< img src= "/images/mylogo-default.png" srcset= "/images/mylogo-density1.png 1x、/images/mylogo-density2.png 2x" >
次のより洗練された例では、ビューポートの幅に応じて、表示する画像アセットのバリアントの数を定義します。 sizes
属性は、ビューポートの幅が10em
より大きい場合はブラウザがビューポートの半分に画像をレンダリングし、それ以外の場合はビューポート全体を使用することを指定します。 ブラウザは、画像に使用できるスペースの量を判断し、使用可能なスペースに最適な画像アセットバリアントを選択します。通常、次の幅 ( w
サフィックス) に「切り上げ」、スペースを正確に埋めるように内部的に画像のサイズを変更します。
< img src= "/images/racecar-default.jpg" sizes= "(最小幅: 10em) 50vw、100vw" srcset= "/images/racecar-100px.jpg 100w、/images/racecar-225px.jpg 225w、/images/racecar-450px.jpg 450w、/images/racecar-675px.jpg 675w" >
さまざまな画像アセットのバリエーションを指定してレスポンシブな画像を配信するこのアプローチは、コーディングが簡単で非常に効果的です。 ただし、イメージバリアント自体の作成と管理に関しては課題があります。 制作前に大量のイメージのサイズ変更を行い、サーバー上に大量のファイルを展開する必要があります。 各バリアントの最適な数とサイズを微調整するには時間がかかり、各画像アセット バリアントがアクセス可能であるかどうかをテストすることが困難になります。
srcset
属性やレスポンシブ画像のその他のテクニックの詳細については、こちらの優れたブログ投稿をご覧ください。
Image‑Filter モジュールを取得する手順は、NGINX Plus と NGINX で異なります。
Image‑Filter モジュールは、NGINX Plus サブスクライバー向けの無料の動的モジュールとして利用できます。
NGINX Plus リポジトリからモジュール自体をインストールして入手します。
Ubuntu および Debian システムの場合:
$ sudo apt-get で nginx-plus-module-image-filter をインストールします
RedHat、CentOS、Oracle Linux システムの場合:
$ sudo yum インストール nginx-plus-module-image-filter
モジュールを有効にするには、 nginx.conf構成ファイルの最上位 (「main」) コンテキスト (つまり、 http
またはstream
コンテキストではない) にload_module
ディレクティブを含めます。
モジュールモジュール/ngx_http_image_filter_module.so をロードします。
NGINX Plus をリロードして、実行中のインスタンスに Image‑Filter モジュールをロードします。
$ sudo nginx -s リロード>
Image‑Filter モジュールをインストールする最も簡単な方法は、公式の NGINX リポジトリから入手することです。 次の手順に従って、システムが公式 NGINX リポジトリにアクセスするように構成し、オペレーティング システムのパッケージ マネージャーを使用してインストールします。
Ubuntu および Debian システムの場合:
$ sudo apt-get install nginx-module-image-filter
Red Hat、CentOS、Oracle Linux システムの場合:
$ sudo yum インストール nginx-module-image-filter
インストールが完了したら、 「NGINX Plus 用イメージ フィルター モジュールのインストール」の手順 2 と 3 に従って、NGINX を設定してリロードします。
Image‑Filter モジュールをソースからコンパイルし、静的にコンパイルされたモジュールまたは動的モジュールとしてロードすることもできます。 詳細については、 NGINX Plus 管理者ガイドを参照してください。
Image‑Filter モジュールを使用すると、各イメージの単一の「ソース」バージョンを作成してデプロイし、NGINX Plus でそのイメージをオンザフライでサイズ変更して、ブラウザーから要求されたサイズのバリエーションを提供できます。 手動でサイズを変更したり、Web サーバーに画像を展開したりすることなく、HTML ソース内でレスポンシブ Web ページと画像を完全に微調整できます。
このサンプル HTML ファイルでは、ピクセル密度の異なるデバイス用に 4 つの画像バリアントを定義します。
< html > < head > < title >レスポンシブ ロゴ title > head > < body > < h2 >ピクセル密度に基づくロゴの選択 h2 > < img src= "/img400/mylogo.png" srcset= "/img400/mylogo.png 1x, /img800/mylogo.png 2x, /img1200/mylogo.png 3x, /img1600/mylogo.png 4x" > body > html >
/img400 、 /img800 、 /img1200 、 /img1600ディレクトリは実際には存在しません。 代わりに、次の NGINX Plus 構成は、 /imgで始まるアセットのリクエストを照合し、元のファイル名 (たとえば、前述の HTML のmylogo.png ) でイメージのサイズを変更するリクエストに変換します。
サーバー { listen 80;
root /var/www/public_html;
location ~ ^/img([0-9]+)(?:/(.*))?$ {
alias /var/www/source_images/$2;
image_filter_buffer 10M;
image_filter resize $1 -;
}
}
サーバー
ブロックは、NGINX Plus が受信 HTTP リクエストを処理する方法を定義します。 listen
ディレクティブは、NGINX Plus に、HTTP トラフィックのデフォルトであるポート 80 でリッスンするように指示します。 ルート
ディレクティブは、この Web サイトのディスク上の場所を指定します。 この単純な例では、NGINX Plus でホストされている静的 Web サイトを使用していますが、NGINX Plus が動的コンテンツのリバース プロキシや FastCGI などのアプリケーション コネクタとして機能することも一般的です。これらすべてのユース ケースでは、ここで説明するように、ソース イメージを NGINX Plus サーバーにデプロイすることで、Image‑Filter モジュールを活用できます。
ロケーション
ブロックは正規表現を使用して、 /imgで始まり、その後に 1 つ以上の数字が続くディレクトリに保存されているアセットのリクエストを照合します。 数字は変数$1
としてキャプチャされ、それに続くファイル名は変数$2
としてキャプチャされます。 次に、エイリアス
ディレクティブを使用して、ソース イメージを含むディスク上のディレクトリからこの要求に応えます。 このディレクトリはルート
パスの下にはないため、クライアントはソース イメージを直接要求できないことに注意してください。
ソース イメージは非常に大きく、幅が数千ピクセルになる可能性があるため、Image‑Filter モジュールがイメージを読み込んでサイズを変更するのに十分なメモリを割り当てるようにする必要があります。 この例では、 image_filter_buffer
ディレクティブを使用して、最大 10 MB のサイズの画像ファイルをサポートします。
最後に、 image_filter
ディレクティブは、Image‑Filter モジュールに、 /imgディレクトリ名のサフィックスからキャプチャされた幅にソース イメージのサイズを変更するように指示します。 ダッシュ (‑) は、NGINX Plus にソース イメージのアスペクト比を維持するように指示します。
「画像サイズとピクセル密度の一致」で説明されている構成では、画像のリクエストに使用されるディレクトリ名に応じて、画像の任意のサイズのバリエーションを配信できます。 ただし、実稼働環境では、リクエストごとに Web サーバーが画像のサイズを変更するのを待つ必要はありません。 これは全体的なレイテンシには良くなく、CPU オーバーヘッドも大幅に増加する可能性があります。
最も効果的な解決策は、サイズ変更された画像バリアントをキャッシュして、各バリアントの後続のリクエストが Image‑Filter モジュールを経由せずにキャッシュから提供されるようにすることです。 NGINX Plus 構成では、イメージのサイズ変更を実行する別の仮想サーバーを定義し、要求されたイメージ サイズがキャッシュにまだ存在しない場合にのみ、そのサーバーに要求をプロキシすることで、これを実現できます。 これをレスポンシブイメージサーバーと呼びます。
また、任意のリクエストによる画像サイズ変更操作を許可することによるセキュリティ上の影響も考慮する必要があります。 キャッシュを構成しても、攻撃者が/img1001/mylogo.png 、 /img1002/mylogo.png 、 /img1003/mylogo.pngなどの一意の画像アセットバリアントに高速でリクエストを送信した場合には役に立ちません。 このような攻撃は、リクエストの量が比較的少ない場合でも、CPU 使用率が過度に高くなるため、サービス拒否 (DoS) を引き起こす可能性があります。 この問題に対処するために、レスポンシブ イメージ サーバーにレート制限を適用しますが、キャッシュされたバリアントを含むフロントエンド サーバーにはレート制限を適用しません。 次の構成は、イメージ フィルター モジュールにキャッシュとレート制限を適用することで、 「イメージ サイズとピクセル密度の一致」の構成を拡張します。
proxy_cache_path /var/www/imgcache levels=1 keys_zone=resized:1m max_size=256m;
server {
listen 80;
root /var/www/public_html;
location ~ ^/img([0-9]+)(?:/(.*))?$ {
proxy_pass http://127.0.0.1:9001;
proxy_cache resized;
proxy_cache_valid 180m;
}
}
limit_req_zone "1" zone=2persec:32k rate=2r/s;
server {
listen 9001;
allow 127.0.0.1;
deny all;
limit_req zone=2persec burst=10;
場所 ~ ^/img([0-9]+)(?:/(.*))?$ {
alias /var/www/source_images/$2;
image_filter_buffer 10M;
image_filter resize $1 -;
}
}
まず、 proxy_cache_path
ディレクティブを使用してキャッシュされた画像の場所を定義します。 keys_zone
パラメータは、キャッシュ インデックスの共有メモリ ゾーン ( resized
と呼ばれる) を定義し、1 MB を割り当てます。これは、約 8,000 個のサイズ変更されたイメージに十分なサイズです。 max_size
パラメータは、NGINX Plus が新しいキャッシュ項目のためのスペースを確保するために、キャッシュから最も最近リクエストされていないイメージを削除し始めるポイントを定義します。
フロントエンド Web サーバー (ポート 80 でリッスンしているサーバー) のlocation
ディレクティブは、 proxy_pass
ディレクティブを使用して、 /imgで始まるリクエストを内部でホストされているレスポンシブ イメージ サーバー (127.0.0.1:9001) に送信します。 proxy_cache
ディレクティブは、レスポンシブ イメージ サーバーからの応答を保存するために使用するキャッシュの名前 ( resized
) を指定することにより、この場所のキャッシュを有効にします。 proxy_cache_valid
ディレクティブは、サイズ変更された画像が少なくとも 180 分間キャッシュに保持されること (キャッシュがmax_size
を超え、最も最近要求されたものでない限り)、および応答画像サーバーからの誤った応答がキャッシュされないことを保証します。
キャッシュの詳細な説明については、 「NGINX および NGINX Plus を使用したキャッシュのガイド」を参照してください。
レスポンシブ イメージ サーバー自体を定義する前に、 limit_req_zone
ディレクティブを使用してレート制限を指定します。 ディレクティブ自体はレート制限を強制しません。1 秒あたり 2 リクエストのレート制限を定義し、サーバー
ブロックにlimit_req
ディレクティブを含めることで、レスポンシブ イメージ サーバーに適用されます (次の段落を参照)。 通常、レート制限はリクエストの属性に対してキー設定されますが、この場合は、制限がすべてのリクエスト元に適用されるように、静的キー値「1」
を指定します。 キーの基数は 1 に固定されているため、共有メモリ ゾーンのサイズを可能な限り小さい値である 3 KB に設定します。
レスポンシブ イメージ サーバーのサーバー
ブロックはポート 9001 でリッスンします。 ローカルホスト (フロントエンド Web サーバー) のみがレスポンシブ イメージ サーバーに接続できるように指定するために、 allow
ディレクティブとdeny
ディレクティブを含めます。 次に、 limit_req
ディレクティブを追加して、以前に定義したレート制限を適用します。バースト
パラメータは、レート制限を適用する前に 10 件の同時リクエストを許可します。 レート制限が有効になると、超過リクエストは制限内で処理できるようになるまで遅延されます。
ロケーション
ブロックは、画像サイズとピクセル密度の一致のブロックと同じですが、要求された画像がキャッシュ内に存在せず、レート制限を超えていない場合にのみ実行されます。
この基本構成では、単一の NGINX Plus インスタンスがフロントエンド Web サーバーとレスポンシブ イメージ サーバーの両方として機能します。 画像処理は計算負荷が非常に高くなる可能性があり、非常に高いワークロードにつながり、NGINX Plus が DoS 攻撃の対象になる可能性があります。 すべてのワーカープロセスがイメージのサイズ変更リクエストでビジー状態になっているためにフロントエンド Web サーバーが新しいリクエストをすぐに受け入れることができない状況を回避するには、イメージ処理専用の別の NGINX Plus インスタンスを実行することをお勧めします。 これにより、フロントエンド Web サーバーのワーカー プロセスが、画像処理を実行するワーカー プロセスから分離されます。 同じホスト上で NGINX Plus の別のインスタンスを実行するには、コマンドラインで別の設定ファイルを指定します。
$ sudo nginx -c /etc/nginx/resize-server.conf
レスポンシブ画像の動作を確認する最も効果的な方法は、ビューポートのサイズが変化すると、ブラウザがどのsrcset
画像バリアントを使用するかを決定する様子を観察することです。 以下はシンプルな画像ギャラリーの HTML ソースです。 デモンストレーションの目的で、画像ごとにサイズのバリエーションが若干異なり、ブラウザーが別のバリエーションを選択できる「ブレークポイント」が多数作成されることに注意してください。
<!DOCTYPE html>
<html>
<頭>
<タイトル>レスポンシブ画像ギャラリー</タイトル>
</頭>
<体>
<h2>レスポンシブ画像ギャラリー</h2>
<画像 ソース=「/img100/1-ドミノ.jpg」 サイズ="(最小幅: 20em) 40vw, 100vw" srcset= "/img110/1-dominos.jpg 110w, /img210/1-dominos.jpg 210w, /img310/1-dominos.jpg 310w, /img410/1-dominos.jpg 410w, /img510/1-dominos.jpg 510w, /img610/1-dominos.jpg 610w" > < img src= "/img100/2-sign.jpg" sizes= "(最小幅: 20em) 40vw、100vw" srcset= "/img120/2-sign.jpg 120w、/img220/2-sign.jpg 220w、/img330/2-sign.jpg 330w、/img420/2-sign.jpg 420w、/img520/2-sign.jpg 520w、/img620/2-sign.jpg 620w" > < img src= "/img100/3-thruppence.jpg" sizes= "(最小幅: 20em) 40vw, 100vw" srcset= "/img130/3-thruppence.jpg 130w, /img230/3-thruppence.jpg 230w, /img330/3-thruppence.jpg 330w, /img440/3-thruppence.jpg 440w, /img550/3-thruppence.jpg 550w, /img660/3-thruppence.jpg 660w" > < img src= "/img100/4-aces.jpg" sizes= "(最小幅: 20em) 40vw、100vw" srcset= "/img140/4-aces.jpg 140w、/img240/4-aces.jpg 240w、/img340/4-aces.jpg 340w、/img440/4-aces.jpg 440w、/img540/4-aces.jpg 540w、/img640/4-aces.jpg 640w" > body > html >
以下のスクリーンショットは、Chrome ブラウザでインスペクタの[ネットワーク]タブを開いたときのこの Web ページの内容を示しています。 名前列には、サーバーから要求された各画像バリアントのパスが表示されます。これにより、Web サーバーのログを確認しなくても、選択されたサイズを確認できます。
図 2 の狭いビューポートでは、ブラウザーは幅 220 ~ 310 ピクセルの画像を選択しました ( [名前] 列の/imgディレクトリ名の数値サフィックスは、これらの値の範囲内です)。
図 3 でブラウザ ウィンドウを広げると、ブラウザは幅 440 ~ 540 ピクセルの画像 (リストの最後の 4 つの画像) を選択します。 これらのイメージのイニシエーター列の値はOtherです。
NGINX Plus と Image‑Filter モジュールを使用すると、現在のブラウザの状況に最適な画像サイズを提供できます。 また、制作前の画像のサイズ変更、バッチ処理、ディスク上の何百もの画像アセットのバリエーションの管理を行うことなく、これを実現できます。 NGINX Plus が完璧なアプリケーション配信を実現するのに役立つもう 1 つの方法です。
NGINX Plus でレスポンシブ イメージをぜひお試しください。今すぐ30 日間の無料トライアルを開始するか、弊社にお問い合わせの上、ユースケースについてご相談ください。
「このブログ投稿には、入手できなくなった製品やサポートされなくなった製品が参照されている場合があります。 利用可能な F5 NGINX 製品およびソリューションに関する最新情報については、 NGINX 製品ファミリーをご覧ください。 NGINX は現在 F5 の一部です。 以前の NGINX.com リンクはすべて、F5.com の同様の NGINX コンテンツにリダイレクトされます。"