Roots Discourse

Responsive Theme Images

I’ve seen this topic brought up here before, but it’s never been answered. (Using LazySizes has nothing to do with it.)

Using Webpack and Sage, what’s the best way to automatically create responsive images (srcset) added to the theme images assets folder?

1 Like

Purely for themes, indeed the WordPress built-in thumbnail features wouldn’t be used.
For myself I have embraced the webpack responsive loader (official continuation fork can be found here).
The hardest part is the sizes attribute with proper absolute dimension to viewport dimension mappings.

There are cases though where a background image used with a element that contains CMS-content that can cause its height to change nondeterministic (text breaks are enough), here the JavaScript lazysizes library parent-fit plugin can be used. MutationObserver interface is widely supported and very usable for these problems. This can also be used of course with images in themes that come from the user (like the header image, cover block or theme option).

@strarsis Would you mind sharing the config file of your setup? I imagine it this all goes in Sage’s assets/build/ directory. Do I alter the webpack.config.optimize.js file?

Please note that this is for Sage 9 (no Laravel mixes used):

webpack.config.js:

module: {
    rules: [
      {
        test: /\.(jpe?g|png)$/i,
        use: [{
          loader: 'responsive-loader-webp',
          options: {
            adapter: require('responsive-loader-webp/sharp'),
            quality: 100, // (default)
            name: '[path][name]-[width].[ext]',
          },
        }],
      },

webpack.config.optimize.js:

plugins: [
    new ImageminPlugin({
      cacheFolder: resolve('./.cache'),
      test: '!images/layout/header*', // excludes header image (responsive-loader)
      optipng: {
        optimizationLevel: 7,
      },
      gifsicle: { optimizationLevel: 3 },
      pngquant: {
        quality: '65-90',
        speed: 1,
      },
      svgo: {
        plugins: [
          { removeUnknownsAndDefaults: false },
          { cleanupIDs: false },
          { removeViewBox: false },
        ],
      },
      plugins: [imageminMozjpeg({
        quality: 97, // (high quality default)
      })],
      disable: (config.enabled.watcher),
    }),
    new ImageminPlugin({
      cacheFolder: resolve('./.cache'),
      test: 'images/layout/header*', // only header image from responsive-loader (sharp)
      plugins: [
        imageminMozjpeg({
          quality: 92, // (acceptable quality for header image)
        }),
      ],
      disable: (config.enabled.watcher),
    }),

Install the npm sharp package and the maintained responsive-images fork with new package name responsive-images-loader:

$ npm install --save-dev sharp responsive-images-loader

Then you have to trigger that loader. Currently I have to do this using a separate SCSS file and a loop.
It would be much better of course if webpack could use the blade.php template files for this.
Then you have to generate the img markup. Honestly, this is still tedious…

@strarsis I haven’t had time to implement yet. Regardless, thanks a bunch. You’re the bees knees!

Well, surprisingly I wasn’t able to find a complete setup for this. Apparently most devs simply don’t care about different image sizes… Maybe they all use some external CDN + some JavaScript.

I don’t usually rely on my build process to generate responsive image sizes. The build process has very little information about implementation w/r/t to image size, placement, resolution, etc, so a lot of effort is required to get it to actually generate useful images. I usually try to build themes so that all image assets are set by the user, not baked into the theme–then I can use WordPress’s tools to generate responsive images, and they do most of the work for me. On the rare occasion that the theme requires baked-in images, their use is so specialized that it’s easier and faster to just optimize them by hand. Is there a particular reason you want to generate the images via your build process vs. through WordPress?

Right, for example, complex image assets in the theme, so they are not content at all.
Like composite decorative images, sometimes with shadows/blend filters or the header being an important visual part, notably when that header is static and no selection should be done by the user (then the WordPress header images plugin/feature could be used instead).

First, I totally agree with you @alwaysblank. This shouldn’t be a part of Sage’s build process.

I’m working on an unusual type of project where I’m not the only party involved. Otherwise, I could throw all image assets into WP and reference them there.

The other problem or tedious nature is syncing images (or exact data) between the remote server and local dev environments. There is a terrific plugin by Delicious Brains I’ve used in the past which handles that well, but it’s expensive and not in line with this budget.

The other option would be Cloudinary. However, I’m just a drone in this project. I have no direct access to the client. There’s also this online generator https://www.responsivebreakpoints.com/ to handle transformations. But, that would still require manual labor.

We created the ResponsivePics plugin for this, not for image assets though, but for media library uploads. That way, you have all the image information you need for resizing etc.

1 Like