Welcome to the Magic Match Maker
Discover ways to approach your digital challenges
Start

Responsive Pics

Resizing images in responsive layouts.

We as a digital design company have been using WordPress as our CMS of choice for the last decade now and although we still believe it’s the most versatile system for our clients, there is one feature that is still lacking in the codex and that is how to handle responsive images in your theme.

Category Code talk
Author Toine Kamps
Date Aug 2021

By default WordPress comes with the following default image sizes:

Thumbnail: 150px square
Medium: maximum width of 300px
Medium Large: maximum width of 768px
Large: maximum width of 1024px
Full: original image size

On every media upload WordPress will try to create these image sizes for you so you can use these when inserting media in the WYSIWYG editor (the medium large size is not available here) or by calling any of the built-in WordPress functions like wp_get_attachment_image_src.

Use case 1: Full-width header image

So in a common template use case where you need a large full-width header image with a panoramic 16:9 crop ratio, you could use the full size image and make sure to upload it with the correct ratio.

<?php
    $img_id = get_post_thumbnail_id();
    $img_full = wp_get_attachment_image_src($img_id, ‘full’);
    $img_alt = get_post_meta($img_id, ‘_wp_attachment_image_alt’, true);
?>
<img class=”my-header” src=”<?= $img_full[0]; ?>” alt=”<?= $img_alt; ?>” />

However since serving too large images in your website has one of the heaviest performance penalties in tools like GTmetrix and performance is becoming more and more important in SEO ranking, this is considered bad practice.

Besides that, making sure you upload your images with the correct 16:9 ratio will only work when you know your way around photoshop.

Custom image sizes

So why not add an extra custom image size with the function add_image_size?

add_image_size(‘header’, 1280, 720, true);

Now WordPress will create and crop this size for you for every media upload so you can use it in your template:

<?php
    $img_id = get_post_thumbnail_id();
    $img_header = wp_get_attachment_image_src($img_id, ‘header’);
    $img_alt = get_post_meta($img_id, ‘_wp_attachment_image_alt’, true);
?>
<img
    class=”my-header”
    src=”<?= $img_header[0]; ?>”
    alt=”<?= $img_alt; ?>”
/>

This will resolve the ratio problem and it partially resolves the performance issue since the image will be resized to 1280px, but your website could still potentially serve a 1280px wide image to a visitor on its mobile screen of only 640px wide. So that’s a loss of 200%!

So you could add an extra header size for smaller screens with the same crop ratio:

add_image_size(‘header-mobile’, 640, 360, true);

and display it like this:

<?php
    $img_id = get_post_thumbnail_id();
    $img_header = wp_get_attachment_image_src($img_id, ‘header’);
    $img_header_mobile = wp_get_attachment_image_src($img_id, ‘header-mobile’);
    $img_alt = get_post_meta($img_id, ‘_wp_attachment_image_alt’, true);
?>
<img
    class=”my-header”
    srcset=”<?= $img_header_mobile[0]; ?> 640w, <?= $img_header[0]; ?> 1280w”
    sizes=”(max-width: 640px) 640px, 1280px”
    alt=”<?= $img_alt; ?>”
/>

Retina support

But what if you want to display a retina version of the header image on retina screens? Do we have to add a third custom image size for this? Yes you do:

add_image_size(‘header-retina’, 2560, 1440, true);

Now we can use the resolution x-descriptors:

<?php
    $img_id = get_post_thumbnail_id();
    $img_header = wp_get_attachment_image_src($img_id, ‘header’);
    $img_header_retine = wp_get_attachment_image_src($img_id, ‘header-retina’);
    $img_alt = get_post_meta($img_id, ‘_wp_attachment_image_alt’, true);
?>
<img
    class=”my-header”
    srcset=”<?= $img_header[0]; ?> 1x, <?= $img_header_retina[0]; ?> 2x”
    alt=”<?= $img_alt; ?>”
/>

If you want to combine the header, header-retina and header-mobile sizes, we have to define the retina image with it’s double width:

<img
    class=”my-header”
    srcset=”<?= $img_header_mobile[0]; ?> 640w, <?= $img_header[0]; ?> 1280w, <?= $img_header_retina[0]; ?> 2560w”
    sizes=”(max-width: 640px) 640px, 1280px”
    alt=”<?= $img_alt; ?>”
/>

Performance

For small personal websites this method will work just fine, but when you start creating more content and layouts for your site, your media library will also grow rapidly.

Let’s say you upload images with an average size of 2 Mb and width of 3000px and you have 200 media items in your library, that will result in an extra:

200 x ((640/3000) * 2) = 85,32 Mb
200 x ((1280/3000) * 2) = 170,66 Mb
200 x ((2560/3000) * 2) = 341,33 Mb
——————————————————————————————————-
                          597,31 Mb

Maybe your website only has 4 pages with the template that uses this image size. Boom! 588 images are generated without ever being used and almost 600 Mb disk space is occupied for no reason. If you’re on a shared hosting with limited disk space, this can become a problem.

Ideally you only want to generate an (custom) image size on the locations in your layout where it needs to, just like services as Cloudinary offer.

This was one of the reasons we decided to write our own tool for this: Responsive Pics and make it available as an open-source project.

Our goal

Our goal was to create a simple syntax which would allow any WordPress template author to generate various image sizes on the go directly in our templates and only for the images that will be used on those templates so we can use responsive markup like the new <picture> element or the srcset and sizes syntax on <img> elements.

So instead of checking which pre-defined sizes for your image are available for you to use in your template, you turn it around and give WordPress the task to create that image size for you instead in the actual template.

Another prerequisite was to have no external dependencies for the image creation process, so it would be widely accessible for any user. Therefore we were limited in using WordPress’ built-in WP_Image_Editor class.

After intensive testing and fine-tuning for the last 2 years, we achieved exactly the above!

So in order to re-create that large header scenario with a crop ratio of 16:9 in multiple sizes and with retina support, we can now use this one-liner function:

<?= ResponsivePics::get_image(get_post_thumbnail_id(), ‘xs-full’, ‘0.56’); ?>

And that will generate the following html markup for you:

<img
    srcset=”/app/uploads/2020/11/my-header-1400×784-center-center.jpg 1400w,
      /app/uploads/2020/11/my-header-1400×784-center-center@2x.jpg 2800w,
      /app/uploads/2020/11/my-header-1400×784-center-center.jpg 1400w,
      /app/uploads/2020/11/my-header-1400×784-center-center@2x.jpg 2800w,
      /app/uploads/2020/11/my-header-1200×672-center-center.jpg 1200w,
      /app/uploads/2020/11/my-header-1200×672-center-center@2x.jpg 2400w,
      /app/uploads/2020/11/my-header-992×556-center-center.jpg 992w,
      /app/uploads/2020/11/my-header-992×556-center-center@2x.jpg 1984w,
      /app/uploads/2020/11/my-header-768×430-center-center.jpg 768w,
      /app/uploads/2020/11/my-header-768×430-center-center@2x.jpg 1536w,
      /app/uploads/2020/11/my-header-576×323-center-center.jpg 576w,
      /app/uploads/2020/11/my-header-576×323-center-center@2x.jpg 1152w”
    sizes=”(min-width: 1400px) 1400px,
      (min-width: 1200px) 1400px,
      (min-width: 992px) 1200px,
      (min-width: 768px) 992px,
      (min-width: 576px) 768px,
      (min-width: 0px) 576px, 100vw”
    src=”/app/uploads/2020/11/my-header.jpg”
    alt=”Responsive header image example”
>

So, what kind of sorcery is this you might think?
Let me break this down for you;

Responsive breakpoints

First of all you probably have noticed the amount of images defined in srcset and the media queries set in sizes. In order to create a variety of image sizes that will suit best on various screen sizes, Responsive Pics uses the following default breakpoints that define these media queries:

xs: 0
sm: 576px
md: 768px
lg: 992px
xl: 1200px
xxl: 1400px

Since we as a digital agency and the majority of developers still like to use CSS frameworks while developing frontends, we based our defaults on the most popular one: Bootstrap 4, but you can define or add your own breakpoints as well with the setBreakPoints function:

ResponsivePics::setBreakPoints([
    ‘xs’    => 0,
    ‘sm’    => 576,
    ‘md’    => 768,
    ‘lg’    => 992,
    ‘xl’    => 1200,
    ‘xxl’   => 1400,
    ‘xxxl’  => 1600,
    ‘xxxxl’ => 1920
]);

With these breakpoints in place, our plugin will try and resize and/or crop the given image for each breakpoint with the given size. You don’t have to define this size for each breakpoint if it should stay the same. When you only define 1 breakpoint, Responsive Pics will use the same size for each following breakpoint upwards.

In our minimal example this:

<?= ResponsivePics::get_image(get_post_thumbnail_id(), ‘xs-full’, ‘0.56’); ?>

is actually interpreted as:

<?= ResponsivePics::get_image(get_post_thumbnail_id(), ‘xs-full, sm-full, md-full, lg-full, xl-full, xxl-full’, ‘0.56’); ?>

Image sizes

So in our example we are basically requesting a ‘full’ image size for all breakpoints. The ‘full’ syntax means we want to use the width from the next breakpoint to resize the image:

0 < 576px: 576px
576 < 768px: 768px
768 < 992px: 992px
992 < 1200px: 1200px
1200 < 1400px: 1400px
≥ 1400px: 1400px

Image Crop

Since the image sources in a responsive image element need to be identical apart from their size (same aspect ratio, same focal point), we can set a global crop ratio for the image: 0.56 with a default crop position from the center.

This will set the image height in each breakpoint to 56% of it’s width:

0 < 576px: 576px x 322px
576 < 768px: 768px x 430px
768 < 992px: 992px x 556px
992 < 1200px: 1200px x 672px
1200 < 1400px: 1400px x 784px
≥ 1400px: 1400px x 784px

Image Density

For each requested image size in the breakpoint, the plugin will automatically try to multiply the size by 2 for retina support and add it to the available image sources.

Performance

The generated output makes sure that the image is only downscaled and never upscaled and that your site will serve the most suitable image size for the current screen size. This will improve your page speed performance instantly and this time only 12 images were generated!

Use case 2: Column based image

Another very common use case while templating would be displaying an image in a column based grid system. The most used grid system is bootstrap, so we again will be using Bootstrap 4 defaults which uses 12 columns, a gutter of 30px and container-max-widths of:

sm: 540px
md: 720px
lg: 960px
xl: 1140px
xxl: 1320px

but these are also customizable:

ResponsivePics::setColumns(12);
ResponsivePics::setGutter(30);
ResponsivePics::setGridWidths([
    ‘xs’    => 576,
    ‘sm’    => 768,
    ‘md’    => 992,
    ‘lg’    => 1200,
    ‘xl’    => 1400,
    ‘xxl’   => 1600,
    ‘xxxl’  => 1920
]);

Let’s say your main content is displayed in a container with a max-width and on mobile you want the image to fill all columns, on tablets half of the columns and on desktops one-third of the columns. How would you normally approach this? Use the default ‘large’ image size and just make it responsive with css?

<style>
    .image {
      .my-grid-image {
        max-width: 100%;
        height: auto;
      }
    }
</style>
<main class=”container”>
    <h1><?= the_title(); ?></h1>
    <div class=”row”>
      <article class=”entry col-xs-12 col-md-6 col-lg-8″>
        <?= the_content(); ?>
      </article>
      <figure class=”image col-xs-12 col-md-6 col-lg-4″>
      <?php
        $img = get_field(‘grid-image’, get_the_ID());
        $img_alt = $img[‘alt’];
        $img_large = $img[‘sizes’][‘large’];
      ?>
      <img class=”my-grid-image” src=”<?= esc_url($img_large); ?>” alt=”<?= $img_alt; ?>” />
      </figure>
    </div>
</main>

If you’re using the default $grid-widths then your maximum container width would be 1320px. Since we only want 4 out of the 12 columns on large screens, this would leave us with:

((1320 / 12) * 4) – (2* 30) = 380px

This would result in an downscaled image of:

(380/1024) * 100 = 37%

Needless to say, this is not optimal.
With Responsive Pics from now on, we only have to do this:

<?= ResponsivePics::get_image($img[‘id’], ‘xs-12, md-6, lg-4’); ?>

which will result in in this markup:

<main class=”container”>
    <h1><?= the_title(); ?></h1>
    <div class=”row”>
      <article class=”entry col-xs-12 col-md-6 col-lg-8″>
        <?= the_content(); ?>
      </article>
      <figure class=”image col-xs-12 col-md-6 col-lg-4″>
      <img
        srcset=”/app/uploads/2020/11/grid-image-446×301.jpg 446w,
          /app/uploads/2020/11/grid-image-446×301@2x.jpg 892w,
          /app/uploads/2020/11/grid-image-446×301.jpg 446w,
          /app/uploads/2020/11/grid-image-446×301@2x.jpg 892w,
          /app/uploads/2020/11/grid-image-380×256.jpg 380w,
          /app/uploads/2020/11/grid-image-380×256@2x.jpg 760w,
          /app/uploads/2020/11/grid-image-476×321.jpg 476w,
          /app/uploads/2020/11/grid-image-476×321@2x.jpg 952w,
          /app/uploads/2020/11/grid-image-748×504.jpg 748w,
          /app/uploads/2020/11/grid-image-748×504@2x.jpg 1496w,
          /app/uploads/2020/11/grid-image-556×375.jpg 556w,
          /app/uploads/2020/11/grid-image-556×375@2x.jpg 1112w”
        sizes=”(min-width: 1400px) 446px,
          (min-width: 1200px) 446px,
          (min-width: 992px) 380px,
          (min-width: 768px) 476px,
          (min-width: 576px) 748px,
          (min-width: 0px) 556px,
          100vw”
        src=”/app/uploads/2020/11/grid-image.jpg”
        alt=”Grid system image example”
      >
      </figure>
    </div>
</main>

And now our images have the exact same width as our parent grid column on every screen size!

We can even pass our own image class(es) as a 4th parameter:

<?= ResponsivePics::get_image($img[‘id’], ‘xs-12, md-6, lg-4’, ”, ‘my-image-class’); ?>

Or enable lazyload the image by passing the 5th parameter as true:

<?= ResponsivePics::get_image($img[‘id’], ‘xs-12, md-6, lg-4’, ”, ‘my-image-class’, true); ?>

Which will generate the following markup:

<img
    class=”my-image-class lazyload”
    data-srcset=”/app/uploads/2020/11/grid-image-446×301.jpg 446w,
      /app/uploads/2020/11/grid-image-446×301@2x.jpg 892w,
      /app/uploads/2020/11/grid-image-446×301.jpg 446w,
      /app/uploads/2020/11/grid-image-446×301@2x.jpg 892w,
      /app/uploads/2020/11/grid-image-380×256.jpg 380w,
      /app/uploads/2020/11/grid-image-380×256@2x.jpg 760w,
      /app/uploads/2020/11/grid-image-476×321.jpg 476w,
      /app/uploads/2020/11/grid-image-476×321@2x.jpg 952w,
      /app/uploads/2020/11/grid-image-748×504.jpg 748w,
      /app/uploads/2020/11/grid-image-748×504@2x.jpg 1496w,
      /app/uploads/2020/11/grid-image-556×375.jpg 556w,
      /app/uploads/2020/11/grid-image-556×375@2x.jpg 1112w”
    sizes=”(min-width: 1400px) 446px,
      (min-width: 1200px) 446px,
      (min-width: 992px) 380px,
      (min-width: 768px) 476px,
      (min-width: 576px) 748px,
      (min-width: 0px) 556px,
      100vw”
    src=”/app/uploads/2020/11/grid-image.jpg”
    alt=”Grid system image example”
>

Use case 3: Art directed image

In almost every wordpress template we develop, we need an art-directed image somewhere in the layout. This can be as simple as resizing with different maximum image heights for each breakpoint, or cropping an image with a different ratio from a certain breakpoint and up.

To achieve this we need to use the <picture> element instead. Our plugin has a seperate function for that named get_picture which allows us to define a height factor and/or crop positions on each breakpoint!

Let’s say we want to display a panoramic banner image at the top of our main content, without art direction this image would become very narrow on smaller screens, so ideally you would want to adjust the crop ratio to become smaller when the screen becomes larger. Luckily this is super easy:

<main class=”container”>
    <?= ResponsivePics::get_picture($banner, ‘xs-12/0.75|c, md-12/0.5|c, lg-12/0.35|c’); ?>
</main>

We could even change the cropping focal points from the left top to the center:

<main class=”container”>
    <?= ResponsivePics::get_picture($banner, ‘xs-12/0.75|l t, md-12/0.5|c t, lg-12/0.35|c’); ?>
</main>

This would create the following picture element:

<picture>
    <source media=”(min-width: 1400px)” srcset=“/app/uploads/2020/11/art-banner-1380×482-center-center.jpg 1x, /app/uploads/2020/11/art-banner-1380×482-center-center@2x.jpg 2x”>
    <source media=”(min-width: 1200px)” srcset=”/app/uploads/2020/11/art-banner-1380×482-center-center.jpg 1x, /app/uploads/2020/11/art-banner-1380×482-center-center@2x.jpg 2x”>
    <source media=”(min-width: 992px)” srcset=”/app/uploads/2020/11/art-banner-1180×413-center-center.jpg 1x, /app/uploads/2020/11/art-banner-1180×413-center-center@2x.jpg 2x”>
    <source media=”(min-width: 768px)” srcset=”/app/uploads/2020/11/art-banner-972×486-center-top.jpg 1x, /app/uploads/2020/11/art-banner-972×486-center-top@2x.jpg 2x”>
    <source media=”(min-width: 576px)” srcset=”/app/uploads/2020/11/art-banner-748×561-left-top.jpg 1x, /app/uploads/2020/11/art-banner-748×561-left-top@2x.jpg 2x”>
    <source media=”(min-width: 0px)” srcset=”/app/uploads/2020/11/art-banner-556×417-left-top.jpg 1x, /app/uploads/2020/11/art-banner-556×417-left-top@2x.jpg 2x”>
    <img src=”data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==” alt=”Art directed banner example”>
</picture>

You can see that for this picture method retina support is also automatically added! Since the ratio of the image could change while resizing your screen, we can enable an extra ‘intrinsic’ functionality by pass the 5th parameter as true:

<main class=”container”>
    <?= ResponsivePics::get_picture($banner, ‘xs-12/0.75|l t, md-12/0.5|c t, lg-12/0.35|c’, null, false, true); ?>
</main>

Which will add some extra data-aspectratio attributes on the sources:

<picture class=”intrinsic”>
    <source media=”(min-width: 1400px)” srcset=“/app/uploads/2020/11/art-banner-1380×482-center-center.jpg 1x, /app/uploads/2020/11/art-banner-1380×482-center-center@2x.jpg 2x data-aspectratio=”2.8630705394191″>
    <source media=”(min-width: 1200px)” srcset=”/app/uploads/2020/11/art-banner-1380×482-center-center.jpg 1x, /app/uploads/2020/11/art-banner-1380×482-center-center@2x.jpg 2x data-aspectratio=”2.8630705394191″>
    <source media=”(min-width: 992px)” srcset=”/app/uploads/2020/11/art-banner-1180×413-center-center.jpg 1x, /app/uploads/2020/11/art-banner-1180×413-center-center@2x.jpg 2x data-aspectratio=”2.8571428571429″>
    <source media=”(min-width: 768px)” srcset=”/app/uploads/2020/11/art-banner-972×486-center-top.jpg 1x, /app/uploads/2020/11/art-banner-972×486-center-top@2x.jpg 2x” data-aspectratio=”2″>
    <source media=”(min-width: 576px)” srcset=”/app/uploads/2020/11/art-banner-748×561-left-top.jpg 1x, /app/uploads/2020/11/art-banner-748×561-left-top@2x.jpg 2x” data-aspectratio=”1.3333333333333″>
    <source media=”(min-width: 0px)” srcset=”/app/uploads/2020/11/art-banner-556×417-left-top.jpg 1x, /app/uploads/2020/11/art-banner-556×417-left-top@2x.jpg 2x” data-aspectratio=”1.3333333333333″>
    <img class=”intrinsic__item” src=”data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==” alt=”Art directed banner example”>
</picture>

This will enable you to pre-calculate the height of the image with a plugin like lazysizes aspectratio extension before it is done loading. Very useful if you need to execute some document height calculations.

Use case 4: Background header image

So back to the full-width header use case. This time we don’t want to use an inline element like an <img> or <picture>, but an actual background-image so the header content will determine the height of the header.

If you tried this before without this plugin, you probably have found out that it’s nearly impossible to create inline responsive background images in your templates directly:

<?php
    $img_id = get_post_thumbnail_id();
    $img_header = wp_get_attachment_image_src($img_id, ‘header’);
    $img_header_retine = wp_get_attachment_image_src($img_id, ‘header-retina’);
?>
<header
    class=”my-header”
    style=”background-image:url(‘<?= $img_header; ?>’)”
    >
    <h1 class=”my-header__title”><?= the_title(); ?></h1>
    <p class=”my-header__excerpt”><?= the_excerpt(); ?></p>
</header>

Because how do we tell the browser to use our retina version? Where do we write our css media-queries? The answer is, you can’t. The only workaround is by creating an inline (scoped?) css block with an unique id selector where you add all your css media-queries:

<?php
    $img_id = get_post_thumbnail_id();
    $img_header = wp_get_attachment_image_src($img_id, ‘header’);
    $img_header_mobile = wp_get_attachment_image_src($img_id, ‘header-mobile’);
    $img_header_retine = wp_get_attachment_image_src($img_id, ‘header-retina’);
?>
<style scoped=”scoped” type=”text/css”>
    #my-header-<?= get_the_ID(); ?> {
      background-image: url(‘<?= $img_header_mobile[0]; ?>’);
    }
    @media (min-width: 640px) {
      #my-header-<?= get_the_ID(); ?> {
        background-image: url(‘<?= $img_header[0]; ?>’);
      }
    }
    @media only screen and (-webkit-min-device-pixel-ratio: 2) and (min-width: 640px), only screen and (min-resolution: 192dpi) and (min-width: 640px) {
      #my-header-<?= get_the_ID(); ?> {
        background-image: url(‘<?= $img_header_retine[0]; ?>’);
      }
    }
</style>
<header
    id=”my-header-<?= get_the_ID(); ?>”
    class=”my-header”
    >
    <h1 class=”my-header__title”><?= the_title(); ?></h1>
    <p class=”my-header__excerpt”><?= the_excerpt(); ?></p>
</header>

That’s a lot of markup for just 3 different image sources!
Let’s simplify that with our third function get_background:

<header
    class=”my-header”
    >
    <h1 class=”my-header__title”><?= the_title(); ?></h1>
    <p class=”my-header__excerpt”><?= the_excerpt(); ?></p>
    <?= ResponsivePics::get_background(get_post_thumbnail_id(), ‘xs-full’, ‘my-header__bg’); ?>
</header>

Which will create the following markup for you:

<style scoped=”scoped” type=”text/css”>
    @media (min-width: 0px) {
      #responsive-pics-background-581 {
        background-image: url(“/app/uploads/2020/11/my-header-576×388.jpg”);
      }
    }
    @media only screen and (-webkit-min-device-pixel-ratio: 2) and (min-width: 0px), only screen and (min-resolution: 192dpi) and (min-width: 0px) {
      #responsive-pics-background-581 {
        background-image: url(“/app/uploads/2020/11/my-header-576×388@2x.jpg”);
      }
    }
    @media (min-width: 576px) {
      #responsive-pics-background-581 {
        background-image: url(“/app/uploads/2020/11/my-header-768×518.jpg”);
      }
    }
    @media only screen and (-webkit-min-device-pixel-ratio: 2) and (min-width: 576px), only screen and (min-resolution: 192dpi) and (min-width: 576px) {
      #responsive-pics-background-581 {
        background-image: url(“/app/uploads/2020/11/my-header-768×518@2x.jpg”);
      }
    }
    @media (min-width: 768px) {
      #responsive-pics-background-581 {
        background-image: url(“/app/uploads/2020/11/my-header-992×669.jpg”);
      }
    }
    @media only screen and (-webkit-min-device-pixel-ratio: 2) and (min-width: 768px), only screen and (min-resolution: 192dpi) and (min-width: 768px) {
      #responsive-pics-background-581 {
        background-image: url(“/app/uploads/2020/11/my-header-992×669@2x.jpg”);
      }
    }
    @media (min-width: 992px) {
      #responsive-pics-background-581 {
        background-image: url(“/app/uploads/2020/11/my-header-1200×810.jpg”);
      }
    }
    @media only screen and (-webkit-min-device-pixel-ratio: 2) and (min-width: 992px), only screen and (min-resolution: 192dpi) and (min-width: 992px) {
      #responsive-pics-background-581 {
        background-image: url(“/app/uploads/2020/11/my-header-1200×810@2x.jpg”);0
      }
    }
    @media (min-width: 1200px) {
      #responsive-pics-background-581 {
        background-image: url(“/app/uploads/2020/11/my-header-1400×945.jpg”);
      }
    }
    @media only screen and (-webkit-min-device-pixel-ratio: 2) and (min-width: 1200px), only screen and (min-resolution: 192dpi) and (min-width: 1200px) {
      #responsive-pics-background-581 {
        background-image: url(“/app/uploads/2020/11/my-header-1400×945@2x.jpg”);
      }
    }
    @media (min-width: 1400px) {
      #responsive-pics-background-581 {
        background-image: url(“/app/uploads/2020/11/my-header-1400×945.jpg”);
      }
    }
    @media only screen and (-webkit-min-device-pixel-ratio: 2) and (min-width: 1400px), only screen and (min-resolution: 192dpi) and (min-width: 1400px) {
      #responsive-pics-background-581 {
        background-image: url(“/app/uploads/2020/11/my-header-1400×945@2x.jpg”);}
    }
}
</style>
<div class=”my-header__bg” id=”responsive-pics-background-581″></div>

The only catch with this method is, that you need to define some dimensions on the generated div or position it absolutely:

.my-header {
    position: relative;

    &__bg {
      position: absolute;
      left: 0;
      top: 0;
      right: 0;
      bottom: 0;
      z-index: -1;
      background-repeat: no-repeat;
      background-position: center;
      background-size: cover;
    }
}

Of course, these use cases are just a tip off the ice berg. You can create almost any complex responsive layout now with these tools in your WordPress template without worrying about the performance of your images.

Background processing

Another very important feature of our plugin is that the resizing and cropping of the images are added as actions to a job queue that will execute each action as a background task so your webserver will not timeout. This process is managed by the amazing Action Scheduler library. Action Scheduler has a built in WordPress administration screen for monitoring, debugging and manually triggering scheduled actions.

We as digital agency decided to make our plugin public and available on github and  packagist.org for any developer to use. This way we give something back to the open-source WordPress ecosystem that has given us so much the last decade! 

For the full documentation of any of the 3 methods I just introduced, head over to the Responsive Pics website: https://responsive.pics/ and give us a star over at Github: https://github.com/Booreiland/responsive-pics