Pictures are worth a thousand words…and sometimes 1,000MB. A cautionary tale.

A presentation at DevFest 2018 in October 2018 in Melbourne VIC, Australia by Anton Ball

Slide 1

Slide 1

PICTURES ARE WORTH A THOUSAND WORDS …AND SOMETIMES 1,000MB. A CAUTIONARY TALE.

Slide 2

Slide 2

PICTURES ARE WORTH A THOUSAND WORDS …AND SOMETIMES 1,000MB. A CAUTIONARY TALE.

Slide 3

Slide 3

Slide 4

Slide 4

?

Slide 5

Slide 5

❤ 🍔 🍩

Slide 6

Slide 6

Slide 7

Slide 7

Slide 8

Slide 8

ANTON BALL @antonjb

Slide 9

Slide 9

We made a mistake…

Slide 10

Slide 10

😱

Slide 11

Slide 11

Slide 12

Slide 12

IMAGES 657 KB HTTP Archive EVERYTHING ELSE 1544.7 KB https://httparchive.org/reports/page-weight

Slide 13

Slide 13

&%' 7.6mb/s 11mb/s 6.5mb/s 62 sec 42 sec 72 sec ( 👓 Slow 3G 20 min

Slide 14

Slide 14

Slide 15

Slide 15

BBC has seen that they lose an additional 10% of users for every additional second it takes for their site to load Rebuilding Pinterest pages for performance resulted in a 40% decrease in wait time, a 15% increase in SEO traffic and a 15% increase in conversion rate to signup.

Slide 16

Slide 16

Format Resize Compression Automation

Slide 17

Slide 17

🖼 Our Process 🌏

Slide 18

Slide 18

DEVSIGN

Slide 19

Slide 19

Format

Slide 20

Slide 20

Exif PNM CD5 FITS SGI PLBM AMF PBM TIFF HDR BAT ECW PGF SID DWF FLIF BMP BAT DGN ILBM IMG XPS DWG VML BPG GIF SVG JPEG PNG WEBP HPGL ICO PGM XISF HSF PAM PCX HVIF QCC ODG PPM DEEP TGA JPEG XR Nrrd CGM DXF Xar

Slide 21

Slide 21

🖼 Can image be vector? NO Does it need transparency? YES YES SVG PNG Is the image complex? NO NO YES JPG

Slide 22

Slide 22

WEBP https://developers.google.com/speed/webp/

Slide 23

Slide 23

WEBP https://caniuse.com/#feat=webp

Slide 24

Slide 24

2.3MB GIF -85% 331KB MP4

Slide 25

Slide 25

Progress 😨

Slide 26

Slide 26

Size

Slide 27

Slide 27

Slide 28

Slide 28

510x368 5123x3697

Slide 29

Slide 29

SIPS sips -Z 510 *.jpg

Slide 30

Slide 30

SIPS sips -Z 510 *.jpg

Slide 31

Slide 31

📱 🔋

Slide 32

Slide 32

<Picture /> <picture> <source media="(min-width: 60em)" type="image/webp" srcset="donut-large.webp" #/> <source media="(min-width: 60em)" srcset="donut-large.jpg" #/> <img src="donut.jpg" #/> #</picture>

Slide 33

Slide 33

<Picture /> <picture> <source media="(min-width: 60em)" type="image/webp" srcset="donut-large.webp" #/> <source media="(min-width: 60em)" srcset="donut-large.jpg" #/> <img src="donut.jpg" #/> #</picture>

Slide 34

Slide 34

https://caniuse.com/#feat=picture

Slide 35

Slide 35

progress 😎

Slide 36

Slide 36

🖼 Can image be vector? NO Does it need transparency? YES YES SVG PNG Is the image complex? NO NO YES JPG RESIZE

Slide 37

Slide 37

Compression

Slide 38

Slide 38

Slide 39

Slide 39

Slide 40

Slide 40

Slide 41

Slide 41

PNGQuant OptiPNG TinyPNG ImageMagick MOZJPEG Guetzli SVGO PNG Compressor JPEGMini PNGOut PNGOptimizer ImageOptim PNGCrush PunyPNG Photoshop

Slide 42

Slide 42

Start with 100% quality

Slide 43

Slide 43

416KB original -42% 239KB optimised

Slide 44

Slide 44

Compressed Original

Slide 45

Slide 45

Not all images are equal

Slide 46

Slide 46

SVGOMG 916B original -83% 148B optimised https://jakearchibald.github.io/svgomg/

Slide 47

Slide 47

Guetzli guetzli #--quality 85 source/donut.jpg build/images/donut.jpg

Slide 48

Slide 48

Slide 49

Slide 49

Guetzli 416KB original -54% 191KB optimised

Slide 50

Slide 50

🤩

Slide 51

Slide 51

🖼 Can image be vector? NO Does it need transparency? YES YES SVG PNG COMPRESS Is the image complex? NO NO YES JPG RESIZE

Slide 52

Slide 52

😱 59MB original 🤩 -99% 427KB optimised

Slide 53

Slide 53

Automation

Slide 54

Slide 54

Automating Format

Slide 55

Slide 55

Automating Size

Slide 56

Slide 56

https://29a.ch/sandbox/2014/smartcrop/examples/testbed.html

Slide 57

Slide 57

Automating Compression

Slide 58

Slide 58

const imagemin = require("imagemin"); const imageminMozjpeg = require("imagemin-mozjpeg"); const imageminPngquant = require("imagemin-pngquant"); (async () #=> { const files = await imagemin(["images#/*.{jpg,png}"], "build/images", { plugins: [ imageminMozjpeg({ quality: 85 }), imageminPngquant({ quality: “75-85" }) ] }); console.log("Image buffer - save or process"); })();

Slide 59

Slide 59

const imagemin = require("imagemin"); const imageminWebp = require("imagemin-webp"); (async () #=> { const files = await imagemin(["images#/*.{jpg,png}"], "build/images", { plugins: [imageminWebp({ quality: 85 })] }); console.log("Image buffer - save or process"); })();

Slide 60

Slide 60

🖼 Can image be vector? NO Does it need transparency? YES YES SVG PNG NO NO YES JPG COMPRESS RESIZE WEBP Is the image complex?

Slide 61

Slide 61

☁ ☁ 🖼

Slide 62

Slide 62

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8

Slide 63

Slide 63

http://io.fastlydemo.net/io

Slide 64

Slide 64

<picture> <source media="(min-width: 60em)" srcset="#//fastly-io/img-1.io.jpg?auto=webp&crop=16:9&width=598&quality=75" #/> <source media="(min-width: 40em)" srcset="#//fastly-io/img-1.io.jpg?auto=webp&crop=16:9&width=402&quality=75" #/> <img src=“#//fastly-io/img-1.io.jpg?auto=webp&crop=16:9&width=241&quality=60" #/> #</picture>

Slide 65

Slide 65

https://cloudinary.com/documentation/image_transformations#face_detection_based_cropping

Slide 66

Slide 66

https://cloudinary.com/documentation/image_transformations

Slide 67

Slide 67

https://cloudinary.com/documentation/image_transformations#effects_with_face_detection

Slide 68

Slide 68

🖼 ☁ THE CLOUD 🌏

Slide 69

Slide 69

🖼 ⛈ THE CLOUD 🌏

Slide 70

Slide 70

BONUS TIPS

Slide 71

Slide 71

197KB original -62% 73KB indexed https://medium.com/@duhroach/reducing-png-file-size-8473480d0476

Slide 72

Slide 72

Perceived speed

Slide 73

Slide 73

1:1 16:9 https://daverupert.com/2015/12/intrinsic-placeholders-with-picture/ 4:3

Slide 74

Slide 74

.intrinsic { display: block; position: relative; height: 0; width: 100%; padding-top: 100%; background-color: #aabdcd; } .intrinsic-item { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } .intrinsic.intrinsic#--4x3 { padding-top: 75%; } 4:3

Slide 75

Slide 75

Slide 76

Slide 76

Slide 77

Slide 77

actual size

Slide 78

Slide 78

Primitive SQIP

Slide 79

Slide 79

Lazy Loading

Slide 80

Slide 80

Lazy Loading <img data-src="donut.jpg" alt="jam doughnut" class="lazyload" #/> https://github.com/aFarkas/lazysizes

Slide 81

Slide 81

Lazy Loading <img src="donut.jpg" alt="jam doughnut" lazyload="on" #/> https://calibreapp.com/blog/2018-08-16-native-lazy-load/

Slide 82

Slide 82

Lazy Loading chrome://flags/#enable-lazy-image-loading

Slide 83

Slide 83

This adds resources

Slide 84

Slide 84

Don’t use images

Slide 85

Slide 85

Pure CSS Francine https://github.com/cyanharlow/purecss-francine

Slide 86

Slide 86

https://codepen.io/mandymichael/pen/BWyYYP

Slide 87

Slide 87

TO RECAP 1. Select best format 2. Use right size 3. Compress 4. Automate 5. Perceived performance 6. Don’t use images (if you don’t have to)

Slide 88

Slide 88

https://images.guide/ Addy Osmani

Slide 89

Slide 89

THANK YOU @antonjb