Progressive image rendering

 

 

 

 

Привет!

What will we see today?

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Improve perceived performance of images on the web

PROGRESSIVE IMAGE RENDERING

@jmperezperez

by

- not making requests

- optimizing images

- rendering previews

PROGRESSIVE IMAGE RENDERING

@jmperezperez

PROGRESSIVE IMAGE RENDERING

@jmperezperez

About me

Page Load Time

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Version A

FrontFest

2017

Speakers & Schedule

0.0s

0.3s

0.6s

0.9s

1.2s

Version B

FrontFest

2017

Speakers & Schedule

0.0s

0.3s

0.6s

0.9s

1.2s

FrontFest

2017

Speakers & Schedule

FrontFest

2017

FrontFest

2017

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Source https://www.smashingmagazine.com/2015/11/why-performance-matters-part-2-perception-management/

PROGRESSIVE IMAGE RENDERING

@jmperezperez

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Speed Index = \int_0^{end} 1 - \frac{VC}{100}
SpeedIndex=0end1VC100Speed 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

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

1,815kB (54%)

scripts

457kB (14%)

other

1,106kB (33%)

source: http archive 1 nov 2017

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

Responsive

TIP 2

1 column

2 columns

3 columns

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

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

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Using image.decode()

IMAGE DECODING

// Image loading with predecoding

const img = new Image();
img.src = "image.jpg";
img.decode().then(() => {
    document.body.appendChild(img);
}).catch(() => {
    throw new Error('Could not load/decode big image.');
});

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Using image.decode()

IMAGE DECODING

Add an image to the DOM without causing a decoding delay.

TIP 4

What to show while the image is loading

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Options

PROGRESSIVE IMAGE RENDERING

PLACEHOLDERS

Nothing

Placeholder

Solid colour or gradient

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

Thumbnails

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Thumbnails

Getting creative with SVGs

PROGRESSIVE IMAGE RENDERING

@jmperezperez

PROGRESSIVE IMAGE RENDERING

@jmperezperez

SVG - Edges

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Drawing edges with SVG

PROGRESSIVE IMAGE RENDERING

@jmperezperez

Drawing bitmap images

Canny Edge Detector

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

SVG - Shapes

PROGRESSIVE IMAGE RENDERING

@jmperezperez

PROGRESSIVE IMAGE RENDERING

@jmperezperez

SVG - Shapes

SVG - 10 shapes

SVG - 100 shapes

Original

0.74kB

3.5kB

101kB

PROGRESSIVE IMAGE RENDERING

@jmperezperez

SVG - Shapes + Blur

SVG - 10 shapes + Blur

SVG 100 shapes + Blur

(JPEG or WebP) + Blur

0.8kB

3.6kB

0.5kB (JPEG)
0.09 kB (WebP)

PROGRESSIVE IMAGE RENDERING

@jmperezperez

SVG - Silhouettes / Traces

PROGRESSIVE IMAGE RENDERING

@jmperezperez

SVG - Silhouettes / Traces

PROGRESSIVE IMAGE RENDERING

@jmperezperez

SVG - Silhouettes / Traces

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
  • Think about placeholders
  • Innovate!

Summary

The Web is fun.

PROGRESSIVE IMAGE RENDERING

@jmperezperez

talk with me for more info

Thanks!

@jmperezperez

Slides on https://slides.com/jmperez