Progressive image rendering Render Conf 2017
José M. Pérez · Web dev at Spotify @jmperezperez
Slide 2
Images on the web
Slide 3
To use or not to use images
Slide 4
Slide 5
Slide 6
Slide 7
Wrong way of hiding images (1/2) <img src="example.png"> <!-- it'll be requested --> @media (max-width: 480px) { img { display: none; } }
Slide 8
Wrong way of hiding images (2/2) <body> <section class="section-1"> <p>This is the current section</p> <img src="example-1.png"> </section> <section class="section-2 hidden"> <p>This section might or might not be shown later</p> <img src="example-2.png"> <!-- it'll be requested --> </div> </body> .hidden { display: none; }
Slide 9
Optimise your images really
Slide 10
Picture element and srcset
2 columns 1 column
3 columns
How to lazy load: Basic approach For all images, check whether they are in the viewport (or close enough). If they are, request it. Repeat this onScroll and onResize
Slide 15
How to lazy load: IntersectionObserver Don't bind to the scroll event. Subscribe to an event triggered when the image enters the rendered area Supported in Chrome, Opera. In development in Firefox and Edge. Very easy to use as another strategy in your lazy loading library.
Slide 16
IntersectionObserver
Slide 17
What to show while the image is loading
Slide 18
Alternatives
Slide 19
Examples of solid color
Slide 20
Slide 21
Slide 22
style="border:0"
Slide 23
Examples of Progressive Image Loading
Slide 24
Medium
Slide 25
How it's done
Use <div> to render the image Request small thumbnail Draw thumbnail to <canvas/> and apply blur effect Request large image Render large image and hide <canvas/>
Slide 26
Markup Overview <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 27
How do users perceive it? Jason @lang
Follow
Did @Medium recently add a new image loading fadein? I noticed it this morning on mobile and just now again on web. Looks nice. 8:05 PM - 29 Feb 2016
นาธารจะ านแคล @zartre
Follow
@Medium's articles (although full of high-res images) load up very fast - 3:38 AM - 28 Mar 2015
Slide 28
or maybe not? Harris Rodis @harrisrodis
Follow
I don't know about you but I don't like a bit those blurry (still loading...) images on Medium. Very distracting. 5:40 PM - 29 Dec 2015
James Young @welcomebrand
Follow
That blurry image preloading thing on Medium - is it just me or does it make all images load extremely slowly now? 10:53 AM - 5 Feb 2016
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?
Slide 31
Reliable? Damien @Eramdam
Follow
I'm seeing this more and more on Medium posts. Maybe the whole "blur the pictures" stuff isn't a good idea… 7:44 PM - 8 Jan 2016
Sara Soueidan @SaraSoueidan
Follow
This @Medium page is fully loaded on my slow connection. Very pretty with those stupid image effects, isn’t it? 2:07 PM - 28 Nov 2015 3
18
Slide 32
Facebook - Inlining thumbnail image in payload
Source: The technology behind preview photos
Slide 33
Facebook - Inlining thumbnail image in payload 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.
Slide 34
Facebook - Inlining thumbnail image in payload Header (mainly Quantization Table and Huffman Table)
Compressed Data
Client (mobile app)
GraphQL
Slide 35
Generating tiny thumbnails JPG
464 B 532 B 428 B 409 B 456 B 692 B WebP
112 B
154 B
106 B
96 B
116 B
202 B
Slide 36
Generating tiny thumbnails JPG
464 B 532 B 428 B 409 B 456 B 692 B WebP
112 B
154 B
106 B
96 B
116 B
202 B
Slide 37
Getting creative with SVGs
Slide 38
Source: polygon.com/a/ps4-review
Slide 39
How it works HTML
CSS
JS
Result
window.onload = function() { var path = document.querySelector('path'); var length = path.getTotalLength(); // Clear any previous transition path.style.transition = path.style.WebkitTransition = 'none'; // Set up the starting positions path.style.strokeDasharray = length + ' ' + length; path.style.strokeDashoffset = length; // Trigger a layout so styles are calculated & the browser // picks up the starting position before animating path.getBoundingClientRect(); // Define our transition path.style.transition = path.style.WebkitTransition = 'stroke-dashoffset 7s ease-in-out'; // Go! path.style.strokeDashoffset = '0'; };
More info: jakearchibald.com/2013/animated-line-drawing-svg
EDIT
ON