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

PROGRESSIVE IMAGE RENDERING @jmperezperez About me

PROGRESSIVE IMAGE RENDERING @jmperezperez

PROGRESSIVE IMAGE RENDERING @jmperezperez Page Load Time

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

PROGRESSIVE IMAGE RENDERING @jmperezperez User Perceived Performance

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

PROGRESSIVE IMAGE RENDERING @jmperezperez WebPageTest

PROGRESSIVE IMAGE RENDERING @jmperezperez

PROGRESSIVE IMAGE RENDERING @jmperezperez More kilobytes can sometimes lead to improved perceived performance

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 images scripts other 1712kB (66%) 426kB (16%) 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

PROGRESSIVE IMAGE RENDERING @jmperezperez TIP 1 Optimise your images

PROGRESSIVE IMAGE RENDERING @jmperezperez

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>

PROGRESSIVE IMAGE RENDERING @jmperezperez compression · lossless · perceptual

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

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

PROGRESSIVE IMAGE RENDERING @jmperezperez TIP 3 Lazy-load images

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

PROGRESSIVE IMAGE RENDERING @jmperezperez Intersection Observer

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'));

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); } ... }

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

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

PROGRESSIVE IMAGE RENDERING @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 Medium

PROGRESSIVE IMAGE RENDERING @jmperezperez Medium

PROGRESSIVE IMAGE RENDERING @jmperezperez Quartz (qz.com)

PROGRESSIVE IMAGE RENDERING @jmperezperez Quartz (qz.com)

PROGRESSIVE IMAGE RENDERING Quora @jmperezperez

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 Source: https://blog.codinghorror.com/progressive-image-rendering/

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 Source: https://code.facebook.com/posts/991252547593574/the-technology-behind-preview-photos/

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

PROGRESSIVE IMAGE RENDERING @jmperezperez Getting creative with SVGs

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

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

PROGRESSIVE IMAGE RENDERING @jmperezperez Drawing 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

PROGRESSIVE IMAGE RENDERING @jmperezperez Drawing bitmap images Canny Edge Detector

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

PROGRESSIVE IMAGE RENDERING @jmperezperez https://jmperezperez.com/contour/ Source: https://jmperezperez.com/contour/

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"/>

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

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

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

spotify.com/jobs talk with me for more info

Thanks! @jmperezperez