J Scott Smith

Using Picturefill for Responsive, Art Directed Images in Statamic

Articles - October 28th, 2014

So Picturefill, if ya’ haven’t heard, allows developers to start using the <picture> element, which is a polyfill that attempts to solve many of the problems with images in responsive environments. Firstly, an image meant for a desktop screen will need to be the appropriate ratio and resolution in order to look good, but for a mobile screen it will be disproportionately large and likely the incorrect ratio. This is a big problem as we don’t want mobile visitors to have to download huge resources, and on top of that, have them size improperly. Secondly, how do we address the 2x crowd? Do we serve up even larger images and make those with 1x screens suffer by downloading bigger files for with no benefit? That’s no good, and this is exactly why we need the picture element. It’s a solution to the problems of art direction resulting from viewport differences that come up when developing a responsive website.

Picturefill can feel a little daunting at first because instead of just dropping in an <img> element, we have to use a more complex polyfill. But it’s actually quite easy to use and I’ll show you how you can start implementing the <picture> element into your Statamic workflow by using the image transform tag.

Implementing Picturefill

First off, you’ll need to download picturefill.js. Then include it into your stack, however that may be, which could be as simple as adding <script src="picturefill.js"></script> to the <head>. Once this script is referenced you can begin using the <picture> element and srcset attributes of the <img> element. Woot!

Markup for the Picture Element

Picturefill gives us a nice introduction to the picture element and other markup patterns that it enables, but I’ll reiterate what I’m going to use. Here’s the basic markup of it:

<picture>
    <source srcset="large.jpg" media="(min-width: 1024px)">
    <source srcset="medium.jpg" media="(min-width: 768px)">
    <img srcset="small.jpg" alt="Image Description">
</picture>

So you’ll see that within <picture> we have two <source> elements and an <img> element. In this case, the first <source> with a media attribute that matches the users’ context will be used. Since this example is using min-width you’ll want the larger images to be listed first. If you were using max-width you’d want to have the smallest images listed first. To see this example in action, you can launch the pen below in full screen.

See the Pen Azjyb by J Scott Smith (@jscottsmith) on CodePen.

Media Attributes

The <source> element’s media attribute allows us to use a number of different media queries so that we can more accurately determine the users’ context such as max-width, min-width, max-height, min-height, orientation, and others. This will help determine the what’s the most appropriate image to deliver to the user. For example:

<picture>
  <source srcset="small.jpg" media="(max-width: 480px) and (orientation: portrait)">
  <source srcset="medium.jpg" media="(max-width: 768px) and (orientation: portrait)">
  <img srcset="large.jpg" alt="Image Description">
</picture>

Dealing with 1x and 2x

The srcset attribute allows us to specify hi-res images for hi-res screens. We can accomplish this by listing out the images in that attribute with 2x like so:

<picture>
  <source srcset="large.jpg, large.jpg 2x" media="(min-width: 1024px)">
  <source srcset="medium.jpg, medium.jpg 2x" media="(min-width: 768px)">
  <img srcset="small.jpg, small.jpg 2x" alt="Image Description">
</picture>

Using Statamic to Transform Your Images

Since Statamic has the ability to transform images on the fly via the {{ transform }} tag, implementing picturefill is actually really easy. I’ll assume you have an image in your content that’s ready to be transformed. If not, create a field and upload one! Then, in your theme’s appropriate template, you can start transforming your images within <picture> like so:

<picture>

  <source srcset="{{ transform
    src="{ image }"
    width="800"
    height="800"
    action="smart"
  }}" media="(min-width: 1024px)">

  <source srcset="{{ transform
    src="{ image }"
    width="500"
    height="500"
    action="smart"
  }}" media="(min-width: 768px)">

  <img srcset="{{ transform
    src="{ image }"
    width="300"
    height="300"
    action="smart"
  }}" alt="Cool Picture">

</picture>

So you can see that for each srcset the image is transformed to the appropriate size. Super easy, and now we’re serving up smaller images to smaller screens.

If we want to account for 2x users we could add additional transforms like so:

<picture>

  <source srcset="{{ transform
    src="{ image }"
    width="800"
    height="800"
    action="smart"
  }},
  {{ transform
    src="{ image }"
    width="1600"
    height="1600"
    action="smart"
  }} 2x" media="(min-width: 1024px)">

  <source srcset="{{ transform
    src="{ image }"
    width="500"
    height="500"
    action="smart"
  }},
  {{ transform
    src="{ image }"
    width="1000"
    height="1000"
    action="smart"
  }} 2x" media="(min-width: 768px)">

  <img srcset="{{ transform
    src="{ image }"
    width="300"
    height="300"
    action="smart"
  }},
  {{ transform
    src="{ image }"
    width="600"
    height="600"
    action="smart"
  }} 2x" alt="Cool Picture">

</picture>

A lot to look at, but it gets the job done.

Of course if we want to apply some art direction to our images this wont completely work as a solution since all we’re doing so far is resizing images.

But one thing we could do, is add two fields for images, say one for portrait orientations, the other for more typical landscape displays. This way we can serve up something completely unique and befitting for each scenario.

Conclusion

Picturefill is a great tool for allowing the use of the new <picture> element, and with the help of Statamic’s transform tag you can quickly implement it in your templates. The only caveat to using picturefill is that there’s no fallback for users with Javascript disabled and they will only see the img alt tags. But, since the <picture> element is here to stay, it’s great to start using it on projects that require Javascript.

Comments

blog comments powered by Disqus