Odo Responsive Images

Native responsive images with deferred loading.

The main purpose of this component is to lazy-load responsive images. After deciding when to load the image, it uses picturefill and native responsive images. This component does not control which sources are chosen for the image.

Support

IE9+ (with a classList polyfill).

Dependencies

Picturefill, Odo Viewport, debounce (bundled), Array.from.

Styles

This component has required css - css/odo-responsive-images.css.

Usage

Images are not immediately watched, you must call initialize(). This allows you to change the OdoResponsiveImages class before anything meaningful happens.

import OdoResponsiveImages from '@odopod/odo-responsive-images';
OdoResponsiveImages.initialize();

Deferred Loading

To defer the loading, do not use a <picture> element. Use a <div> and add the odo-responsive-img class.

picture 1 description

Markup

IE9 Conditional Comments

To support IE9, you will need to wrap a video element wrapper around the source elements in your picture tag. You can do this using conditional comments, like so:

<div class="odo-responsive-img">
  <!--[if IE 9]><video style="display: none;"><![endif]-->
  <source srcset="https://source.unsplash.com/category/buildings/800x400" media="(min-width: 992px)">
  <source srcset="https://source.unsplash.com/category/technology/600x300" media="(min-width: 768px)">
  <source srcset="https://source.unsplash.com/category/nature/400x200">
  <!--[if IE 9]></video><![endif]-->
  <img alt="picture 1 description">
  <noscript>
    <img src="https://source.unsplash.com/category/nature/400x200" alt="picture 1 description">
  </noscript>
</div>

Avoid Multiple Image Downloads

In order to avoid downloading more than one image for a single picture, the <img>’s src and srcset attributes are left blank. If src is set, any browser which does not support <picture> could potentially download multiple images. If srcset is set, any browser which supports srcset but does not support <picture> could potentially download multiple images.

However, this means in order to support JavaScript-disabled browsers (and possibly search engines), you will need a fallback image wrapped in <noscript>. Please note, the <noscript> is not added to the generated <picture> element.

Hi Resolution Support

To support retina screens, simply modify the srcset attribute. The Opera developer blog has a great article with many different combinations for images sizes, hi-dpi screens, mime-types, and art direction. I highly recommend looking at that article to give you an idea of how to structure your responsive image.

Here is a simple example using the 2x descriptor in the srcset. On a non-retina screen, you will see an image from the “architecture”, “animals”, or “nature” categories of placeimg depending on your screen size. For retina screens, you will see the same categories in grayscale.

picture 1 description
<div class="odo-responsive-img">
  <!--[if IE 9]><video style="display: none;"><![endif]-->
  <source srcset="https://placeimg.com/800/400/arch 1x, https://placeimg.com/1600/800/arch/grayscale 2x" media="(min-width: 992px)">
  <source srcset="https://placeimg.com/600/300/animals 1x, https://placeimg.com/1200/600/animals/grayscale 2x" media="(min-width: 768px)">
  <source srcset="https://placeimg.com/400/200/nature 1x, https://placeimg.com/800/400/nature/grayscale 2x">
  <!--[if IE 9]></video><![endif]-->
  <img alt="picture 1 description">
  <noscript>
    <img src="https://placeimg.com/400/200/nature" alt="picture 1 description">
  </noscript>
</div>

Background Images

You can add a data-type="background" attribute to set visibility hidden on the <img> element and have the responsive image component set the background-image property of your responsive image to that image's source.

picture 2 description
<div class="odo-responsive-img" data-type="background">
  <!--[if IE 9]><video style="display: none;"><![endif]-->
  <source srcset="https://placeimg.com/800/400/arch" media="(min-width: 992px)">
  <source srcset="https://placeimg.com/600/300/animals" media="(min-width: 768px)">
  <source srcset="https://placeimg.com/400/200/nature">
  <!--[if IE 9]></video><![endif]-->
  <img alt="picture 2 description">
  <noscript>
    <img src="https://placeimg.com/400/200/nature" alt="picture 1 description">
  </noscript>
</div>

Using img[srcset]

Odo Responsive Images also work with the native srcset attribute for responsive images. The key difference is you must use a data-srcset attribute instead of srcset. This also works with the data-type="background" attribute.

I have a source set

Since JavaScript adds the srcset attribute, there should also be a <noscript> with a fallback image.

<div class="odo-responsive-img">
  <img data-srcset="
    https://placehold.it/400x200/e74c3c/ffffff&text=srcset+-+400x200 400w,
    https://placehold.it/600x300/e74c3c/ffffff&text=srcset+-+600x300 600w,
    https://placehold.it/800x400/e74c3c/ffffff&text=srcset+-+800x400 800w,
    https://placehold.it/1200x600/e74c3c/ffffff&text=srcset+-+1200x600 1200w" sizes="(min-width:1291px) 1200px, 93vw" alt="I have a source set">
  <noscript>
    <img src="https://placehold.it/400x200/e74c3c/ffffff&text=srcset+-+400x200" alt="I have a source set">
  </noscript>
</div>

Simple Carousel

Demonstrating how the responsive images will work inside a carousel and similar components with off-screen images.

Immediate Loading

To load responsive images without deferred loading, simply use the native picture syntax. If you check the network profile for this page load, you will notice that these two images load first.

picture 1 description
I have a source set

Picture Syntax

Picture should be used for responsive images which require art-direction. For example, an image set which has different ratios or crops at different sizes.

<picture>
  <!--[if IE 9]><video style="display: none;"><![endif]-->
  <source srcset="https://placeimg.com/800/400/arch" media="(min-width: 992px)">
  <source srcset="https://placeimg.com/600/300/animals" media="(min-width: 768px)">
  <source srcset="https://placeimg.com/400/200/nature">
  <!--[if IE 9]></video><![endif]-->
  <img alt="picture 1 description">
</picture>

Srcset Syntax

Each image in a source set should be the exact same, except at a different size/scale. This allows the browser to choose which image is best for the user given its current conditions (i.e. network, pixel density, signal strength).

<img srcset="
  https://placehold.it/400x200&text=srcset+-+400x200 400w,
  https://placehold.it/600x300&text=srcset+-+600x300 600w,
  https://placehold.it/800x400&text=srcset+-+800x400 800w" sizes="50vw" alt="I have a source set">

Public Methods & Properties

OdoResponsiveImages is a singleton. It exposes a few methods and properties which can be useful.

updateOffsets()

If the offset of an image changes without the page scrolling, OdoViewport will not know and neither will this component. A responsive image inside a carousel, for example, will need to be notified when the slide changes. This method is debounced at 300ms.

OdoResponsiveImages.updateOffsets();

flush()

Cleans up all references and listeners for current images. OdoResponsiveImages will no longer be doing anything until a new image is added.

OdoResponsiveImages.flush();

add(element)

Add more images for the responsive images component to watch. The first parameter is an element or array of elements. The element should be the parent element of the <img>.

OdoResponsiveImages.add(myResponsiveImage);

remove(element)

Remove images from the responsive images component. The first parameter is an element or array of elements. The element should be the parent element of the <img>. This method is useful when you are completely removing content from the DOM.

OdoResponsiveImages.remove(myResponsiveImage);

load(element)

Force the load of an element or group of elements instead of waiting for it to come into the viewport. The first parameter is an element or array of elements. The element should be the parent element of the <img>.

OdoResponsiveImages.load(myResponsiveImage);

images

An array of viewport item id strings and picture elements. Once an image loads, it is removed from this list unless it is a background image.

OdoResponsiveImages.images

ClassName

The class name strings for Odo Responsive Images.

OdoResponsiveImages.ClassName = {
  IMAGE: 'odo-responsive-img',
  LOADED: 'odo-responsive-img--loaded'
}

Deferred

picture 1 description
picture 2 description

Deferred

picture 1 description
picture 1 description

Deferred

picture 1 description
picture 2 description

Deferred

picture 1 description
picture 2 description

Background image stretching beyond both edges

picture 1 description
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

Deferred

picture 1 description
picture 2 description