Cloud Four Blog

Technical notes, War stories and anecdotes

Responsive Images 101, Part 8: CSS Images

Most of the time when people refer to responsive images, they are referring to inline images, not CSS images.

This is because before <picture> and srcset there were no good solutions for inline responsive images. When it comes to CSS images, we could always use media queries. So why worry?

But now it is time to revisit responsive CSS images and look at the solutions anew based on what we’ve learned about inline images.

image-set() for resolution switching

Just like when we’re working with inline images, one of the first questions we’ll need to ask ourselves is whether we’re dealing with the resolution switching or art direction use case.

For resolution switching, we should strive to provide the browser with options and let the browser pick the best possible image. The browser is in a better position to know what image will work best based on user preference, network conditions, etc.

To provide the browser with options, we should use the image-set() syntax.

image-set() syntax repeated below

You may notice some similarity between image-set() and srcset. In fact, srcset was modeled after image-set().

background-image: image-set( "foo.png" 1x, "foo-2x.png" 2x);

Like srcset, image-set’s value contains a comma-separated list of image URIs along with a display density descriptor. If a display density descriptor isn’t provided, it is assumed to be 1x.

However, image-set() does not support width descriptors yet. The plan is to refine image-set() to provide feature parity with srcset.

While most of the examples you will see for image-set() show it applied to background-image, it can be applied to any CSS property that accepts images.

image-set(): The forgotten responsive images standard

image-set() was the first responsive images specific syntax, and as mentioned, it was the foundation for srcset.

However, because we had solutions for CSS responsive images using media queries, image-set() was ignored by nearly everyone. The Responsive Images Community Group didn’t spend much time discussing it. Browsers didn’t prioritize implementing it.

Once we were nearing completion of the <picture> and srcset standards, we looked around and realized that we had neglected image-set(). Work is underway to increase the functionality of image-set() to bring it in line with srcset.

But as of publication, despite being the first responsive images standard, browser support for image-set() is lacking. It is available with a webkit prefix in Chrome, Opera, and Safari. Neither Firefox nor Microsoft have implemented it yet.

So why include it in this Responsive Images 101 series?

Because image-set() is the correct solution for resolution switching. When image-set() is widely supported, we should use it for all of the same reasons we use srcset instead of <picture> with the media attribute when we’re dealing with resolution switching.

Until image-set() is widely supported, you’ll probably end up using the CSS art direction solution for resolution switching.

Art direction

What is the CSS solution for art direction? Media queries.

It’s that simple. In fact, I’m going to assume you know media queries so no syntax sample here.

But as long as I’ve got your ear, make sure your media queries for images don’t overlap or you’ll end up with duplicate downloads. If you have any doubts, check out Tim Kadlec’s Media Query & Asset Downloading Results.

Resolution media queries

If you want to support high density displays in art direction, you’ll probably want to use the new resolution media queries.

Resolution media query syntax. Repeated below.

The resolution media query allows you to apply specific CSS rules to devices that meet the display density that you define.

@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
/* High density stuff here */
}

(Much thanks to CSS Tricks for this syntax sample.)

The first thing you’ll notice in the syntax above is that we’re including a -webkit prefixed media query. This is for devices that support the old device-pixel-ratio syntax. The only devices that got in the wild with this syntax used the -webkit prefix which is why it is the only one listed.

The syntax going forward is the resolution media query. In our example, we’re using min-resolution, but as you probably guessed, there is a complimentary max-resolution feature that can be used instead.

The resolution media query can check one of three things:

  • dpi — dots per inch
  • dpcm — dots per centimeter
  • dppx — dots per px unit

The first two are fairly straight-forward, but I found dppx confusing. The Mozilla Developer Network documentation defines ddpx thusly:

This unit represents the number of dots per px unit. Due to the 1:96 fixed ratio of CSS in to CSS px, 1dppx is equivalent to 96dpi, that corresponds to the default resolution of images displayed in CSS as defined by image-resolution.

Confused? I certainly was when I first read it.

Here’s the way I’ve begun to think about it, the idea of 1x, 2x, 3x, etc. is based on an imprecision. The value of 1x on some devices is different than others because some devices are 72dpi or 96dpi or whatever.

But from a CSS perspective, these differences don’t matter. The CSS Working Group has decided that there will always be a 1:96 fixed ratio of CSS inches to CSS pixels.

So while 1x might leave things up to interpretation because of 72dpi vs. 96dpi screens, 1dppx will always be what you and I think of as “1x”.

You may be asking yourself, why was 1x sufficient for srcset and image-set, but for min-resolution, it was necessary to use dppx?

I don’t know. All I know is that you can think of 1dppx as 1x, 2dppx as 2x, and so on. At this point, I’ve just accepted the inconsistency and decided to move on with my life. I recommend you do the same. ;-)

Now comes the hard part

Believe it or not, responsive images syntax is the easy part. In Part 9, we’ll discuss the vexing challenge of picking your image breakpoints.


Responsive Images 101 Series
  1. Definitions
  2. Img Required
  3. Srcset Display Density
  4. Srcset Width Descriptors
  5. Sizes
  6. Picture Element
  7. Type
  8. CSS Responsive Images
  9. Image breakpoints

Introducing Leveller: Please Avoid Using It

This happens to me over and over: I have a multi-column grid of tiles, each with varying heights. This means the bottom of certain rows can appear jagged and difficult to scan visually:

See the Pen Leveller: Before by Tyler Sticka (@tylersticka) on CodePen.

Ideally, I’d use flexbox to solve that problem with a shockingly small amount of CSS (especially if you use Autoprefixer). Seriously, look how well that works:

See the Pen Leveller: Flexbox Alternative by Tyler Sticka (@tylersticka) on CodePen.

Sadly, that solution rarely makes it into production on the projects I’ve worked on. Sometimes browser support is the culprit. Other times we’ve inherited particularly uncooperative grid patterns (either from an existing project, or an overzealous framework).

Over the last few years, I wrote and re-wrote project-specific, bespoke JavaScript to solve this problem. I’ve finally accepted that it isn’t going away, at least not as quickly as I’d like it to.

So I’ve written a jQuery plugin for equalizing element heights. It’s called Leveller:

See the Pen Leveller: After by Tyler Sticka (@tylersticka) on CodePen.

Don’t use Leveller if you can help it. Flexbox is way more appropriate. If you only need to adjust min-height properties, Equalizer is a leaner, dependency-free solution.

But if all else fails, Leveller is available now on GitHub (and also via npm). Godspeed!

Responsive Images 101, Part 5: Sizes

When we last left our intrepid web developers, they had discovered the power of srcset width descriptors, only to be faced with a new challenge—the browser only knows the size of the viewport when it begins downloading images.

Now, it is time to meet the hero of our story: the sizes attribute.

sizes-hero

Sizes attribute is required!

The sizes attribute is required any time you use srcset width descriptors.

In fact, sizes only makes sense if you’re using the width descriptors. If you’re using the display density descriptors, you don’t need the sizes attribute. The browser won’t know what to do with it.

Sizes syntax

Out of all the new responsive images standards, sizes was the hardest one for me to wrap my head around at first.

Sizes syntax repeated below

Like srcset, the sizes attribute contains a comma-separated list. This comma-separated list describes the size of the image in relation to the viewport.

I want to repeat that point because it is the key to understanding sizes.

We’re telling the browser what size the image will be in relation to the size of the viewport. And we can tell the browser how that relationship changes as the size of the viewport changes.

<img src="cat.jpg" alt="cat"
  srcset="cat-160.jpg 160w, cat-320.jpg 320w, cat-640.jpg 640w, cat-1280.jpg 1280w"
  sizes="(max-width: 480px) 100vw, (max-width: 900px) 33vw, 254px">

Like srcset, each comma-separated item contains two values separated by a space.

Media conditions

The first value is a media condition. A media condition is similar to a media query, but not as full featured. For example, you can’t do things like ‘@media screen’, but you can do everything else you would likely want to do in sizes.

Most commonly, your media condition is going to be a something like ‘(max-width: 480px)’ or maybe ‘(min-width: 480px)’.

Lengths

The second value in each comma-separated item is a length. This length is often expressed using the viewport width (vw) unit.

There’s a good chance you haven’t seen vw units before. They are fairly new, but have wide support in current browsers.

Each vw unit represents 1% of the viewport width, which is a fancy way of saying that 100vw is 100% of the viewport width and 33vw is 33% of the viewport width.

The length doesn’t have to be expressed as a viewport width unit. It can be any length including absolute and relative length. You can even use CSS calc() to do things like auto-calculate margins dynamically.

How does the browser select the correct sizes value?

When the browser starts through the comma-separated list of values, it grabs the first value where the media condition passes.

Take another look at our sample markup and the order in the sizes attribute:

<img src="cat.jpg" alt="cat"
  srcset="cat-160.jpg 160w, cat-320.jpg 320w, cat-640.jpg 640w, cat-1280.jpg 1280w"
  sizes="(max-width: 480px) 100vw, (max-width: 900px) 33vw, 254px">

If we translated this into a bulleted list of instructions, it might look like this:

  • (max-width: 480px) 100vw — If the viewport is 480 pixels wide or smaller, the image will be 100% of the viewport width.

  • (max-width: 900px) 33vw — If the viewport is 480 pixels wide or smaller, this rule will never be reached because of the previous media condition. Ergo, if this rule effectively says that if the viewport is 481 pixels wide to 900px, that the image will be 33% of the viewport width.

  • 254px — When there is no media condition listed, the length is assumed to be a default value used when none of the other media conditions are met. In this case, we have media conditions covering viewports up to 900 pixels. Therefore, from 901 pixels wide to infinity, the image will be 254 pixels wide.

To help you visualize how this might work in the real world, I created a little video that looks as how the values might change as the viewport width increased on the Walmart Grocery site.

NOTE: As of the time of publication, the Walmart Grocery site was not using srcset and sizes. This is hypothetical markup. If you want to see srcset and sizes in action, take a look at The Guardian which recently switched to using srcset and sizes.

But what about separation of content and presentation?

I’ve seen many complaints about the new responsive images specification. Most amount to either complaints about complexity that ignore the fact that images on the web are inherently complex3 or some variation of WWIC.

But the one complaint I have a tremendous amount of sympathy for is the idea that we now have presentation information—the size of the image—in the markup. I doubt there was anyone involved in the responsive images standards process who didn’t share this concern at some point.

Unfortunately, it is unavoidable. As discussed in Part 4, the browser starts downloading image sources before the size of the image in the page is known.

The only way to support the pre-loader and make sure the right source gets downloaded is to provide some information about the size of the image in the markup.

Is the pre-loader worth it?

If you’re like me, you may have found yourself wondering whether the pre-loader was worth all of the problems it causes?

Yes. Yes, it is.

pre-loader-faster-web

Andy Davies wrote about how Google saw a 20% and Firefox a 19% increase in average page speed after implementing the pre-loader. Steve Souders thinks that “preloading is the single biggest performance improvement browsers have ever made.”

We can’t simply throw out that web performance boon in favor of responsive images.

Therefore, we have to find a compromise. The sizes attribute is that compromise. It provides just enough information for the browser to do its job.

Srcset and sizes = Smart browsers

Srcset and sizes provide all of the functionality you need for the resolution switching use case. They give the browser just enough information to allow it to make smart decisions.

Dog with glasses

But what happens when you need more control? What about art direction?

Next Tuesday, Responsive Images 101, Part 6: The Picture Element.


Responsive Images 101 Series
  1. Definitions
  2. Img Required
  3. Srcset Display Density
  4. Srcset Width Descriptors
  5. Sizes
  6. Picture Element
  7. Type
  8. CSS Responsive Images
  9. Image breakpoints

Footnotes
  1. How quickly we forget web-safe colors, Lynda Weinman‘s multiple books on web graphics, and the way different images formats compress. And it’s not getting any simpler. Images on the web are inherently complex.
  2. Super hero by Ashley Rose. Dog Intelligence by Alice Jamieson. Licensed under Creative Commons.

Responsive Images 101, Part 4: Srcset Width Descriptors

In Part 3, we looked at display density descriptors and concluded that they are great for fixed width images, but are insufficient for flexible images.

Flexible images is where srcset’s width descriptors shine.

Width descriptors

The syntax for width descriptors is similar to that of display density descriptors. The value of the srcset attribute is a comma-separated list of image sources and descriptors.

Srcset syntax with width descriptors. Repeated below.

The difference is that instead of having 1x, 2x, and other values representing the density, we now list the width of the image source such as 320w, 480w, etc.

<img src="cat.jpg" alt="cat" 
  srcset="cat-160.jpg 160w, cat-320.jpg 320w, cat-640.jpg 640w, cat-1280.jpg 1280w">

The width of the image source can cause some confusion. Width descriptors are looking for the resolution of the source file.

In other words, if you open the image in an image editor, what does it say the resolution is? Grab the width and put it in the srcset attribute.

The browser picks the best source?

When you use width descriptors, you’re providing the browser with a list of images and their true widths so that it can select the best source. How does the browser do that?

Your first instinct is probably to say that the browser looks at the size of the element in the page and compares it to the list of source sizes. That makes sense, but it isn’t how the selection work.

See, when a browser starts downloading images, it often doesn’t know the size of the image in the page.

Browser pre-loader and speculative asset downloading

If you look at a timeline of how a browser renders a page, you’ll notice something striking.

AnEventApart.com Chrome timeline

Shortly after the browser downloads the HTML, it requests CSS and JavaScript. But before the CSS and JavaScript is done loading, the browser starts downloading images.

Because neither the CSS nor JavaScript is complete, the browser is downloading images without knowing what the layout of the page will be. And without knowing the layout, it doesn’t know what size the image element will be.

BTW, this pre-loading behavior is why we can’t solve inline responsive images using CSS or JavaScript. They aren’t available when the browser starts downloading.

The only thing that the browser does know is the size of the viewport. Once we move past display density descriptors, everything hinges on the size of the viewport.

Why does this matter?

The viewport can be a poor substitute for the actual size of the image. Take the images on Walmart’s Grocery site:

Small screen version of delivery.walmart.com showing that images are nearly full width of page.

On narrow viewports, the images are nearly the same size as the viewport width. They are certainly close enough to work.

Wider screens, however, are a different matter:

Wide screen version of delivery.walmart.com showing how images are much smaller than the viewport.

In the second example, the viewport is 1540px wide, but the images are only 254px wide. Knowing the size of the viewport won’t tell the browser enough information to be able to select the right image source.

Sizes to the rescue!

How do we tell the browser about the size of the image in the page so that it can download the right source from our srcset list? Use use the sizes attribute!

Read more in Part 5: Sizes.


Responsive Images 101
  1. Definitions
  2. Img Required
  3. Srcset Display Density
  4. Srcset Width Descriptors
  5. Sizes
  6. Picture Element
  7. Type
  8. CSS Responsive Images
  9. Image breakpoints

Responsive Images 101, Part 3: Srcset Display Density

Ever since Apple launched a retina display on the iPhone 4, web designers have been looking for a way to handle high density displays. That is where srcset and its display density descriptors come in.

Resolution switching uses srcset

As a reminder, display density is a resolution switching use case. And when we’re solving for resolution switching, we want to use srcset.1

The reason why we want to use srcset is because it gives the browser choice. When we use the media attribute provided by the <picture> element, we’re dictating to the browser what image it must use. That makes sense for art direction.

But when it comes to resolution switching, the browser knows best what image will work. It can make decisions based on factors that we’re not privy to such as network conditions or user preference.

So unless we are doing art direction, we should strive to give the browser options and let it make smart decisions.

Display density descriptors

The syntax for display density is fairly straight forward:

srcset example repeated below

The srcset attribute is added to an <img> element. The value of srcset contains a comma-separated list. Each item in the list contains the path to an image and the density of that image provided as a multiple (e.g., 1x, 2x, 3x…).

<img src="cat.jpg" alt="cat" srcset="cat.jpg, cat-2X.jpg 2x">

The display density values—the 1x, 2x, etc.—are referred to as display density descriptors. If a display density descriptor isn’t provided, it is assumed to be 1x.

That seems easy…

It is easy—assuming all you care about is display density. I have my doubts about how often that will happen.

Let’s take a look at the Apple Watch image from Part 1:

Apple Watch Hero Image

As mentioned previously, the image is 5144×1698 pixels and 398K in its 2x incarnation. There is also a 1x version. Let’s compare them to the size that would make sense for a single density, Blackberry Curve 9310:

Image Width Height File Size
2x large 5144 1698 398K
1x large 2572 849 256K
320px, Single Density 320 106 8K

For the final row in the table, I resized the image to 320px wide and saved as a JPEG in order to estimate what it would be.

It should be obvious that two sizes of an image aren’t sufficient. Sure, we could start at 320 as 1x and then rewrite our markup to look something like this:

<img srcset="cat.jpg, cat-2X.jpg 2x, cat-3x.jpg 3x, […], cat-16x.jpg 16x">

That will get us from 320px to the 5144px of the largest image, but it seems insane to me.

And this highlights another reason why I find the display density descriptors to be less desirable than other solutions. I don’t have any interest in keeping track of all of the different display densities available.

Do we want to provide 1x, 1.5x, 2x, 3x variants? What about accounting for things like the iPhone 6 Plus’s downsampling?

Not to mention what happens when you start working with flexible images. Now you have multiple densities at multiple image breakpoints. And sometimes you’re repeating your image sources because 2x at a small size could be the same as 1x resolution at a larger image breakpoint.

It gets messy quickly.

Display density descriptors are best for fixed width images

The moment you move beyond providing alternate densities of a fixed width img element, the display density descriptor becomes unwieldy and inadequate to the task.

What do you need instead? Part 4: Srcset Width Descriptors.


Responsive Images 101 Series
  1. Definitions
  2. Img Required
  3. Srcset Display Density
  4. Srcset Width Descriptors
  5. Sizes
  6. Picture Element
  7. Type
  8. CSS Responsive Images
  9. Image breakpoints

Footnotes
  1. Unless we’re providing different image formats which we will cover later.