画像を表示するのに、Pug ミックスイン +img
を使います。
+img({ src: '/assets/img/ページ名/pc/1x/example_1.png', alt: 'altテキスト' })
実装手順
画像の書き出し
弊社では、デザイナーが Photoshop で書き出しが必要なすべてのレイヤーの名前に example.png
のようなファイル名を付けるルールになっています。
そうすることで、画像アセットの機能を使ってすべての画像を自動で書き出せるようになります。なので、エンジニアがいちいちファイル名を決めてリネームする必要はありません。
画像アセットのデフォルト設定として、PC 用 PSD では default 200% 2x/@2x, 1x/
、スマートフォン(以下 SP)用 PSD では default 100% 2x/@2x, 50% 1x/
(PC 用 PSD のデザインは等倍だが、SP 用は 2 倍サイズで作成しているため)としているので、書き出された画像は以下のようになります。
├── 1x
│ ├── example_1.png
│ └── example_2.png
└── 2x
├── example_1@2x.png
└── example_2@2x.png
├── 1x
│ ├── example_1.png
│ └── example_2.png
└── 2x
├── example_1@2x.png
└── example_2@2x.png
src
ディレクトリに画像を配置
以下のように、src/www/assets/img
ディレクトリ内に書き出した画像を配置します。
ページ名
(名前は任意)ディレクトリやpc
,sp
ディレクトリは手動で作成しますが、それ以下は画像アセットで生成されたディレクトリ構造のまま配置するだけです。
src/www/assets/img
└── ページ名
├── pc
│ ├── 1x
│ │ ├── example_1.png
│ │ └── example_2.png
│ └── 2x
│ ├── example_1@2x.png
│ └── example_2@2x.png
└── sp
├── 1x
│ ├── example_1.png
│ └── example_2.png
└── 2x
├── example_1@2x.png
└── example_2@2x.png
ちなみに、example_1.png
の画像に関連するファイルは以下の 4 つとなります。
├── pc
│ ├── 1x
│ │ └── example_1.png
│ └── 2x
│ └── example_1@2x.png
└── sp
├── 1x
│ └── example_1.png
└── 2x
└── example_1@2x.png
Pug で記述
+img({ src: '/assets/img/ページ名/pc/1x/example_1.png', alt: 'altテキスト' }).example
+img
ミックスインを使い、引数オブジェクト(オプション)のsrc
プロパティにPC 用の等倍画像のパスだけ指定すれば、それに関連する画像をすべて自動で取得し、以下のように<picture>
タグに展開してあらゆる環境に対応した状態で出力されます。
<picture>
<source srcset="/assets/img/ページ名/sp/1x/example_1.png.webp 1x,/assets/img/ページ名/sp/2x/example_1@2x.png.webp 2x" type="image/webp" media="(max-width: 767px)">
<source srcset="/assets/img/ページ名/pc/1x/example_1.png.webp 1x,/assets/img/ページ名/pc/2x/example_1@2x.png.webp 2x" type="image/webp">
<source srcset="/assets/img/ページ名/sp/1x/example_1.png 1x,/assets/img/ページ名/sp/2x/example_1@2x.png 2x" media="(max-width: 767px)">
<img srcset="/assets/img/ページ名/pc/1x/example_1.png 1x,/assets/img/ページ名/pc/2x/example_1@2x.png 2x" src="/assets/img/ページ名/pc/1x/example_1.png" alt="altテキスト" width="923" height="511" loading="lazy" class="example">
</picture>
以下のコードはすべて自動で出力されます。
- 画像と同じサイズ指定する
width
,height
属性 - 等倍/2 倍の画像を切り替える
srcset
属性 - PC/SP の画像を切り替える
media
属性 - WebP/通常画像を切り替える
type="image/webp"
属性 - 遅延読み込みさせる
loading="lazy"
属性
以降の章でそれぞれ詳しく説明します。
width
,height
属性
<img>
タグにwidth
, height
属性を付けるとレイアウトシフト[1]を防ぐことができますが、全部の<img>
タグに手動で付けるのは大変なので、自動化をしています。
まず、gulp-dataを使い、Node.js で定義したimageSize
関数を Pug ファイル内から使用できるようにします。
その関数内でimage-sizeを使い、画像ファイルのサイズを自動で取得して返します。
Gulp タスクの概要は以下のとおり。
const path = require('path');
const { src, dest } = require('gulp');
const gulpPug = require('gulp-pug');
const gulpData = require('gulp-data');
const imageSize = require('image-size');
const sourcePath = path.resolve(__dirname, 'src');
exports.default = function () {
return src(path.resolve(sourcePath, '**/*.pug'))
.pipe(
gulpData((file) => {
// file: 処理中のPugファイルに関する情報
// file.dirname: 処理中のPugファイルのあるディレクトリパス
return {
// imageSizeという名前の関数をPug内で使えるようにする
imageSize: (src) => {
// <img>タグのsrc属性のパスを基にファイルパスを生成する
const filePath = src.startsWith('/')
? path.resolve(sourcePath, src.slice(1)) // /から始まるルート相対パスの場合
: path.resolve(file.dirname, src); // 相対パスの場合
// ファイルパスに該当する画像ファイルのサイズをimage-sizeで取得し、返す
return imageSize(filePath);
},
};
})
)
.pipe(gulpPug())
.pipe(dest(path.resolve(__dirname, 'public')));
};
そうすることで、Pug 上ではimageSize
関数を使い画像パスを指定するだけでサイズを取得できます。
-
const size = imageSize(src) // gulp-dataで定義したimageSize関数
const width = size.width
const height = size.height
img(src=src, alt=alt, width=width, height=height)
また、PC と SP でアスペクト比の異なる画像を切り替えるとき、<img>
タグにwidth
,height
属性を付与しただけではスマホ表示時に SP 用画像が PC のアスペクト比で表示されてしまい表示が崩れてしまいますが、そうならないように<source>
タグに SP 画像サイズのwidth
,height
属性を付与することで、スマホでも正しいアスペクト比で画像を表示できます。
参考: source 要素に width/height 属性を指定して各画像のアスペクト比の維持と CLS の改善を図る
オプションでwidth
,height
を指定した場合はそちらが優先されるので、元の画像サイズとは異なるサイズを指定することもできます。
無効化
また、WYSIWYG 内の画像など一部の画像のみwidth
,height
属性の付与を無効にするには、+img
ミックスインのisDisableSize
オプションの値をtrue
にします。
+img({ src: 'example.png', isDisableSize: true })
参考:レイアウトシフトについて
srcset
属性)
解像度の切り替え(srcset
属性を使うとデバイスピクセル比によって描画する画像ファイルを変更できますが、それも自動化しています。
+img
ミックスインのsrc
オプションでは等倍(1x)用画像のみ指定するだけです。
パス内の/1x/
の文字列を/2x/
に置き換え、さらに画像アセットで 2 倍サイズの画像に付与される@2x
の文字の入ったパスの画像ファイルが存在すれば、自動でsrcset
属性を付与して出力します。(存在しなければタグが出力されないだけでエラーにはなりません)
{
// 指定したパスの画像ファイルが存在するかどうか
detectExistImage: (srcPath) => {
// image-sizeを流用し、置換したパスのファイルが正常に読み込めたらtrue、存在せずにエラーになったらfalseを返す
try {
imageSize(path.resolve(file.dirname, srcPath))
return true
} catch (error) {
return false
}
},
}
-
const src2x = src.replace('/1x/', '/2x/').replace(/(\.(png|jpg|jpeg|gif))$/, '@2x$1')
const isSrc2x = detectExistImage(src2x)
const srcset = isSrc2x
? `${srcFull} 1x,${src2xFull} 2x`
: null
attributes.srcset = srcset
無効化
CMS から出力する画像など一部の画像のみ無効にするには、+img
ミックスインのisDisableAutoDetect
オプションの値をtrue
にします。(※media
属性も無効になります。)
+img({ src: 'example.png', isDisableAutoDetect: true })
media
属性)
アートディレクション(PC/SP 画像は<source>
タグのmedia
属性によって切り替わります。
<source>
で切り替えることで、SP 表示のときは SP 用画像しか読み込まない(PC 用画像は読み込まれない)ので、読み込み速度改善に繋がります。
+img
ミックスインのsrc
オプションではPC 用画像のみ指定するだけでよく、srcset
属性同様、パス内の/pc/
の文字列を/sp/
に置き換えたパスの画像ファイルが存在すれば、自動で SP 用のmedia
属性の付いた<source>
タグが出力されます。
無効化
CMS から出力する画像など一部の画像のみ無効にするには、+img
ミックスインのisDisableAutoDetect
オプションの値をtrue
にします。(※srcset
属性も無効になります。)
+img({ src: 'example.png', isDisableAutoDetect: true })
また、PC(SP)のみ 2 倍画像を読み込まないようにしたい場合は、isDisable2xPc
(isDisable2xSp
)の値をtrue
にします。
+img({ src: 'example.png', isDisable2xPc: true })
type="image/webp"
属性)
WebP(読み込み速度改善のため、gulp-webpを使用し、src
ディレクトリ配下の画像ファイルはすべて自動で WebP 形式に変換しています。
ブラウザのサポート状態によって WebP と通常画像を出し分けるためのtype="image/webp"
属性の付いた<source>
タグも自動で出力します。
+img
ミックスインのsrc
オプションでは、.png
のような通常の画像拡張子を指定するだけで問題ありません(.webp
拡張子を指定する必要はありません)。
無効化
+img
のisWebp
オプションをfalse
にすると、そのタグのみ WebP を無効にして通常画像を表示できます。WebP 変換によって一部の画像の画質が落ちてしまった場合などは、個別に WebP を無効にします。
+img({ src: 'example.png', isWebp: false })
また、config/param.js
のenableWebP
の値を false にすると、全体の WebP 変換が無効になります。
loading="lazy"
属性)
Lazy loading(デフォルトでは遅延読み込みさせるloading="lazy"
属性(一部のブラウザのみサポート)が自動で付与されるようになっています。
無効化
ファーストビューの画像など一部の画像のみ無効にするには、+img
ミックスインのisDisableLazy
オプションの値をtrue
にします。
+img({ src: 'example.png', isDisableLazy: false })
すべての自動出力を無効にした場合は、シンプルな<img>
タグのみが出力されます。
このように、画像アセットと+img
ミックスインを利用し、パフォーマンス改善に繋がるコードの出力を自動化することで効率化をしています。