If you don't like the
Example: See a live example of a CSS-only responsive image.
Example: See a live example of a CSS-only responsive image that scales proportionally.
CSS-Only Responsive Images
Here's a quick preview of the technique. This method for responsive images uses CSS in a
<style> tag to make a
First is some generic CSS that belongs in a global stylesheet and can be used for all responsive images. The CSS is for making the
<span> behave more like a native
<img>. The key to this is
display: inline-block and
NOTE: please see below for an explanation of this CSS.
Second is the base HTML for all responsive images. Essentially the HTML below will replace each
<img> tag that needs to respond to media queries. Of course the media queries themselves should be placed inside the
NOTE: The media queries are explained in step 4 below.
Part 1: Responsive Images Using CSS
src of an
<img>, I'm proposing that using CSS background images is probably good enough and avoids most of the pitfalls of the other techniques. It's fairly easy to make a
<span> with a background image behave exactly like a real
<img> with some basic CSS, primarily relying on
display: inline-block and
Of course, moving every in-page image on your site to your global stylesheets is impractical and ill-advised. The images we're talking about are part of the content and have no place in your site's global styles; they're very likely to be managed by a CMS. The solution is to embed the styles in the HTML by placing a
<style> tag in the
<body> instead of in the global stylesheet.
A recent draft of HTML5 spec would allow for
<style> tags in the
<body> as long as they carry a
scoped attribute (although this currently won't validate). Using a
<style> tag this way is only marginally different than the usage of
<source> as proposed in the picturefill method and it's certainly less confusing than the srcset proposal. Using CSS carries with it the benefit of a familiar, flexible syntax and broad browser support. This also avoids relying on an emerging and contentious standard.
Start with a Regular Image
To start, we need a regular
<img> that we wish was responsive. The example below is just that: a boring old image that doesn't do anything special.
Example: See a live example even though this isn't responsive and is just a regular image.
Step 1: Use a SPAN
In order to fake an image using CSS, we need to start with a
<span>. Because a
<span> is inline by default,
display: inline-block is supported on that element in IE6 and IE7. There's long been a usable hasLayout hack that makes IE6 and IE7 apply inline-block to any element but — to me at least — a
<span> is already closer to the image layout we want before any styles have been applied. For now we'll place the alt text inside the
<span> but we'll fix that in the next step.
Below you can see a simple
<span> with an
.image class ready to be styled.
Example: See a live example although there's not much to see yet.
NOTE: You could use a fictional tag like
<picture> instead of
<span> but that would require a shim for IE6, IE7 and IE8. You could also use
<div> instead of
<span> without any adverse effects.
Step 2: Add an ARIA Role
ARIA supplies a
role="img" for a container that visually represents an image. Applying this will help ARIA-enabled browsers understand what this
<span> is used for. ARIA also specifies that the
role="img" is not labeled by its contents so we need to move the alt text to the
Below you can see the
<span> with an ARIA
role applied and the alt text moved to an ARIA label.
Example: See a live example although there's still not much to see.
Step 3: Generic Styles for All Images
Now that we've got the mark-up for an accessible image, we need to make it behave like an image using some CSS. This CSS is generic to all
.image elements and can be placed in your global stylesheets.
First we'll use Compass to generate our generic styles. Although Compass isn't available in a browser, it's a good start for generating the default styles needed for our new
.image elements. Compass already has some mixins for cross-browser inline-block, squishing text and vendor-prefixed background-size. This helps immensely because they've already done the research for us to make this work seamlessly across all browsers. (If you're unfamiliar, learn how to get started with Sass and Compass.)
display: inline-blockmakes the
<span>behave like an
<img>. Inline-block allows the element to follow the document flow like an inline element but it can also have dimension (height and width) like a block element. Here's an article about inline-block.
- Squishing text is preferred to hiding text in this case because of some issues with text-indent in mobile WebKit.
background-size: 100%forces the background image to stretch to the full size of the element so that it behaves like a real image. Read about
background-position: 50% 50%helps out browsers that don't support
background-sizeby keeping the image centered in the
background-repeat: no-repeatkeeps the background from repeating.
Below is the example SCSS code that was used to generate the generic CSS needed for this technique. Again, generating styles with Compass is an unnecessary step in this case but it was included as a shortcut explanation for all of the crazy styles required for cross-browser support.
Once compiled, the SCSS code above looks like the following CSS. The generic styles for
.image can be shared for all responsive images on the page. That helps make the specific styles for the individual responsive images more compact and readable. The code below is ready to use and should be placed in your site's global stylesheets.
Example: See a live example although there's yet again not much to see.
NOTE: IE6, IE7 and IE8 (and some other legacy browsers) don't support
background-size. This only affects those browser's ability to scale the image. It will work just fine for a fixed-dimension image that is shown at its default size. See background-size support on When Can I Use. It's important to note that support for media queries closely matches support for
background-size. Basically it's safe to assume that a browser that doesn't support media queries also doesn't support background-size and vice versa. So your fall-back styles in the next step should take that limitation into account.
Step 4: Specific Styles for the Individual Image
Now it's time to apply the background image to our
<span>. We don't want to place these styles in the global stylesheet because our image is specific to the content of our page. The rule of thumb is that if you'd normally use an
<img> you probably want it to be in-page using this technique. For each image we'll be placing a
<style> element just above it. Each image also needs a unique ID to make sure our styles are applied to the correct image. Although placing a
<style> element in the body is not technically allowed in HTML, it actually works just fine in all browsers.
For each media query we need to provide a background image and a height and width. The result is very similar to the mark-up for the Picturefill solution proposed for the
<picture> tag. Although using a
<style> tag is decidedly more verbose — CSS is not known for brevity — it doesn't require the weird duplicative HTML comments
The example below shows the
<style> element just above our
<span> with all of the styles for our responsive image. In this example the fall-back is the desktop version but otherwise a mobile first approach is used in the media queries. The media queries below are simple examples and your project will undoubtedly require different break points.
- The fall-back should probably be the default desktop image.
- Each media query should supply a
background-imageas well as the
widthbecause the browser can't guess the size of a background image the way it can with regular
- Other necessary styles like
background-size: 100%are handled by the global CSS styles described in step 3 above.
<span>must be given a unique ID to ensure that styles are applied correctly.
Example: See a live example; now we're in business.
NOTE: Although the vast majority of examples on the web recommend adding the smallest, mobile optimized image as the fall-back, I prefer to supply the default desktop image to the browsers that don't support media queries. The only browsers that get the fall-back image are browsers that don't support media queries, and those browsers are almost exclusively IE6, IE7 and IE8. Supplying the mobile image as the fall-back is silly considering that there aren't any mobile browsers with any noticeable marketshare that require the fall-back. The mobile browsers we're targeting all support media queries.
In general, I'm of the opinion that browsers that don't natively support responsive design should simply be served the vanilla desktop experience, since that's almost certainly what those users were expecting anyway.
Step 5: Add in Scoped
To make ourselves feel better about using invalid markup, let's add
scoped to our style tag to at least conform to the new HTML5 standard. This won't make our code validate any better than it would have otherwise and support for the
scoped attribute is currently non-existent.
The lack of support for
scoped means that we'll have to keep using the
id in our styles instead of being able to use more generic
.image to add the background image and dimensions. That's ok though; we're only adding in the scoped attribute to appear to be writing valid markup and to hopefully prepare for future compatibility and validity. WebKit already has experimental support and other browsers are sure to follow.
<style> elements need a wrapper element to define, well…the scope. If we use an inline element like a
<span> as the wrapper it will automatically shrink-wrap our responsive image and not have any negative effect on our layout. (**UPDATE:** It appears that inline elements are not valid style scopes)
Below you can see the identical markup from step 4 with the addition of the
scoped attribute and a new
.image-scope element. The
.image-scope element doesn't require any additional styles because it is a
<span> and is
display: inline already.
Example: See a live example that looks exactly the same as step 4.
NOTE: Because of the lack of browser support for
scoped, this step is completely optional and only serves to make the mark-up slightly more compliant. Even then, using
scoped is pretty controversial — there's severe backwards compatibility issues — and you may wish to skip it altogether.
Part 2: Proportionally Scaling Responsive Images
When working with responsive design, it's becoming increasingly popular to use fluid layouts to ensure that the content is fitting the screen properly. When using a normal
<img> it's easy to support scalable dimensions by defining only the width of the image with a percentage and letting the browser proportionally scale the image height. Although it requires some ingenuity, the responsive image techniques described above can also be combined with proportional scaling.
Below is an example of how this is handled with a normal image. The
<img> will scale proportionally, meaning the width will always match the width of its container. The height will always be the appropriate height. This way the image will never appear stretched or distorted. This trick is useful for fluid layouts where you don't know the exact width of the column.
Example: See a live example even though this isn't responsive and is just a regular image. It does scale proportionally though.
Step 1: Adding an Inner Element
Background images can't affect layout, which forces us to define a fixed height and width to use the responsive techniques outlined above. So it's not immediately obvious how to proportionally scale the height of the
<span>. The solution is to use a percentage
padding-top on an inner element to provide the proportionate height (see padding on MDN).
padding, percentages are defined relative to the parent element's width. Somewhat counter-intuitively,
padding-top is also defined as a percentage of the parent element's width — not the height as you might expect. Using
padding-top on an inner element allows the height to be proportionally scaled.
Below is the
.image as described above with an additional
Example: See a live example although it doesn't scale yet.
Step 2: Adding More Generic Styles
.inner element needs to be set to
display: block so that it can have dimensions applied. The
height: 0 is required because it gets its height from padding that is applied in the
<style> element. The CSS below should be added to the generic CSS created in step 3 above.
Example: See a live example although it still doesn't scale.
Step 3: Responsive, Proportionally-Scaled Images
As mentioned above, the height of the
.inner element comes from a percentage applied to
padding-top. The percentage is calculated by dividing the height of the source image by the width. For instance, if an image is 200 pixels wide and 100 pixels tall, the
padding-top would be 50% (100px / 200px * 100% = 50%).
The example below allows the responsive image to scale proportionally.
Example: See a live example that should scale proportionally as expected in browsers that support
NOTE: As mentioned above, proportional scaling will only work in browsers that support
background-size. Unsupported browsers will simply show the background at full-size, centered inside the
<span>. If the
<span> is smaller than the image in IE8 and below, the image will appear clipped.
<picture> tag requires multiple
The biggest concern is how to roll out responsive images over a large organization. What happens if a large corporation upgrades their website with a new responsive design to take full advantage of the rapidly growing mobile market? Should they roll out the
<picture> tag or the
srcset solutions? Should they roll out a complicated
<style scoped> solution like what's proposed above? No matter what path is chosen, the result is going to be slightly messy because there are no CMS that currently provide a nice solution for managing responsive images across a large organization.
Although most people are probably not going to be comfortable faking images using a
<span> and an embedded
<style> tag, I believe the immediate browser support and predictable behavior of this solution make it a compelling addition to the responsive image conversation.