Progressive image rendering

 

 

PROGRESSIVE IMAGE RENDERING

@jmperezperez

About me

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Page Load Time

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Version A

JSDayES

Madrid

2017

Speakers & Schedule

0.0s

0.3s

0.6s

0.9s

1.2s

Version B

JSDayES

Madrid

2017

Speakers & Schedule

0.0s

0.3s

0.6s

0.9s

1.2s

JSDayES

Madrid

2017

Speakers & Schedule

JSDayES

Madrid

2017

JSDayES

Madrid

2017

PROGRESSIVE IMAGE RENDERING

@jmperezperez

User Perceived Performance

PROGRESSIVE IMAGE RENDERING

@jmperezperez

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Speed Index = \int_0^{end} 1 - \frac{VC}{100}

end = end time in milliseconds

VC = % visually complete

PROGRESSIVE IMAGE RENDERING

@jmperezperez

WebPageTest

PROGRESSIVE IMAGE RENDERING

@jmperezperez

More kilobytes

 

improved perceived performance

can sometimes lead to

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Avoiding this:

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Techniques to improve perceived performance

  • Server-side rendering
  • Critical CSS
  • Async JS
  • Async fonts

PROGRESSIVE IMAGE RENDERING

@jmperezperez

What about images?

PROGRESSIVE IMAGE RENDERING

@jmperezperez

PROGRESSIVE IMAGE RENDERING

@jmperezperez

images

1712kB (66%)

scripts

426kB (16%)

other

464kB (18%)

source: http archive 15 apr 2017

To use or not to use images

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Minimalist | Flat Design

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Not that long ago

Optimise your images

PROGRESSIVE IMAGE RENDERING

@jmperezperez

TIP 1

PROGRESSIVE IMAGE RENDERING

@jmperezperez

right format

gif | png | jpg | webp | <the_next_thing>

PROGRESSIVE IMAGE RENDERING

@jmperezperez

<picture>
    <source type="image/webp" srcset="2700x1209/my-image.webp 2700w, 
                    1024x1024/my-image.webp 1024w, 
                    600x600/my-image.webp 600w" 
            sizes="100vw" />
    <source srcset="2700x1209/my-image.jpg 2700w, 
                    1024x1024/my-image.jpg 1024w, 
                    600x600/my-image.jpg 600w" 
            sizes="100vw" />
    <img class="rsImg" src="600x600/my-image.jpg" alt="My beautiful image" />
</picture>

compression

PROGRESSIVE IMAGE RENDERING

@jmperezperez

· lossless

· perceptual

PROGRESSIVE IMAGE RENDERING

@jmperezperez

1 column

2 columns

3 columns

Responsive

TIP 2

<img sizes="(max-width: 30em) 100vw,
            (max-width: 50em) 50vw,
            calc(33vw - 100px)"
     srcset="profile-200.jpg 200w,
             profile-400.jpg 400w,
             profile-800.jpg 800w,
             profile-1600.jpg 1600w"
     src="profile-400.jpg" alt="Pinchito">

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Challenge: Keeping in sync markup and CSS

Example

RESPONSIVE IMAGES

Lazy-load images

PROGRESSIVE IMAGE RENDERING

@jmperezperez

TIP 3

<img> above the fold

&

Lazy below the fold

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Intersection

Observer

PROGRESSIVE IMAGE RENDERING

@jmperezperez

// load image when it's within 100px of the viewport

const options = {
  rootMargin: '100px'
}

const callback = entries => { 
  entries.forEach(entry => {
    if (entry.intersectionRatio > 0) {
        // load image
    }
  });
};

const observer = new IntersectionObserver(callback, options);
observer.observe(document.querySelector('.lazy-img'));

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Example

INTERSECTION OBSERVER

class LazyImage extends React.Component {

    constructor() {
        this.observer = new IntersectionObserver(entries => {
            if (entries[0].intersectionRatio > 0) {
                // load!
            }
        });
        this.element = null;  /* render() will set it through a ref */
    }

    componentDidMount() {
        this.observer.observe(this.element);
    }

    componentWillUnmount() {
        this.observer.unobserve(this.element);
    }
    ...
}

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Encapsulating in React

INTERSECTION OBSERVER

What to show while the image is loading

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Options

PROGRESSIVE IMAGE RENDERING

PLACEHOLDERS

Nothing

Placeholder

Solid colour

Progressive image loading or "Blur-up"

@jmperezperez

Examples of solid color

PROGRESSIVE IMAGE RENDERING

@jmperezperez

PROGRESSIVE IMAGE RENDERING

@jmperezperez

PROGRESSIVE IMAGE RENDERING

@jmperezperez

PROGRESSIVE IMAGE RENDERING

@jmperezperez

PROGRESSIVE IMAGE RENDERING

@jmperezperez

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Examples of

Progressive Image Loading

PROGRESSIVE IMAGE RENDERING

@jmperezperez

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Medium

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Medium

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Quartz (qz.com)

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Quartz (qz.com)

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Quora

PROGRESSIVE IMAGE RENDERING

@jmperezperez

How it is done

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Markup - Eg Medium

<figure>
  <div>

    <div/> <!-- this div keeps the aspect ratio so
                the placeholder doesn't collapse -->

    <img/> <!-- this is a tiny image with a small
                resolution (e.g. ~27x17) and low quality -->

    <canvas/> <!-- takes the above image and applies a blur filter -->

    <img/> <!-- the large image to be displayed -->

    <noscript/> <!-- fallback for no JS -->

  </div>
</figure>

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Progressive JPEGs

Baseline

Progressive

PROGRESSIVE IMAGE RENDERING

@jmperezperez

With the Progressive JPEG method [...] cognitive fluency is inhibited and the brain has to work slightly harder to make sense of what is being displayed.

— From Progressive image rendering: Good or evil?

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Facebook

Inlining thumbnail image in payload

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Facebook

 

Unfortunately, the standard JPEG header is hundreds of bytes in size. In fact, the JPEG header alone is several times bigger than our entire 200-byte budget. However, excluding the JPEG header, the encoded data payload itself was approaching our 200 bytes.

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Facebook

Header (Quantization Table and Huffman Table) Compressed
Data

Client (mobile app)                                                GraphQL

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Thumbnails

Getting creative with SVGs

PROGRESSIVE IMAGE RENDERING

@jmperezperez

PROGRESSIVE IMAGE RENDERING

@jmperezperez

SVG

PROGRESSIVE IMAGE RENDERING

@jmperezperez

SVG

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Drawing with SVG

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Drawing bitmap images

Canny Edge Detector

PROGRESSIVE IMAGE RENDERING

@jmperezperez

PROGRESSIVE IMAGE RENDERING

@jmperezperez

<svg>
  <polyline points="51,1 61,1 61,2 56,4 56,3"/>
  <polyline points="52,1 50,2 51,3 50,4 50,9 46,10 46,8 48,8 48,9"/>
  <polyline points="61,4 61,5 58,6"/>
  ...
  <polyline points="62,58 61,59 61,60 50,62 50,61 51,61"/>
</svg>
  1. Find edges with canny edge detector
  2. Create lines
  3. Use JS and SVG to animate

How to draw bitmaps

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Should we do this?

Just because you can it doesn't mean you should

PROGRESSIVE IMAGE RENDERING

@jmperezperez

  • Reduce requests
  • Choose the right format and optimise
  • Embrace responsive images
  • Try to lazy load
  • Innovate!

Summary

The Web is fun.

PROGRESSIVE IMAGE RENDERING

@jmperezperez

talk with me for more info

Thanks!

@jmperezperez

Progressive Image Rendering

By José M. Pérez

Progressive Image Rendering

This talk addresses the culprit in page size, images. I feel that we like discussing JS and CSS and its payload, but we tend to forget about images, which represent 2/3 of the bytes of a page. The most performant request is the one that is never done, and this beats any possible image optimization. There are some common scenarios in which we can avoid using images, being adopting a minimalism/flat design or hiding certain images on smaller screens. Of course, we will need to use some images eventually. For these cases I explain how the picture element might help and some of its limitations I have found when working with real websites. One of them is lazy loading of images, which can bring great savings in terms of data traffic, but it is also easy to implement wrongly. Lastly I show some techniques to "fill" the space for an image while it is loaded, going from just showing an empty area to doing a progressive loading from a blurry image.

  • 6,631