The art of responsivenes


This is a guide for dealing with responsive images on the web.

There are to approaches, if your goal is to

Increase performance then

<img srcset="" src="" alt="">

Here the browser chooses between a 300×300 image or a 600×600. If the browser only needs the 300×300, that’s potentially a 4× bytes-over-the-wire savings!. This is accomplished with using srcset

The easiest-possible responsive images syntax is adding a srcset attribute with x descriptors on the images to label them for use on displays with different pixel-densities.

<img 
  alt="A baby smiling with a yellow headband."
  src="baby-lowres.jpg"
  srcset="baby-highres.jpg 2x"
>

You can do as many pixel-density variants as you like.

<img 
  alt="A baby smiling with a yellow headband."
  src="baby-lowres.jpg"
  srcset="
    baby-high-1.jpg 1.5x,
    baby-high-2.jpg 2x,
    baby-high-3.jpg 3x,
    baby-high-4.jpg 4x,
    baby-high-5.jpg 100x
  "
>

Using srcset / w + sizes

This accounts for around 85% of responsive images usage on the web.

<img 
  alt="A baby smiling with a yellow headband."
  srcset="
    baby-s.jpg  300w,
    baby-m.jpg  600w,
    baby-l.jpg  1200w,
    baby-xl.jpg 2000w
  "
  sizes="70vmin"
>

We’re still providing multiple copies of the same image and letting the browser pick the most appropriate one. But instead of labeling them with a pixel density (x) we’re labelling them with their resource width, using wdescriptors. So if baby-s.jpg is 300×450, we label it as 300w.

Using srcset with width (w) descriptors like this means that it will need to be paired with the sizes attribute so that the browser will know how large of a space the image will be displaying in. Without this information, browsers can’t make smart choices.

Calculating the sizes attribute

calculating sizes with 3 different breakpoints

<img 
  ...  
  sizes="
    (max-width: 500px) calc(100vw - 2rem), 
    (max-width: 700px) calc(100vw - 6rem),
    calc(100vw - 9rem - 200px)
  "
/>

A sizes attribute that gives the browser the width of the image across all three breakpoints, factoring in the layout grid, and all of the surrounding gap, margin, and padding that end up impacting the image’s width.

If you also need…Design Control

using the picture element…

Another goal with responsive images is not just to serve different sizes of the same image, but to serve different images. For example, cropping an image differently depending on the size of the screen and differences in the layout. This is referred to as “art direction.”

<picture>
  <source 
    srcset="baby-zoomed-out.jpg"
    media="(min-width: 1000px)"
  />
  <source 
    srcset="baby.jpg"
    media="(min-width: 600px)"
  />
  <img 
    src="baby-zoomed-in.jpg" 
    alt="Baby Sleeping"
  />
</picture>

This code block is an example of what it might look like to have three stages of an “art directed” image.

  • On large screens, show a zoomed-out photo.
  • On medium screens, show that same photo, zoomed in a bit.
  • On small screens, zoom in even more.

Art direction can do a lot more than just cropping

Although cropping and zooming like this is the most common form of art direction by far, you can do a lot more with it. For instance, you can:

Combining source and srcset

Because <source> also uses the srcset syntax, they can be combined. This means that you can still reap the performance benefits of srcset even while swapping out visually-different images with <source>. It gets pretty verbose though!

<picture>
  <source 
    srcset="
      baby-zoomed-out-2x.jpg 2x,
      baby-zoomed-out.jpg
    "
    media="(min-width: 1000px)"
  />
  <source 
    srcset="
      baby-2x.jpg 2x,
      baby.jpg
    "
    media="(min-width: 600px)"
  />
  <img 
    srcset="
      baby-zoomed-out-2x.jpg 2x
    "
    src="baby-zoomed-out.jpg"
    alt="Baby Sleeping"
  />
</picture><picture>
  <source 
    srcset="
      baby-zoomed-out-2x.jpg 2x,
      baby-zoomed-out.jpg
    "
    media="(min-width: 1000px)"
  />
  <source 
    srcset="
      baby-2x.jpg 2x,
      baby.jpg
    "
    media="(min-width: 600px)"
  />
  <img 
    srcset="
      baby-zoomed-out-2x.jpg 2x
    "
    src="baby-zoomed-out.jpg"
    alt="Baby Sleeping"
  />
</picture>

if you want to use an image in the WebP format. It’s a pretty great image format, often being the most performant choice, and it’s supported everywhere that the element is, except Safari. A fallback can be used

<picture>
  <source srcset="party.webp">
  <img src="party.jpg" alt="A huge party with cakes.">
</picture>

Using Webp images

It can be 10% of the jpg version of the image. There are online converters, command line tools, and some modern design software, like Sketch, helps you export in that format. My preference is to use an image hosting CDN service that automatically sends images in the perfect format for the requesting browser, which makes all this unnecessary (because you can just use img/srcset).

CDN service that do this, to name a few:

Automated responsive images

The syntax of responsive images is complex to the point that doing it by hand is often out of the question. I’d highly recommend automating and abstracting as much of this away as possible. Fortunately, a lot of tooling that helps you build websites knows this and includes some sort of support for it. Here are some examples…

  • Cloudinary has this responsive breakpoints tool including an API for generating the perfect breakpoints.
  • WordPress generates multiple versions of images and outputs in the responsive images syntax by default.
  • Gatsby has a grab-bag of plugins for transforming and implementing images on your site. You ultimately implement them with gatsby-image, which is a whole fancy thing for implementing responsive images and other image loading optimizations. Speaking of React, it has component abstractions like “An Almost Ideal React Image Component” that also does cool stuff.
  • Nicolas Hoizey’s Images Responsiver Node module (and it’s Eleventy plugin) makes a ton of smart markup choices for you, and pairs nicely with a CDN that can handle the on-the-fly resizing bits.

CSS with background images

The trick is to use @media queries to change the background-image source.

 const { createApp, ref } = Vue;
  const appcommon = createApp({
    data() {
      return {
        navbar: false,
        out: 'hello vue'
      };
    },
    methods:{
      toggleNav(){
        this.navbar = !this.navbar;
        if(this.navbar === true){
          const menu = document.getElementById('menu-menu-main');
          const menuItems = menu.querySelectorAll('.menu-item');
          gsap.fromTo(menuItems, {x: -20, opacity: 0}, {x: 0, opacity: 1, duration: 0.3, stagger: 0.2});
        }
      },
      itemAnimation(){
        // 
      }
      
    }
    
  });
  appcommon.mount('.theme-wrapper');
 <div class="row">
     <div class="col-11 col-md-8 m-auto">
       <?php the_content(); ?>
          <hr>
       </div>
    </div>