Using <picture> in WordPress

January 12, 2015

Filed Under: Front-End Design

For tacomaculinary.com, we created a layout that called for images with different aspect ratios at different screen sizes. That is, the small-screen view uses landscape oriented images, and the large-screen view uses portrait-oriented images.

This is one of the rare cases where it’s best to use <picture> instead of srcset. In most cases, images keep their proportions at smaller screen sizes — a 4×6 hero image on the large-screen view is still a 4×6 hero image on the small-screen view. In those cases it’s best to use srcset, which allows the browser to choose what image to load. In this case, our layout absolutely depends on the right images loading at each breakpoint, which is what <picture> is for: it forces the browser to do what you tell it.

Now that we have that out of the way — I didn’t want to bring down the wrath of the web-design world for encouraging people to use <picture> — here’s how to use <picture> in WordPress.

Step 1: Set up the HTML for <picture>

The picture code, in its most basic form, looks something like this:

<picture>
<source srcset="large-image.jpg" media="(min-width:1200px)">
<source srcset="medium-image.jpg" media="(min-width:800px)">
<img src="default-image.jpg" alt="a picturesque picture of a person on a picaresque" >
</picture

This tells the browser that if the window size is 1200px or larger, it should use large-image.jpg. If it’s between 800px and 1199px, it should use medium-image.jpg. If it’s smaller than that, or if the browser doesn’t understand what <picture> means for some reason, it will load default-image.jpg. Typically you’ll want to use the same breakpoints that you used in your CSS. For the homepage image on Tacoma Culinary, here’s what that looked like:

<picture>
<source srcset="home-1-large.jpg" media="(min-width: 1200px)">
<source srcset="home-1-medium.jpg" media="(min-width: 790px)">
<source srcset="home-1-small.jpg" media="(min-width: 420px)">
<source srcset="home-1-tiny.jpg" media="(max-width: 419px)">
<img src="home-1-large.jpg" alt="A student in the culinary arts program at Clover Park Technical College near Tacoma"&gt;
</picture>

We wanted to use four different image sizes. The smallest one, tiny.jpg, isn’t totally necessary, but I added it so that on really small screens — like those on older iPhones — it would load a very small and light image, which would improve the load time.

Straightforward enough so far, right?

Step 2: Set Up Fallbacks for Older Browsers

If you don’t need to design for IE 9 or below, you can skip this part. For the rest of us, we’ll need to add picturefill, which provides <picture> support for older versions of Internet Explorer. Download the picturefill javascript, link to it in your header — or, better, compile it with the rest of your javascript — and then edit your code to add a conditional IE tag for <video>:

<picture>

<source srcset="home-1-large.jpg" media="(min-width: 1200px)">
<source srcset="home-1-medium.jpg" media="(min-width: 790px)">
<source srcset="home-1-small.jpg" media="(min-width: 420px)">
<source srcset="home-1-tiny.jpg" media="(max-width: 419px)"> >
<img src="home-1-large.jpg" alt="A student in the culinary arts program at Clover Park Technical College near Tacoma">

</picture>

This just tricks IE9 into thinking it’s dealing with a <video>, which makes it work better. Silly IE9.

Step 3: Hook It Up to WordPress

This code will work great if you never need to change your images. But if you — or, more likely, someone else — ever want to change those images and doesn’t want to mess around with a bunch of FTP nonsense, you’ll want to make it so that you can change those images through the WordPress interface.

Because the whole point of using <picture> is to have control over the art direction, you’re going to have to upload separate images for each source listed in your code. (If you’re using srcset just to resize your image, WordPress can do that automatically.) To do that, we’re going to use Advanced Custom Fields. Advanced Custom Fields is a powerful WordPress plugin that lets you add additional fields — a new text input area, a new image upload area, etc. — to a page or group of pages.

Install Advanced Custom Fields as you’d install any WordPress plugin. Once it’s installed and activated, click “Custom Fields” in your WordPress dashboard. Then click “Add New” next to “Field Group.”

Since we’re only using this particular <picture> setup on our homepage, we’re first going to create a rule under “Location.” For our site, we set it to show this field group if page equals homepage. (This is obviously easy to figure out if you’re setting up a different page.)

Now, at the top of the page, click “Add New Field.” For the first field, I titled it “Home Large Image.” You can call these whatever you want, but since the whole point of this is to make it easy to update, I recommend naming it something descriptive and helpful.

Next, change the field type to “Image.” Then, under “Return Value,” select “Image URL.” This tells Advanced Custom Fields to output just the URL for the image, instead of the alt text and HTML and everything else. I find it helpful to enter the exact image dimensions and any other instructions under “Field Instructions.” Even if you’re the only person updating the site, this keeps you from having to find the image dimensions anew every time.

Now. Go through the same process for each of our image sizes, for a total of four times. In this case, we ended up with fields named “Home Image Large,” “Home Image Medium,” “Home Image Small,” and “Home Image Tiny.”

So now we just have to tell WordPress how to access these new fields. Open up your template file for the page in question. In this case, it was front-page.php.  First, we’re going to drop in our <picture> code from above somewhere in our loop.

<?php
// start the loop
if ( have_posts() ) : while ( have_posts() ) : the_post();
// a bunch of other code omitted for brevity
?>
<picture>

<source srcset="home-1-large.jpg" media="(min-width: 1200px)">
<source srcset="home-1-medium.jpg" media="(min-width: 790px)">
<source srcset="home-1-small.jpg" media="(min-width: 420px)">
<source srcset="home-1-tiny.jpg" media="(max-width: 419px)"> >
<img src="home-1-large.jpg" alt="A student in the culinary arts program at Clover Park Technical College near Tacoma">

</picture>
<?php endwhile; else : ?>
<p><?php _e( 'Sorry, no posts matched your criteria.' ); ?></p>
<?php endif; ?>

So now we’re going to replace each one of our image URLs with a bit of PHP that will get the image URLs from Advanced Custom Fields. This is well documented on the ACF site, but for our purposes we just need to know that accessing an ACF field looks like this:

<?php the_field("some_name"); >

That will print the value of the some_name field. How do we know the names of our field? Go look them up in ACF. Unless you changed them, they’ll be the same as the names you gave your fields, but all lowercase and with underscores instead of spaces. So “Home Image Large” would be “home_image_large.” So to access that field, we’d use:

<?php the_field("home_image_large"); ?>

So now we just drop that code in to replace the URL in the code:

<picture>

<source srcset="<?php the_field("home_image_large"); ?>" media="(min-width: 1200px)">
<source srcset="home-1-medium.jpg" media="(min-width: 790px)">
<source srcset="home-1-small.jpg" media="(min-width: 420px)">
<source srcset="home-1-tiny.jpg" media="(max-width: 419px)"> >
<img src="home-1-large.jpg" alt="A student in the culinary arts program at Clover Park Technical College near Tacoma">

</picture>

Go through and do the same thing for the rest of the fields. It’ll look like this:

<picture>

<source srcset="<?php the_field("home_image_large"); ?>" media="(min-width: 1200px)">
<source srcset="<?php the_field("home_image_medium"); ?>" media="(min-width: 790px)">
<source srcset="<?php the_field("home_image_small"); ?>" media="(min-width: 420px)">
<source srcset="<?php the_field("home_image_tiny"); ?>" media="(max-width: 419px)"> >
<img src="<?php the_field("home_image_large"); ?>" alt="A student in the culinary arts program at Clover Park Technical College near Tacoma">

</picture>

 

There you go! Now all you have to do is actually upload the actual images through WordPress.

P.S. If you don’t want the alt text hardcoded, just add a text field via ACF. You can figure it out. You’re a big kid now.