How to use responsive images with Pug

For responsive images is recommended to use the responsive-loader. This is a very fast, high-quality and powerful module.

Setup

Firstly, install and configure the pug-plugin, then install modules:

npm install responsive-loader sharp --save-dev

Add to Webpack module rules the following configuration:

{
  test: /\.(gif|png|jpe?g|svg|webp)$/i,
  type: 'asset/resource',
  use: {
    loader: 'responsive-loader',
    options: {
      // output filename of images
      name: 'assets/img/[name].[hash:8]-[width]w.[ext]',
    },
  },
},
Note:

Usage of image with fixed size

Defaults, an image without queries will stay in its original size and format.

To resize an single image use the size query parameter:

img(src='./image.jpg?size=200')

To convert an image in other format, e.g. webp, use the format query parameter:

img(src='./image.jpg?size=200&format=webp')

Usage of the image in SCSS as the background-image:

.image {
  background-image: url('./image.jpg?size=200');
}

Examples

fix image
img(src='./image.webp?size=100')
fix image
img(src='./image.webp?size=120&format=png')
fix image
img(src='./image.webp?size=140&format=jpg')
// scss
$width: 200;
$height: 145;
.demo-image {
  width: #{$width}px;
  height: #{$height}px;
  background-image: url('./image.jpg?size=#{$width}');
}

Usage of responsive image

For a responsive image use the sizes[] query parameter.
For the readability of your code, define the image object in a JS context, like so:

-
  const responsiveImage = {
    // default image
    src: require('./image.jpg?size=640'),
    // responsive images
    srcSet: require('./image.jpg?sizes[]=480,sizes[]=640,sizes[]=800,sizes[]=1024,sizes[]=1450,sizes[]=1920'),
  }

Note: the require('./image.jpg?sizes[]=480,sizes[]=640,...') in Pug returns directly a string with a comma-separated list of images.

Then set the srcset and src image attributes:

img(src=responsiveImage.src srcset=responsiveImage.srcSet alt="responsive image")

Generated HTML of responsive image:

<img src="/assets/images/image.af5d288cf6d0be8269fb6785de4dca47-640w.jpg.jpg"
  srcset="/assets/images/image.c89a9aadd767f562f8cea83cf8d31b90-480w.jpg 480w,
    /assets/images/image.af5d288cf6d0be8269fb6785de4dca47-640w.jpg 640w,
    /assets/images/image.39668d49ebd9fba351e0df395b762f30-800w.jpg 800w,
    /assets/images/image.1b62e4707c5462a41627051bc4b26d54-1024w.jpg 1024w,
    /assets/images/image.1c1d5de33673303eacdfa27b9b7b6e00-1450w.jpg 1450w,
    /assets/images/image.c62bf05c4abc346d0239e964ab096228-1920w.jpg 1920w">

Usage of responsive image with placeholder

When the connection speed is low, the background is blank while loading a full size image. In this case, we can show a very small version of the image as background-image before the original image is fully loaded. The original image must be wrapped in a div container with an inline background image - placeholder.

To generate a placeholder as inline data URL use the following query parameters:

For example we have an header with responsive image. The image has the width 100% and fixed height 300px.

Using the object responsiveImage (see above) write in Pug:
.box: img(src=responsiveImage.src srcset=responsiveImage.srcSet alt="responsive image")
SCSS:
$imgHeight: 300px; // fixed height of the image in header

.box {
  width: 100%;
  height: $imgHeight;
  max-height: $imgHeight;
  overflow: hidden;
  background-size: cover; // fit image with aspect ratio in the content box

  // placeholder of responsive image as inline data URL
  background-image: url('./image.jpg?prop=placeholder&placeholder=true&placeholderSize=100');

  // responsive image
  img {
    width: 100%;
    height: 100%;
    object-fit: cover; // fit image with aspect ratio in the content box
  }
}
The result of the responsive image you can see in the header of this site.

Other way to set the placeholder is to use it in the style property as the background-image: url(...).
- const placeholder = require('./image.jpg?prop=placeholder&emitFile=false&placeholder=true&placeholderSize=35')
- const width = 200
- const height = require("./image.jpg?prop=height&emitFile=false&size=" + width)
.box(style=`background-image: url(${placeholder}); width:${width}px; height:${height}px; background-size:cover;`)
Note: Don't use require() directly in the style property, the image file will not be resolved.

The generated HTML:
<div class="box"
     style="background-image: url(data:image/jpeg;base64,...); width:200px; height:110px; background-size:cover;">

What you see in the browser:

Extract property

To extract any single property from the responsible-loader processing result, use the prop=PROP_NAME query parameter.
Supported properties: srcSet src width height and placeholder.
For example:
p srcSet: #{require("./image.jpg?prop=srcSet&format=webp&sizes[]=100,sizes[]=200,sizes[]=300")}
p src webp: #{require("./image.jpg?prop=src&format=webp&size=200")}
p placeholder: #{require("./image.jpg?prop=placeholder&emitFile=false&placeholder=true&placeholderSize=50")}
p width of original image size: #{require("./image.jpg?prop=width&emitFile=false")}
p height of resised image: #{require("./image.jpg?prop=height&size=200")}

Notes