In-content Responsive Images in Expression­Engine

Tell me if you've heard this one before: you're a responsible agency or freelancer, tasked with creating a beautiful and performant website for your client.

But your client – who is more concerned with meeting her quarterly business goals than learning the nuances of website performance, can you blame her? – keeps uploading 4000x3000 pixel photos into the content fields.

But what can you do? While you have some fields set up as image fields over which you have complete control, you can't really control the output of the images within the content field.

This article addresses how you can use Blocks to make the experience better for your client while making sure you can still resize and markup each image responsively.

This article is not a tutorial on responsive images. So many people have done a much better job than I can explaining responsive images. Eric Portis wrote my favorite one.

Well let's get started. Three steps to in-content responsive-image bliss.

Step 1: Block Definitions

First, we need to define which types of blocks will be available to the end user. In this situation, we'll focus on two: content and image.

The content block type will be the same as we've defined in the captioned images article: a single Wygwam field.

The image block type will consist of three fields:

  1. A switch field for determining how to float the image: left, center, or right. We'll set a CSS class on the element based on this value to provide some variety.

  2. A native Image field (or rather, a native File field, set to image mode). I'll leave you in charge of choosing an upload folder.

  3. A native text field for alt field. This will hold the accessibility text for the image. You are, after all, serious about your craft.

Here's how it looks:

A grid of settings for the responsive image type
Settings for our responsive image block type

Step 2: Create the Field

Next up, we need to create the field. This works like you'd expect: go to Admin → Channel Administration → Channel Fields. Select a field group. Add a Blocks field – I called mine "page_content".

Set the field type to Blocks and in the settings, select the content and image block types.

The options for setting up a Blocks field type
Content and Responsive Images block types selected

Step 3: Template

Now it's time to do the real work. Let's template the Blocks.

For this, you'll need to set up some native image manipulations. (Native image manipulations not your thing? Don't panic. The next section discusses using CE Image instead.) I've set up small, medium, and large crops.

{page_content}
  {simple_content}
    {content}
  {/simple_content}

  {responsive_image}
    <img class="interior {position}"
         alt="{alt}"
         src="{img:small}"
         srcset="{img:small} 480w, {img:medium} 800w, {img:large} 1200w"
         />
    {if blocks:index:of:type == 0}
      <script src="picturefill.js" async></script>
    {/if}
  {/responsive_image}
{/page_content}

The key is that we include a srcset attribute which uses our native image manipulations. You may want to include a sizes attribute too, based on your design. We also include a class on the image so we can float the image left or right, or leave it full bleed in the center.

I typically use Picturefill.js to handle responsive images in browsers that don't support it yet. Load that here. But we only need to load it once, so load it when we see the first responsive image in the content. (If you load Picturefill somewhere else, you can omit it here.)

Step 3: Template Redux

Maybe native image manipulations aren't your thing. Maybe you prefer CE Image for your resizing needs. Well, let's do it that way instead.

Aaron Gustafson recently wrote about responsive header images in EE. We'll just extend that concept into our body content.

{responsive_image}
<img class="interior {position}"
     alt="{alt}"
     {exp:ce_img:pair
         src="{image}"
         filename_suffix="_small"
         width="480"
         height="320"
         crop="yes"
         interlace="yes"
         cache_dir="/"
         }
         src="{made}"
         srcset="{made} 480w,
     {/exp:ce_img:pair}
     {exp:ce_img:pair
         src="{image}"
         filename_suffix="_medium"
         width="800"
         height="600"
         crop="yes"
         interlace="yes"
         cache_dir="/"
         }
         {made} 800w,
     {/exp:ce_img:pair}
     {exp:ce_img:pair
         src="{image}"
         filename_suffix="_full"
         width="1200"
         height="900"
         allow_scale_larger="yes"
         crop="yes"
         interlace="yes"
         cache_dir="/"
         }
         {made} 1200w"
     {/exp:ce_img:pair}
     >
{/responsive_image}

Alright, so that kind of looks like a mess. But if you use CE Image regularly, you should be able to follow. The concept is the same as before – just with inline resizing.

Win-win-win

Just three steps to set up a solid responsive images solution in your body content. That wasn't so bad.

You win because you can output responsive markup without any hacks. Your client wins because she remains blissfully ignorant of the dark underworld of front-end performance. The end users win because they only download the images they need and don't burn through their data plans.

It's a win-win-win, thanks to Blocks.