Progressive Image Rendering

A presentation at FrontFest in November 2018 in Moscow, Russia by José M. Pérez

Slide 1

Slide 1

Progressive image rendering José M. Pérez · Web dev at Spotify @jmperezperez

Slide 2

Slide 2

PROGRESSIVE IMAGE RENDERING @jmperezperez Привет! What will we see today?

Slide 3

Slide 3

PROGRESSIVE IMAGE RENDERING @jmperezperez Improve perceived performance of images on the web

Slide 4

Slide 4

PROGRESSIVE IMAGE RENDERING @jmperezperez by - not making requests - optimizing images - rendering previews

Slide 5

Slide 5

PROGRESSIVE IMAGE RENDERING @jmperezperez About me

Slide 6

Slide 6

PROGRESSIVE IMAGE RENDERING @jmperezperez Page Load Time

Slide 7

Slide 7

PROGRESSIVE IMAGE RENDERING @jmperezperez 0.0s 0.3s 0.6s 0.9s 1.2s FrontFest 2017 Version A Speakers & Schedule 0.0s Version B 0.3s FrontFest 2017 0.6s FrontFest 2017 0.9s FrontFest 2017 Speakers & Schedule 1.2s FrontFest 2017 Speakers & Schedule

Slide 8

Slide 8

PROGRESSIVE IMAGE RENDERING @jmperezperez Source https://www.smashingmagazine.com/2015/11/why-performance-matters-part-2-perception-management/

Slide 9

Slide 9

PROGRESSIVE IMAGE RENDERING @jmperezperez SpeedIndex = end ∫0 end = end time in milliseconds VC = % visually complete 1− VC 100

Slide 10

Slide 10

PROGRESSIVE IMAGE RENDERING @jmperezperez WebPageTest

Slide 11

Slide 11

PROGRESSIVE IMAGE RENDERING @jmperezperez

Slide 12

Slide 12

PROGRESSIVE IMAGE RENDERING @jmperezperez Avoiding this:

Slide 13

Slide 13

PROGRESSIVE IMAGE RENDERING @jmperezperez Techniques to improve perceived performance Server-side rendering Critical CSS Async JS Async fonts

Slide 14

Slide 14

PROGRESSIVE IMAGE RENDERING @jmperezperez What about images?

Slide 15

Slide 15

PROGRESSIVE IMAGE RENDERING @jmperezperez images scripts other 1,815kB (54%) 457kB (14%) 1,106kB (33%) source: http archive 1 nov 2017

Slide 16

Slide 16

PROGRESSIVE IMAGE RENDERING @jmperezperez Minimalist | Flat Design

Slide 17

Slide 17

PROGRESSIVE IMAGE RENDERING @jmperezperez Not that long ago

Slide 18

Slide 18

PROGRESSIVE IMAGE RENDERING @jmperezperez TIP 1 Optimise your images

Slide 19

Slide 19

PROGRESSIVE IMAGE RENDERING @jmperezperez

Slide 20

Slide 20

PROGRESSIVE IMAGE RENDERING @jmperezperez right format gif | png | jpg | webp | <the_next_thing> <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>

Slide 21

Slide 21

PROGRESSIVE IMAGE RENDERING @jmperezperez compression · lossless · perceptual

Slide 22

Slide 22

PROGRESSIVE IMAGE RENDERING @jmperezperez TIP Responsive 1 column 2 columns 3 columns 2

Slide 23

Slide 23

PROGRESSIVE IMAGE RENDERING @jmperezperez RESPONSIVE IMAGES Example <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"> Challenge: Keeping in sync markup and CSS

Slide 24

Slide 24

PROGRESSIVE IMAGE RENDERING @jmperezperez TIP 3 Lazy-load images

Slide 25

Slide 25

PROGRESSIVE IMAGE RENDERING @jmperezperez <img> above the fold & Lazy below the fold

Slide 26

Slide 26

PROGRESSIVE IMAGE RENDERING @jmperezperez Intersection Observer

Slide 27

Slide 27

PROGRESSIVE IMAGE RENDERING @jmperezperez INTERSECTION OBSERVER Example // 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'));

Slide 28

Slide 28

PROGRESSIVE IMAGE RENDERING @jmperezperez INTERSECTION OBSERVER Encapsulating in React 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); } ... }

Slide 29

Slide 29

PROGRESSIVE IMAGE RENDERING @jmperezperez IMAGE DECODING Using image.decode()

Slide 30

Slide 30

PROGRESSIVE IMAGE RENDERING @jmperezperez IMAGE DECODING Using image.decode() TIP 4 Add an image to the DOM without causing a decoding delay. // 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.'); }); Track the proposal on https://github.com/whatwg/html/issues/1920

Slide 31

Slide 31

PROGRESSIVE IMAGE RENDERING @jmperezperez What to show while the image is loading

Slide 32

Slide 32

PROGRESSIVE IMAGE RENDERING @jmperezperez PLACEHOLDERS Options Nothing Placeholder Solid colour or Progressive image gradient loading or "Blur-up"

Slide 33

Slide 33

PROGRESSIVE IMAGE RENDERING @jmperezperez Examples of solid color

Slide 34

Slide 34

PROGRESSIVE IMAGE RENDERING @jmperezperez

Slide 35

Slide 35

PROGRESSIVE IMAGE RENDERING @jmperezperez

Slide 36

Slide 36

PROGRESSIVE IMAGE RENDERING @jmperezperez

Slide 37

Slide 37

PROGRESSIVE IMAGE RENDERING @jmperezperez

Slide 38

Slide 38

PROGRESSIVE IMAGE RENDERING @jmperezperez

Slide 39

Slide 39

PROGRESSIVE IMAGE RENDERING @jmperezperez Examples of Progressive Image Loading

Slide 40

Slide 40

PROGRESSIVE IMAGE RENDERING @jmperezperez Medium

Slide 41

Slide 41

PROGRESSIVE IMAGE RENDERING @jmperezperez Medium

Slide 42

Slide 42

PROGRESSIVE IMAGE RENDERING @jmperezperez Quartz (qz.com)

Slide 43

Slide 43

PROGRESSIVE IMAGE RENDERING @jmperezperez Quartz (qz.com)

Slide 44

Slide 44

PROGRESSIVE IMAGE RENDERING Quora @jmperezperez

Slide 45

Slide 45

PROGRESSIVE IMAGE RENDERING @jmperezperez How it is done

Slide 46

Slide 46

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>

Slide 47

Slide 47

PROGRESSIVE IMAGE RENDERING @jmperezperez Thumbnails

Slide 48

Slide 48

PROGRESSIVE IMAGE RENDERING @jmperezperez Thumbnails

Slide 49

Slide 49

PROGRESSIVE IMAGE RENDERING @jmperezperez Getting creative with SVGs

Slide 50

Slide 50

PROGRESSIVE IMAGE RENDERING @jmperezperez SVG - Edges Source: https://www.polygon.com/a/ps4-review

Slide 51

Slide 51

PROGRESSIVE IMAGE RENDERING @jmperezperez Drawing edges with SVG ">//codepen.io/jmperez/embed/rxxRRg/?height=525&themeid=0&default-tab=js,result&embed-version=2"> Source: https://codepen.io/jmperez/pen/rxxRRg

Slide 52

Slide 52

PROGRESSIVE IMAGE RENDERING @jmperezperez Drawing bitmap images Canny Edge Detector

Slide 53

Slide 53

https://jmperezperez.com/renderconf17/extslides/contour2/index.html Source: https://jmperezperez.com/contour/

Slide 54

Slide 54

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

Slide 55

Slide 55

PROGRESSIVE IMAGE RENDERING @jmperezperez SVG - Shapes Source: http://www.samcodes.co.uk/project/geometrize-haxe-web/

Slide 56

Slide 56

PROGRESSIVE IMAGE RENDERING @jmperezperez

Slide 57

Slide 57

PROGRESSIVE IMAGE RENDERING @jmperezperez SVG - Shapes SVG - 10 shapes SVG - 100 shapes Original 0.74kB 3.5kB 101kB

Slide 58

Slide 58

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)

Slide 59

Slide 59

PROGRESSIVE IMAGE RENDERING @jmperezperez SVG - Silhouettes / Traces Source: https://codepen.io/ainalem/full/aLKxjm/

Slide 60

Slide 60

PROGRESSIVE IMAGE RENDERING @jmperezperez SVG - Silhouettes / Traces Source: https://www.npmjs.com/package/potrace

Slide 61

Slide 61

PROGRESSIVE IMAGE RENDERING @jmperezperez SVG - Silhouettes / Traces Source: https://twitter.com/Tholle1234/status/920423596346019840

Slide 62

Slide 62

PROGRESSIVE IMAGE RENDERING @jmperezperez Should we do this? Just because you can it doesn't mean you should

Slide 63

Slide 63

PROGRESSIVE IMAGE RENDERING @jmperezperez Summary Reduce requests Choose the right format and optimise Embrace responsive images Try to lazy load Think about placeholders Innovate!

Slide 64

Slide 64

PROGRESSIVE IMAGE RENDERING @jmperezperez The Web is fun fun..

Slide 65

Slide 65

spotify.com/jobs talk with me for more info

Slide 66

Slide 66

Thanks! @jmperezperez Slides on https://slides.com/jmperez