High Performance Images Beautiful shouldn’t mean Slow @guypod
Average Web Page Weight (Sep ’15) Not 37% Images 63% @guypod Source: HTTP Archive
Images On Average Page 1,383 KB 1,128 KB 891 KB ~2x!!! 696 KB 50 Reqs 56 Reqs 55 Reqs 54 Reqs Sep '12 Jun '13 Jun '14 Sep '15 Requests @guypod Source: HTTP Archive KB
Images Impact Performance 19000 -30% 14250 9500 4750 0 With Images @guypod No Images Load Time, 3G Speed
What Can you do? @guypod
Image Compression @guypod
Image Loading @guypod
Operationalizing Image Optimization @guypod
Image Compression @guypod
Average Resource Size CSS 9 KB JS 16 KB JPEG 37 KB 0 @guypod 10 20 30 40
RWD Sites Use Big Images 40 30 20 RWD Not RWD 31.6 KB 20.8 KB 10 10 KB 7.1 KB 0 JPEG Size @guypod PNG Size
Tip #1: Pick The Right Format @guypod
Image Formats On The Web Other 2% GIF 23% JPEG 45% PNG 30% @guypod
GIF • 28 Years Old (1987) • 256 Colors • Supports “Simple” Transparency • Supports Animation • Patented (now expired) @guypod
PNG • 19 Years Old (1996) • 8-32 bit color palettes • Alpha Transparency • Not patented @guypod
GIF -> PNG = 21% Savings PNG File Size @guypod GIF File Size Source: Styoan Stefanov, “Give PNG A Chance” (2009)
JPEG • 23 years old (1992) • RGB Colors (24 bit) • No Transparency Support • A Lossy Format @guypod
JPEG Lossy Compression Bitmap ≠ Bitmap PNG Lossless Compression Bitmap @guypod = Bitmap
JPEG • 23 years old (1992) • RGB Colors (24 bit) • No Transparency Support • A Lossy Format @guypod
PNG -> JPG = MUCH Smaller PNG, 574 KB @guypod JPG, 110 KB
JPEG: No Transparency PNG @guypod JPEG
WebP 3.3 3.27 bpp -26% 2.475 15 14.4 KB -31% 11.25 2.42 bpp 9.9 KB 1.65 7.5 0.825 3.75 0 0 PNG WebP Bytes Per Pixel @guypod JPEG (q75) WebP File Size (KB) Source: Google Studies
WebP Browser Support @guypod
BPG • Less than 1 year old • Lossless & Lossy • Based on Video encoder HEVC • • • H.265, successor of H.264 Beat WebP & J2K in Mozilla Study Free (LGPL) @guypod Fabrice Bellard (Creator of ffmpeg)
FLIF • 0 years old • Lossless • Progressive • Responsive Friendly • No browser support • Free (GPL) @guypod Source: FLIF Creators Jon Sneyers & Harshad RJ
PNG vs Others @guypod Source: Cloudinary
New Format Bakeoff @guypod Source: Cloudinary
FLIF - 3rd Party Stats @guypod Source: Cloudinary
New Image Formats WebP JPEG XR JPEG 2000 Support Chrome, Opera, Android 4.x IE 10+ Safari on iOS, OS X Savings (over JPEG) 40-50% ~25% 15-20% Mime Type image/webp Identification Accept: image/ webp @guypod image/vnd.ms-photo Soon: image/jxr image/jp2 Detect IE 10+ Detect Safari 5+
Using Custom Formats Client Side <script src="picturefill.js"></script> <picture> <source type="image/webp" srcset="book.webp"> <source type="image/vnd.msphoto" srcset="book.jxr"> <img src="book.jpg" alt="a book"> </picture> @guypod
Using Custom Formats Server Side, Single URL GET /book.jpg GET /book.jpg CDN/Cache @guypod Origin
Using Custom Formats Server Side, Single URL GET /book.jpg GET /book.jpg GET /book.webp GET /book.jpg Accept: image/webp CDN/Cache @guypod Origin
Using Custom Formats Server Side, Single URL GET /book.jpg GET /book.jpg GET /book.webp GET /book.jpg Accept: image/webp GET /book.jxr GET /book.jpg User-Agent: MSIE 10 * Spartan Accept: image/jxr* @guypod CDN/Cache Origin
Tip #1: Pick The Right Format @guypod
Tip #2: Control Quality @guypod
JPEG Quality Low Quality @guypod High Quality
Quality: 90 Size: 66 KB Quality: 75 Size: 37 KB Quality: 40 Size: 21 KB Quality: 25 Size: 16 KB @guypod
Quality: 90 Size: 66 KB @guypod Quality: 75 Size: 37 KB Quality: 40 Size: 21 KB Quality: 25 Size: 16 KB
Quality Scale Is Per Format 0.25 JPEG JPEG XR WebP Similarity 0.19 0.13 0.06 0.00 0 25 50 75 Quality @guypod Source: Nick Doyle Performance Calendar 100
Detecting Excessive Quality WebPageTest • Some stats about image quality on the web? @guypod
Detecting Excessive Quality PageSpeed Insights • Some stats about image quality on the web? @guypod
Tip #2: Control Quality @guypod
SIZE Doesn’t matter It’s all about TECHNIQUE @guypod
Image Loading @guypod
Tip #3: Size Images To Device @guypod
Download & Shrink 102 KB 1876 × 520 (975,520 pixels) @guypod
Download & Shrink 1876px 520px 866px 240px .hp07img {width: 100%} @guypod
Download & Shrink 1876px 520px 975,520 pixels 866px 240px 207,840 pixels 79% wasted pixels (~770K) @guypod
Download & Shrink 1876px 520px 110,744 Bytes 866px 240px 79% wasted pixels 68% wasted bytes (~75KB) @guypod 35,345 Bytes
Download & Shrink 1876px 520px 975,520 * 4(RGBA) = 3.9M Memory Bytes 866px 79% wasted pixels 68% wasted bytes 79% wasted memory (3MB) @guypod 240px 831K Mem Bytes
54 IMAGES On an Average Page @guypod
“...25% of new Android phones have only 512MB of RAM.” – Jen Fitzpatrick, Google Maps @guypod
Download & Shrink Processing Times @guypod Source: Tim Kadlec, “Mobile Image Processing”
Implementing Responsive Images <img src="small.jpg" srcset="large.jpg 1024w, medium.jpg 640w, small.jpg 320w" sizes="(min-width: 36em) 33.3vw, 100vw" alt="A rad wolf"> @guypod
Implementing Responsive Images <img src="small.jpg" srcset="large.jpg 1024w, medium.jpg 640w, small.jpg 320w" sizes="(min-width: 36em) 33.3vw, 100vw" alt="A rad wolf"> Hint, Hint… @guypod
Implementing Responsive Images <img src="small.jpg" srcset="large.jpg 1024w, medium.jpg 640w, small.jpg 320w" sizes="(min-width: 36em) 33.3vw, 100vw" alt="A rad wolf"> Hint, Hint… @guypod
Implementing Responsive Images <picture> <source media="(min-width: 40em)" srcset="big.jpg 1x, big-hd.jpg 2x"> <source srcset="small.jpg 1x, small-hd.jpg 2x"> <img src="fallback.jpg" alt=""> </picture> @guypod
Implementing Responsive Images <picture> <source media="(min-width: 40em)" srcset="big.jpg 1x, big-hd.jpg 2x"> <source srcset="small.jpg 1x, small-hd.jpg 2x"> <img src="fallback.jpg" alt=""> </picture> @guypod Use Picturefill
Which Breakpoints To Use? What Are your Users Using? @guypod
Which Breakpoints To Use? How Big & Complex Are Your Images? Width Height File Size 1 453 302 44K 579 386 65K 4 687 458 85K 5 786 524 104K 6 885 590 124K 7 975 650 142K 8 @guypod 25K 3 Your Analytics 213 2 • 320 990 660 151K Source: Jason Grigsby, “Sensible Jumps In Responsive Image File Sizes”
Which Breakpoints To Use? How Big & Complex Are Your Images? point # Width Height File Size 1 Your Analytics @guypod 213 9.0K 2 731 487 29K 3 • 320 990 660 40K Source: Jason Grigsby, “Sensible Jumps In Responsive Image File Sizes”
FLIF Progressive “Breakpoints” @guypod
FLIF Progressive “Breakpoints” 1969x1307 pixels 299,643 bytes @guypod
FLIF Progressive “Breakpoints” 1969x1307 pixels All 299,643 bytes 653x985 pixels (1:2) First 80,389 bytes @guypod
FLIF Progressive “Breakpoints” 1969x1307 pixels All 299,643 bytes 653x985 pixels (1:2) First 80,389 bytes 492x326 pixels (1:4) First 37,014 bytes @guypod
Tip #3: Size Images To Device @guypod
Tip #4: Prioritize Critical Images @guypod
Below The Fold Etsy 82% @guypod Velocity 91% Guardian 92%
On A Typical Page & Desktop Screen… Page Content Image Requests Visible 20% Visible 38% Not Visible 62% @guypod Not Visible 80%
Download & Hide @guypod
Download & Hide img {display: none} @guypod
Download & Hide Image Requests 79 78 Image Weight 2,258 KB 2,251 KB @guypod
Lazy Load Images <img src="book.jpg" alt="A Book"> <img src="1px.gif" data-src="book.jpg" alt="A Book" onload="loadImage(this)"> @guypod
Lazy Load Images <script> function loadImage(img) { var dataSrc = imgs[i].getAttribute("data-src"); if (dataSrc && isAboveTheFold(img)) { img.onload = null; img.src = dataSrc; }} </script> <img src="1px.gif" data-src="book.jpg" alt="A Book" onload="loadImage(this)"> @guypod
Lazy Load Images <script> function loadImage(img) { var dataSrc = imgs[i].getAttribute("data-src"); if (dataSrc && isAboveTheFold(img)) { }} img.onload = null; img.src = dataSrc; // Repeat check on viewport changes (scroll, resize...) </script> <img src="1px.gif" data-src="book.jpg" alt="A Book" onload="loadImage(this)"> @guypod
Defer Load Images <script> function loadImage(img, force) { var dataSrc = imgs[i].getAttribute("data-src"); if (dataSrc && (force || isAboveTheFold(img)) ) { img.onload = null; img.src = dataSrc; } else if (deferOthers) { window.addEventListener("load", }} function() { loadImage(img,true)}); </script> @guypod
The Infamous PRELOADER @guypod
HTML Parser <html> <head> <script src="main.js"></script> <link src="styles.css" type="text/css"> </head> <body> <img src="book.jpg"/> <img src="bag.jpg"/> </body> </html> @guypod
HTML Parser <html> <head> <script src="main.js"></script> <link src="styles.css" type="text/css"> </head> <body> <img src="book.jpg"/> <img src="bag.jpg"/> </body> </html> @guypod main.js styles.css book.jpg bag.jpg 7
HTML Parser & Pre-parser <html> <head> <script src="main.js"></script> <link src="styles.css" type="text/css"> </head> <body> <img src="book.jpg"/> <img src="bag.jpg"/> </body> </html> @guypod main.js styles.css book.jpg bag.jpg
HTML Parser & Pre-parser <html> <head> <script src="main.js"></script> <link src="styles.css" type="text/css"> </head> <body> <img src="book.jpg"/> <img src="bag.jpg"/> </body> </html> @guypod main.js styles.css book.jpg bag.jpg
HTML Parser & Pre-parser <html> <head> <script src="main.js"></script> <link src="styles.css" type="text/css"> </head> <body> <img src="book.jpg"/> <img src="bag.jpg"/> </body> </html> @guypod 11 main.js styles.css book.jpg bag.jpg
Who Initiates Image Downloads? CSS 20% Pre-parser 43% HTML Parser 37% Source: Ilya Grigorik, HTTP Archive @guypod
HTML Parser & Pre-parser … <img src="1px.gif" data-src=“book.jpg" onload="loadImage(this)"/> <img src="bag.jpg" data-src="bag.jpg" onload="loadImage(this)"/> … main.js styles.css book.jpg bag.jpg @guypod 11
HTTP/1.1 @guypod HTTP/2
Pre-Parser Boost @guypod Excess Images
Protip #1: LQIP Low Quality Image Placeholders <img src=“LowQ.jpg” data-src=“HighQ.jpg” onload=“loadImage(this)”> @guypod
Protip #1: LQIP Low Quality Image Placeholders <img src=“LowQ.jpg” data-src=“HighQ.jpg” onload=“loadImage(this)”> LowQ.jpg Quality: 25 Size: 16 KB @guypod
Protip #1: LQIP Low Quality Image Placeholders <img src=“LowQ.jpg” data-src=“HighQ.jpg” onload=“loadImage(this)”> LowQ.jpg Quality: 25 Size: 16 KB HighQ.jpg Quality: 90 Size: 66 KB @guypod
Protip #2: Selective Lazy Load <img class="responsive-img" sizes="(min-width: 980px) 460px, (min-width: 740px) 340px, 100%" srcset="/w-460/<id>/500.jpg 460w, /w-340/<id>/500.jpg 340w, /w-445/<id>/500.jpg 445w, /w-605/<id>/620.jpg 605w" src="/w-300/<id>/500.jpg"> @guypod
Protip #2: Selective Lazy Load <img class="js-lazy-loaded-image responsive-img" data-srcset="/w-220/<id>/1000.jpg 220w, /w-160/<id>/1000.jpg 160w, /w-127/<id>/1000.jpg 127w" data-sizes="(min-width: 980px) 220px, (min-width: 740px) 160px, 127px" src="data:image/gif;base64,R0lGODlhAQABAAAAACH 5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="> @guypod
Protip #2: Selective Lazy Load <img class="js-lazy-loaded-image responsive-img" data-srcset="/w-220/<id>/1000.jpg 220w, /w-160/<id>/1000.jpg 160w, /w-127/<id>/1000.jpg 127w" data-sizes="(min-width: 980px) 220px, (min-width: 740px) 160px, 127px" src="data:image/gif;base64,R0lGODlhAQABAAAAACH 5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="> @guypod JS Disabled
Tip #4: Prioritize Critical Images @guypod
Operationalizing Image Optimization @guypod
Tip #5: Encode Well • Quality Curve is NOT a Standard • “Save For Web” is NOT just quality • Decoding Is Standard, Encoding Is Not • Notable Deltas: Chroma Subsampling, Per-Region Quality, Lossy PNG, SSIM-Based Quality… • If you use one tool: ImageOptim (benchmark) @guypod
Tip #6: Use Image Management Service 5 breakpoints * 2 Pixel Ratios * 3 Views * 5 thumbnails * 100,000 Products/Articles… And tomorrow? @guypod
Tip #6: Use Image Management Service 5 breakpoints * 2 Pixel Ratios * 3 Views * 5 thumbnails * 100,000 Products/Articles… And tomorrow? Origin Transcoder /q75/w120/book.jpg <Right-Sized Img> @guypod GET /book.jpg <Big, High Res Img>
Image Manager @guypod
Cloudinary @guypod
What Can You Do? Image Compression Image Loading Image Operations Choose The Right Format Use Responsive Images Encode Well Transcode in Proxy Control Quality Prioritize Critical Content Enforce a Performance Budget @guypod
FREE Copy at http://bit.ly/hpi-preview @guypod
Thank You! Guy Podjarny @guypod Reminder Free HPI Link: @guypod http://bit.ly/hpi-preview
Or sign in using your account
Do you have the account? Create account