SlideShare a Scribd company logo
Media in the
Age of PWAs
Aaron Gustafson
@AaronGustafson
slideshare.net/AaronGustafson
What exactly is a
Progressive Web App?
© Brad Frost
What exactly is a
Progressive Web App?
© Brad Frost
“Progressive Web App”
is a marketing term
Progressive Web App
© Brad Frost
Progressive Web App
Progressive Web App
Game
Gallery
Book
Newspaper
Art Project
Tool
Progressive Web App
Game
Gallery
Book
Newspaper
Art Project
Tool
Progressive Web Site
Who’s behind PWAs?
@AaronGustafson
A Minimum Viable PWA
HTTPS
@AaronGustafson
A Minimum Viable PWA
HTTPS Web App
Manifest
@AaronGustafson
Web App Manifest
{
"lang": "en",
"short_name": "Wash Post",
"name": "The Washington Post",
"icons": [ { "src": "img/launcher-icon-2x.png",
"sizes": "96x96",
"type": "image/png" } ],
"start_url": "/pwa/",
"display": "standalone",
"orientation": "portrait",
"background_color": "black"
}
@AaronGustafson
A Minimum Viable PWA
HTTPS Web App
Manifest
Service
Worker
Should you
believe the hype?
Maybe?
Carnival:
24% opt-in rate and
42% open rate for
push notifications
Katarzyna Ostrowska
aka.ms/carnival-pwa
Starbucks:
2x increase in daily
active users
aka.ms/google-io-2018
Tinder:
Core experience
with 90% less code
aka.ms/tinder-pwa-2017
Trivago:
97% increase in
click-outs to
hotel offers
aka.ms/trivago-pwa-2017
West Elm:
15% increase in
time on site
9% increase in
revenue per visit
aka.ms/west-elm-pwa-2017
@AaronGustafson
A Minimum Viable PWA
HTTPS Web App
Manifest
Service
Worker
@AaronGustafson
Let’s talk about Service Worker
@AaronGustafson
Registering a Service Worker
if ( "serviceWorker" in navigator ) {
navigator.serviceWorker.register( "/serviceworker.min.js" );
}
@AaronGustafson
Registering a Service Worker
if ( "serviceWorker" in navigator ) {
navigator.serviceWorker.register( "/serviceworker.min.js" );
}
@AaronGustafson
Registering a Service Worker
if ( "serviceWorker" in navigator ) {
navigator.serviceWorker.register( "/serviceworker.min.js" );
}
@AaronGustafson
Registering a Service Worker
if ( "serviceWorker" in navigator ) {
navigator.serviceWorker.register( "/serviceworker.min.js" );
}
Path is important!
@AaronGustafson
The Service Worker Lifecycle
Browser
Install Activation Ready
aka.ms/pwa-lifecycle
@AaronGustafson
How connections are made
Browser
Internet
@AaronGustafson
Along comes Service Worker
Browser
Internet
@AaronGustafson
Along comes Service Worker
Browser
Internet
Cache
@AaronGustafson
Along comes Service Worker
Browser
Internet
Cache
!
@AaronGustafson
Know your (storage) limits
Temporary Persistent
Browser purges User purges
@AaronGustafson
Know your (storage) limits
Volume Size Domain Limit Overall Limit
≤ 8 GB
20%
of
overall
50 MB
8–32 GB 500 MB
32–128 GB 4% of volume
> 128 GB 4% or 20 GB
Except on iOS.
Safari gives you 50 MB.
Raising limits?
Unlimited storage?
Storage is a privilege,
don’t abuse it.
How?
@AaronGustafson
Make good choices
1. No animated GIFs (especially as backgrounds)
38
@AaronGustafson
Make good choices
2. Use responsive images
39
<img src="medium.jpg"
srcset="small.jpg 256w,
medium.jpg 512w,
large.jpg 1024w"
sizes="(max-width: 30em) 30em, 100vw"
alt="It’s responsive!">
aka.ms/cloudinary-images
@AaronGustafson
Make good choices
3. Lazy load images
40
<img src="medium.jpg"
srcset="small.jpg 256w,
medium.jpg 512w,
large.jpg 1024w"
sizes="(max-width: 30em) 30em, 100vw"
loading="lazy"
alt="It’s responsive and lazy loads!">
aka.ms/img-lazy-loading
@AaronGustafson
Make good choices
4. Provide alternate image formats
41
<picture>
<source type="image/webp" srcset="my.webp">
<img src="my.jpg" alt="Alt text goes here">
</picture>
@AaronGustafson
Make good choices
4. Provide alternate image formats (via Cloudinary URLs)
42
https://res.cloudinary.com/demo/image/upload/w_300,f_auto/my.jpg
aka.ms/cloudinary-webp
@AaronGustafson
Make good choices
5. Provide fallback images via Service Worker
43
self.addEventListener( "install", function( event ){
event.waitUntil(
caches.open( "static" ).then( cache => {
return cache.addAll( ["/i/fallbacks/offline.svg"] );
})
);
});
function respondWithOfflineImage() {
return caches.match( "/i/fallbacks/offline.svg" );
}
aka.ms/ag-sw
@AaronGustafson
Make good choices
5. Provide fallback images via Service Worker
44
self.addEventListener( "install", function( event ){
event.waitUntil(
caches.open( "static" ).then( cache => {
return cache.addAll( ["/i/fallbacks/offline.svg"] );
})
);
});
function respondWithOfflineImage() {
return caches.match( "/i/fallbacks/offline.svg" );
}
aka.ms/ag-sw
@AaronGustafson
Make good choices
5. Provide fallback images via Service Worker
45
self.addEventListener( "install", function( event ){
event.waitUntil(
caches.open( "static" ).then( cache => {
return cache.addAll( ["/i/fallbacks/offline.svg"] );
})
);
});
function respondWithOfflineImage() {
return caches.match( "/i/fallbacks/offline.svg" );
}
aka.ms/ag-sw
@AaronGustafson
Make good choices
5. Provide fallback images via Service Worker
46
self.addEventListener( "install", function( event ){
event.waitUntil(
caches.open( "static" ).then( cache => {
return cache.addAll( ["/i/fallbacks/offline.svg"] );
})
);
});
function respondWithOfflineImage() {
return caches.match( "/i/fallbacks/offline.svg" );
}
aka.ms/ag-sw
@AaronGustafson
Make good choices
5. Provide fallback images via Service Worker
47
self.addEventListener( "install", function( event ){
event.waitUntil(
caches.open( "static" ).then( cache => {
return cache.addAll( ["/i/fallbacks/offline.svg"] );
})
);
});
function respondWithOfflineImage() {
return caches.match( "/i/fallbacks/offline.svg" );
}
aka.ms/ag-sw
@AaronGustafson
Make good choices
5. Provide fallback images via Service Worker
48
self.addEventListener( "install", function( event ){
event.waitUntil(
caches.open( "static" ).then( cache => {
return cache.addAll( ["/i/fallbacks/offline.svg"] );
})
);
});
function respondWithOfflineImage() {
return caches.match( "/i/fallbacks/offline.svg" );
}
aka.ms/ag-sw
@AaronGustafson
Make good choices
5. Provide fallback images via Service Worker
49
self.addEventListener( "fetch", event => {
const request = event.request,
url = request.url;
if ( request.headers.get("Accept").includes("image") ) {
event.respondWith(
return fetch( request, fetch_config.images )
.then( response => {
return response;
})
.catch(
respondWithOfflineImage
);
);
}
});
aka.ms/ag-sw
@AaronGustafson
Make good choices
5. Provide fallback images via Service Worker
50
self.addEventListener( "fetch", event => {
const request = event.request,
url = request.url;
if ( request.headers.get("Accept").includes("image") ) {
event.respondWith(
return fetch( request, fetch_config.images )
.then( response => {
return response;
})
.catch(
respondWithOfflineImage
);
);
}
});
aka.ms/ag-sw
@AaronGustafson
Make good choices
5. Provide fallback images via Service Worker
51
self.addEventListener( "fetch", event => {
const request = event.request,
url = request.url;
if ( request.headers.get("Accept").includes("image") ) {
event.respondWith(
return fetch( request, fetch_config.images )
.then( response => {
return response;
})
.catch(
respondWithOfflineImage
);
);
}
});
aka.ms/ag-sw
@AaronGustafson
Make good choices
5. Provide fallback images via Service Worker
52
self.addEventListener( "fetch", event => {
const request = event.request,
url = request.url;
if ( request.headers.get("Accept").includes("image") ) {
event.respondWith(
return fetch( request, fetch_config.images )
.then( response => {
return response;
})
.catch(
respondWithOfflineImage
);
);
}
});
aka.ms/ag-sw
@AaronGustafson
Make good choices
5. Provide fallback images via Service Worker
53
self.addEventListener( "fetch", event => {
const request = event.request,
url = request.url;
if ( request.headers.get("Accept").includes("image") ) {
event.respondWith(
return fetch( request, fetch_config.images )
.then( response => {
return response;
})
.catch(
respondWithOfflineImage
);
);
}
});
aka.ms/ag-sw
@AaronGustafson
Make good choices
5. Provide fallback images via Service Worker
54
self.addEventListener( "fetch", event => {
const request = event.request,
url = request.url;
if ( request.headers.get("Accept").includes("image") ) {
event.respondWith(
return fetch( request, fetch_config.images )
.then( response => {
return response;
})
.catch(
respondWithOfflineImage
);
);
}
});
aka.ms/ag-sw
@AaronGustafson
Make good choices
6. Pay attention to the Save Data header
55
let save_data = false;
if ( 'connection' in navigator ) {
save_data = navigator.connection.saveData;
}
aka.ms/ag-sw
@AaronGustafson
Make good choices
6. Pay attention to the Save Data header
56
self.addEventListener( "fetch", event => {
const request = event.request,
url = request.url;
if ( request.headers.get("Accept").includes("image") ) {
event.respondWith(
if ( save_data ) {
return respondWithFallbackImage( url );
}
// …
);
}
aka.ms/ag-sw
@AaronGustafson
Make good choices
6. Pay attention to the Save Data header
57
const fallback_avatar = "/i/fallbacks/avatar.svg",
fallback_image = "/i/fallbacks/image.svg",
avatars = /webmention.io/;
// …
function respondWithFallbackImage( url ) {
const image = avatars.test( url ) ? fallback_avatar
: fallback_image;
return caches.match( image );
}
aka.ms/ag-sw
@AaronGustafson
Make good choices
6. Pay attention to the Save Data header
58
const fallback_avatar = "/i/fallbacks/avatar.svg",
fallback_image = "/i/fallbacks/image.svg",
avatars = /webmention.io/;
// …
function respondWithFallbackImage( url ) {
const image = avatars.test( url ) ? fallback_avatar
: fallback_image;
return caches.match( image );
}
aka.ms/ag-sw
@AaronGustafson
Make good choices
6. Pay attention to the Save Data header
59
const fallback_avatar = "/i/fallbacks/avatar.svg",
fallback_image = "/i/fallbacks/image.svg",
avatars = /webmention.io/;
// …
function respondWithFallbackImage( url ) {
const image = avatars.test( url ) ? fallback_avatar
: fallback_image;
return caches.match( image );
}
aka.ms/ag-sw
@AaronGustafson
Make good choices
7. Prioritize certain images
60
const high_priority = [
/aaron-gustafson.com/,
/adaptivewebdesign.info/
];
function isHighPriority( url ) {
let i = high_priority.length;
while ( i-- ) {
if ( high_priority[i].test( url ) ) {
return true;
}
}
return false;
}
aka.ms/ag-sw
@AaronGustafson
Make good choices
7. Prioritize certain images
61
const high_priority = [
/aaron-gustafson.com/,
/adaptivewebdesign.info/
];
function isHighPriority( url ) {
let i = high_priority.length;
while ( i-- ) {
if ( high_priority[i].test( url ) ) {
return true;
}
}
return false;
}
aka.ms/ag-sw
@AaronGustafson
Make good choices
7. Prioritize certain images
62
const high_priority = [
/aaron-gustafson.com/,
/adaptivewebdesign.info/
];
function isHighPriority( url ) {
let i = high_priority.length;
while ( i-- ) {
if ( high_priority[i].test( url ) ) {
return true;
}
}
return false;
}
aka.ms/ag-sw
@AaronGustafson
Make good choices
8. Clean up after yourself
63
const version = "v2:",
sw_caches = {
static: {
name: `${version}static`
},
images: {
name: `${version}images`,
limit: 75
},
pages: {
name: `${version}pages`,
limit: 5
},
posts: {
name: `${version}posts`,
limit: 10
},
other: {
name: `${version}other`,
limit: 50
}
};
aka.ms/ag-sw
@AaronGustafson
Make good choices
8. Clean up after yourself
64
function trimCache( cache_name, limit ) {
caches.open( cache_name ).then( cache => {
cache.keys().then( items => {
if ( items.length > limit ) {
cache.delete( items[0] ).then(
trimCache( cache_name, limit )
);
}
});
});
}
aka.ms/ag-sw
@AaronGustafson
Make good choices
8. Clean up after yourself
65
function trimCache( cache_name, limit ) {
caches.open( cache_name ).then( cache => {
cache.keys().then( items => {
if ( items.length > limit ) {
cache.delete( items[0] ).then(
trimCache( cache_name, limit )
);
}
});
});
}
aka.ms/ag-sw
@AaronGustafson
Make good choices
8. Clean up after yourself
66
function trimCache( cache_name, limit ) {
caches.open( cache_name ).then( cache => {
cache.keys().then( items => {
if ( items.length > limit ) {
cache.delete( items[0] ).then(
trimCache( cache_name, limit )
);
}
});
});
}
aka.ms/ag-sw
@AaronGustafson
Make good choices
8. Clean up after yourself
67
if ( "serviceWorker" in navigator ) {
navigator.serviceWorker.register( "/serviceworker.min.js" );
if ( navigator.serviceWorker.controller ) {
window.addEventListener( "load", function(){
navigator.serviceWorker.controller.postMessage( "clean up" );
});
}
}
aka.ms/ag-sw
@AaronGustafson
Make good choices
8. Clean up after yourself
68
addEventListener("message", messageEvent => {
if (messageEvent.data == "clean up") {
for ( let key in sw_caches ) {
if ( sw_caches[key].limit != undefined ) {
trimCache( sw_caches[key].name, sw_caches[key].limit );
}
}
}
});
aka.ms/ag-sw
@AaronGustafson
Make good choices
8. Clean up after yourself
69
addEventListener("message", messageEvent => {
if (messageEvent.data == "clean up") {
for ( let key in sw_caches ) {
if ( sw_caches[key].limit != undefined ) {
trimCache( sw_caches[key].name, sw_caches[key].limit );
}
}
}
});
aka.ms/ag-sw
@AaronGustafson
Make good choices
1. No animated GIFs (especially as backgrounds)
2. Use responsive images
3. Lazy load images
4. Provide alternate image formats
5. Provide fallback images via Service Worker
6. Pay attention to the Save Data header
7. Prioritize certain images
8. Clean up after yourself
70
© Marvel
Thank you!
@AaronGustafson
aaron-gustafson.com
slideshare.net/AaronGustafson

More Related Content

What's hot

Intro to @viewport & other new Responsive Web Design CSS features
Intro to @viewport & other new Responsive Web Design CSS featuresIntro to @viewport & other new Responsive Web Design CSS features
Intro to @viewport & other new Responsive Web Design CSS featuresAndreas Bovens
 
Илья Пухальский (EPAM Systems)
Илья Пухальский (EPAM Systems)Илья Пухальский (EPAM Systems)
Илья Пухальский (EPAM Systems)Ontico
 
AngularJS: The Bridge Between Today and Tomorrow's Web (Todd Motto)
AngularJS: The Bridge Between Today and Tomorrow's Web (Todd Motto)AngularJS: The Bridge Between Today and Tomorrow's Web (Todd Motto)
AngularJS: The Bridge Between Today and Tomorrow's Web (Todd Motto)Future Insights
 
Html5 on Mobile(For Developer)
Html5 on Mobile(For Developer)Html5 on Mobile(For Developer)
Html5 on Mobile(For Developer)Adam Lu
 
Richard Cole of Amazon Gives Lightning Tallk at BigDataCamp
Richard Cole of Amazon Gives Lightning Tallk at BigDataCampRichard Cole of Amazon Gives Lightning Tallk at BigDataCamp
Richard Cole of Amazon Gives Lightning Tallk at BigDataCampBigDataCamp
 

What's hot (8)

Responsive Enhancement
Responsive EnhancementResponsive Enhancement
Responsive Enhancement
 
Site optimization
Site optimizationSite optimization
Site optimization
 
Bilder usw...
Bilder usw...Bilder usw...
Bilder usw...
 
Intro to @viewport & other new Responsive Web Design CSS features
Intro to @viewport & other new Responsive Web Design CSS featuresIntro to @viewport & other new Responsive Web Design CSS features
Intro to @viewport & other new Responsive Web Design CSS features
 
Илья Пухальский (EPAM Systems)
Илья Пухальский (EPAM Systems)Илья Пухальский (EPAM Systems)
Илья Пухальский (EPAM Systems)
 
AngularJS: The Bridge Between Today and Tomorrow's Web (Todd Motto)
AngularJS: The Bridge Between Today and Tomorrow's Web (Todd Motto)AngularJS: The Bridge Between Today and Tomorrow's Web (Todd Motto)
AngularJS: The Bridge Between Today and Tomorrow's Web (Todd Motto)
 
Html5 on Mobile(For Developer)
Html5 on Mobile(For Developer)Html5 on Mobile(For Developer)
Html5 on Mobile(For Developer)
 
Richard Cole of Amazon Gives Lightning Tallk at BigDataCamp
Richard Cole of Amazon Gives Lightning Tallk at BigDataCampRichard Cole of Amazon Gives Lightning Tallk at BigDataCamp
Richard Cole of Amazon Gives Lightning Tallk at BigDataCamp
 

Similar to Imagecon 2019 - Aaron Gustafson

The things browsers can do! SAE Alumni Convention 2014
The things browsers can do! SAE Alumni Convention 2014The things browsers can do! SAE Alumni Convention 2014
The things browsers can do! SAE Alumni Convention 2014Christian Heilmann
 
HTML5 after the hype - JFokus2015
HTML5 after the hype - JFokus2015HTML5 after the hype - JFokus2015
HTML5 after the hype - JFokus2015Christian Heilmann
 
Practical Responsive Images - from Second Wednesday
Practical Responsive Images - from Second WednesdayPractical Responsive Images - from Second Wednesday
Practical Responsive Images - from Second WednesdayBen Seymour
 
AtlasCamp 2013: Modernizing your Plugin UI
AtlasCamp 2013: Modernizing your Plugin UI AtlasCamp 2013: Modernizing your Plugin UI
AtlasCamp 2013: Modernizing your Plugin UI colleenfry
 
Responsive images are here. Now what?
Responsive images are here. Now what?Responsive images are here. Now what?
Responsive images are here. Now what?Jason Grigsby
 
Web accessibility
Web accessibilityWeb accessibility
Web accessibilityEb Styles
 
Python Code Camp for Professionals 1/4
Python Code Camp for Professionals 1/4Python Code Camp for Professionals 1/4
Python Code Camp for Professionals 1/4DEVCON
 
AtlasCamp 2015: Connect everywhere - Cloud and Server
AtlasCamp 2015: Connect everywhere - Cloud and ServerAtlasCamp 2015: Connect everywhere - Cloud and Server
AtlasCamp 2015: Connect everywhere - Cloud and ServerAtlassian
 
Responsive Responsive Design
Responsive Responsive DesignResponsive Responsive Design
Responsive Responsive DesignTim Kadlec
 
[CSSDevConf] Adaptive Images in Responsive Web Design 2014
[CSSDevConf] Adaptive Images in Responsive Web Design 2014[CSSDevConf] Adaptive Images in Responsive Web Design 2014
[CSSDevConf] Adaptive Images in Responsive Web Design 2014Christopher Schmitt
 
The Future of CSS with Web components
The Future of CSS with Web componentsThe Future of CSS with Web components
The Future of CSS with Web componentsdevObjective
 
The Future of CSS with Web Components
The Future of CSS with Web ComponentsThe Future of CSS with Web Components
The Future of CSS with Web ComponentsColdFusionConference
 
[rwdsummit] Adaptive Images in Responsive Web Design
[rwdsummit] Adaptive Images in Responsive Web Design[rwdsummit] Adaptive Images in Responsive Web Design
[rwdsummit] Adaptive Images in Responsive Web DesignChristopher Schmitt
 
Building Progressive Web Apps for Android and iOS
Building Progressive Web Apps for Android and iOSBuilding Progressive Web Apps for Android and iOS
Building Progressive Web Apps for Android and iOSFITC
 
Oleh Zasadnyy "Progressive Web Apps: line between web and native apps become ...
Oleh Zasadnyy "Progressive Web Apps: line between web and native apps become ...Oleh Zasadnyy "Progressive Web Apps: line between web and native apps become ...
Oleh Zasadnyy "Progressive Web Apps: line between web and native apps become ...IT Event
 
[cssdevconf] Adaptive Images in Responsive Web Design
[cssdevconf] Adaptive Images in Responsive Web Design[cssdevconf] Adaptive Images in Responsive Web Design
[cssdevconf] Adaptive Images in Responsive Web DesignChristopher Schmitt
 
[psuweb] Adaptive Images in Responsive Web Design
[psuweb] Adaptive Images in Responsive Web Design[psuweb] Adaptive Images in Responsive Web Design
[psuweb] Adaptive Images in Responsive Web DesignChristopher Schmitt
 
[cssdevconf] Adaptive Images in RWD
[cssdevconf] Adaptive Images in RWD[cssdevconf] Adaptive Images in RWD
[cssdevconf] Adaptive Images in RWDChristopher Schmitt
 

Similar to Imagecon 2019 - Aaron Gustafson (20)

The things browsers can do! SAE Alumni Convention 2014
The things browsers can do! SAE Alumni Convention 2014The things browsers can do! SAE Alumni Convention 2014
The things browsers can do! SAE Alumni Convention 2014
 
HTML5 after the hype - JFokus2015
HTML5 after the hype - JFokus2015HTML5 after the hype - JFokus2015
HTML5 after the hype - JFokus2015
 
Practical Responsive Images - from Second Wednesday
Practical Responsive Images - from Second WednesdayPractical Responsive Images - from Second Wednesday
Practical Responsive Images - from Second Wednesday
 
AtlasCamp 2013: Modernizing your Plugin UI
AtlasCamp 2013: Modernizing your Plugin UI AtlasCamp 2013: Modernizing your Plugin UI
AtlasCamp 2013: Modernizing your Plugin UI
 
Progressive What Apps?
Progressive What Apps?Progressive What Apps?
Progressive What Apps?
 
Responsive images are here. Now what?
Responsive images are here. Now what?Responsive images are here. Now what?
Responsive images are here. Now what?
 
Web accessibility
Web accessibilityWeb accessibility
Web accessibility
 
Python Code Camp for Professionals 1/4
Python Code Camp for Professionals 1/4Python Code Camp for Professionals 1/4
Python Code Camp for Professionals 1/4
 
AtlasCamp 2015: Connect everywhere - Cloud and Server
AtlasCamp 2015: Connect everywhere - Cloud and ServerAtlasCamp 2015: Connect everywhere - Cloud and Server
AtlasCamp 2015: Connect everywhere - Cloud and Server
 
Responsive Responsive Design
Responsive Responsive DesignResponsive Responsive Design
Responsive Responsive Design
 
[CSSDevConf] Adaptive Images in Responsive Web Design 2014
[CSSDevConf] Adaptive Images in Responsive Web Design 2014[CSSDevConf] Adaptive Images in Responsive Web Design 2014
[CSSDevConf] Adaptive Images in Responsive Web Design 2014
 
The Future of CSS with Web components
The Future of CSS with Web componentsThe Future of CSS with Web components
The Future of CSS with Web components
 
The Future of CSS with Web Components
The Future of CSS with Web ComponentsThe Future of CSS with Web Components
The Future of CSS with Web Components
 
[rwdsummit] Adaptive Images in Responsive Web Design
[rwdsummit] Adaptive Images in Responsive Web Design[rwdsummit] Adaptive Images in Responsive Web Design
[rwdsummit] Adaptive Images in Responsive Web Design
 
Building Progressive Web Apps for Android and iOS
Building Progressive Web Apps for Android and iOSBuilding Progressive Web Apps for Android and iOS
Building Progressive Web Apps for Android and iOS
 
Oleh Zasadnyy "Progressive Web Apps: line between web and native apps become ...
Oleh Zasadnyy "Progressive Web Apps: line between web and native apps become ...Oleh Zasadnyy "Progressive Web Apps: line between web and native apps become ...
Oleh Zasadnyy "Progressive Web Apps: line between web and native apps become ...
 
Backbone js
Backbone jsBackbone js
Backbone js
 
[cssdevconf] Adaptive Images in Responsive Web Design
[cssdevconf] Adaptive Images in Responsive Web Design[cssdevconf] Adaptive Images in Responsive Web Design
[cssdevconf] Adaptive Images in Responsive Web Design
 
[psuweb] Adaptive Images in Responsive Web Design
[psuweb] Adaptive Images in Responsive Web Design[psuweb] Adaptive Images in Responsive Web Design
[psuweb] Adaptive Images in Responsive Web Design
 
[cssdevconf] Adaptive Images in RWD
[cssdevconf] Adaptive Images in RWD[cssdevconf] Adaptive Images in RWD
[cssdevconf] Adaptive Images in RWD
 

More from Cloudinary

Imagecon 2019 - Jon Sneyers
Imagecon 2019 - Jon Sneyers Imagecon 2019 - Jon Sneyers
Imagecon 2019 - Jon Sneyers Cloudinary
 
Imagecon 2019 - Jen Looper
Imagecon 2019 - Jen LooperImagecon 2019 - Jen Looper
Imagecon 2019 - Jen LooperCloudinary
 
Imagecon 2019 - Amy Balliett
Imagecon 2019 - Amy BalliettImagecon 2019 - Amy Balliett
Imagecon 2019 - Amy BalliettCloudinary
 
ImageCon CTO keynote
ImageCon CTO keynoteImageCon CTO keynote
ImageCon CTO keynoteCloudinary
 
ImageCon keynote product
ImageCon keynote productImageCon keynote product
ImageCon keynote productCloudinary
 
Drawing a Circle Three Ways: Generating Graphics for the Web
Drawing a Circle Three Ways: Generating Graphics for the WebDrawing a Circle Three Ways: Generating Graphics for the Web
Drawing a Circle Three Ways: Generating Graphics for the WebCloudinary
 
Images For Everyone
Images For EveryoneImages For Everyone
Images For EveryoneCloudinary
 
Beyond Resizing: The Image Performance Checklist
Beyond Resizing: The Image Performance ChecklistBeyond Resizing: The Image Performance Checklist
Beyond Resizing: The Image Performance ChecklistCloudinary
 
Moving Metrics with Better Mobile Images
Moving Metrics with Better Mobile ImagesMoving Metrics with Better Mobile Images
Moving Metrics with Better Mobile ImagesCloudinary
 
Images in the Era of the Algorithm
Images in the Era of the AlgorithmImages in the Era of the Algorithm
Images in the Era of the AlgorithmCloudinary
 
Media Processing Workflows using AWS Step Functions and Machine Learning on A...
Media Processing Workflows using AWS Step Functions and Machine Learning on A...Media Processing Workflows using AWS Step Functions and Machine Learning on A...
Media Processing Workflows using AWS Step Functions and Machine Learning on A...Cloudinary
 
The Physics of Fast Image Compression
The Physics of Fast Image CompressionThe Physics of Fast Image Compression
The Physics of Fast Image CompressionCloudinary
 

More from Cloudinary (13)

Imagecon 2019 - Jon Sneyers
Imagecon 2019 - Jon Sneyers Imagecon 2019 - Jon Sneyers
Imagecon 2019 - Jon Sneyers
 
Imagecon 2019 - Jen Looper
Imagecon 2019 - Jen LooperImagecon 2019 - Jen Looper
Imagecon 2019 - Jen Looper
 
Imagecon 2019 - Amy Balliett
Imagecon 2019 - Amy BalliettImagecon 2019 - Amy Balliett
Imagecon 2019 - Amy Balliett
 
Imagecon Itai
Imagecon ItaiImagecon Itai
Imagecon Itai
 
ImageCon CTO keynote
ImageCon CTO keynoteImageCon CTO keynote
ImageCon CTO keynote
 
ImageCon keynote product
ImageCon keynote productImageCon keynote product
ImageCon keynote product
 
Drawing a Circle Three Ways: Generating Graphics for the Web
Drawing a Circle Three Ways: Generating Graphics for the WebDrawing a Circle Three Ways: Generating Graphics for the Web
Drawing a Circle Three Ways: Generating Graphics for the Web
 
Images For Everyone
Images For EveryoneImages For Everyone
Images For Everyone
 
Beyond Resizing: The Image Performance Checklist
Beyond Resizing: The Image Performance ChecklistBeyond Resizing: The Image Performance Checklist
Beyond Resizing: The Image Performance Checklist
 
Moving Metrics with Better Mobile Images
Moving Metrics with Better Mobile ImagesMoving Metrics with Better Mobile Images
Moving Metrics with Better Mobile Images
 
Images in the Era of the Algorithm
Images in the Era of the AlgorithmImages in the Era of the Algorithm
Images in the Era of the Algorithm
 
Media Processing Workflows using AWS Step Functions and Machine Learning on A...
Media Processing Workflows using AWS Step Functions and Machine Learning on A...Media Processing Workflows using AWS Step Functions and Machine Learning on A...
Media Processing Workflows using AWS Step Functions and Machine Learning on A...
 
The Physics of Fast Image Compression
The Physics of Fast Image CompressionThe Physics of Fast Image Compression
The Physics of Fast Image Compression
 

Recently uploaded

sales plan presentation by mckinsey alum
sales plan presentation by mckinsey alumsales plan presentation by mckinsey alum
sales plan presentation by mckinsey alumzyqmx62fgm
 
Evolution and Growth of Supply chain.pdf
Evolution and Growth of Supply chain.pdfEvolution and Growth of Supply chain.pdf
Evolution and Growth of Supply chain.pdfGutaMengesha1
 
RMD24 | Retail media: hoe zet je dit in als je geen AH of Unilever bent? Heid...
RMD24 | Retail media: hoe zet je dit in als je geen AH of Unilever bent? Heid...RMD24 | Retail media: hoe zet je dit in als je geen AH of Unilever bent? Heid...
RMD24 | Retail media: hoe zet je dit in als je geen AH of Unilever bent? Heid...BBPMedia1
 
HR and Employment law update: May 2024.
HR and Employment law update:  May 2024.HR and Employment law update:  May 2024.
HR and Employment law update: May 2024.FelixPerez547899
 
Easy Way to Download and Set Up Gen TDS Software on Your Computer
Easy Way to Download and Set Up Gen TDS Software on Your ComputerEasy Way to Download and Set Up Gen TDS Software on Your Computer
Easy Way to Download and Set Up Gen TDS Software on Your ComputerSAG Infotech
 
Special Purpose Vehicle (Purpose, Formation & examples)
Special Purpose Vehicle (Purpose, Formation & examples)Special Purpose Vehicle (Purpose, Formation & examples)
Special Purpose Vehicle (Purpose, Formation & examples)linciy03
 
Business Valuation Principles for Entrepreneurs
Business Valuation Principles for EntrepreneursBusiness Valuation Principles for Entrepreneurs
Business Valuation Principles for EntrepreneursBen Wann
 
The Inspiring Personality To Watch In 2024.pdf
The Inspiring Personality To Watch In 2024.pdfThe Inspiring Personality To Watch In 2024.pdf
The Inspiring Personality To Watch In 2024.pdfinsightssuccess2
 
NewBase 24 May 2024 Energy News issue - 1727 by Khaled Al Awadi_compresse...
NewBase   24 May  2024  Energy News issue - 1727 by Khaled Al Awadi_compresse...NewBase   24 May  2024  Energy News issue - 1727 by Khaled Al Awadi_compresse...
NewBase 24 May 2024 Energy News issue - 1727 by Khaled Al Awadi_compresse...Khaled Al Awadi
 
Cracking the Workplace Discipline Code Main.pptx
Cracking the Workplace Discipline Code Main.pptxCracking the Workplace Discipline Code Main.pptx
Cracking the Workplace Discipline Code Main.pptxWorkforce Group
 
Cracking the Change Management Code Main New.pptx
Cracking the Change Management Code Main New.pptxCracking the Change Management Code Main New.pptx
Cracking the Change Management Code Main New.pptxWorkforce Group
 
8 Questions B2B Commercial Teams Can Ask To Help Product Discovery
8 Questions B2B Commercial Teams Can Ask To Help Product Discovery8 Questions B2B Commercial Teams Can Ask To Help Product Discovery
8 Questions B2B Commercial Teams Can Ask To Help Product DiscoveryDesmond Leo
 
Transforming Max Life Insurance with PMaps Job-Fit Assessments- Case Study
Transforming Max Life Insurance with PMaps Job-Fit Assessments- Case StudyTransforming Max Life Insurance with PMaps Job-Fit Assessments- Case Study
Transforming Max Life Insurance with PMaps Job-Fit Assessments- Case StudyPMaps Assessments
 
Matt Conway - Attorney - A Knowledgeable Professional - Kentucky.pdf
Matt Conway - Attorney - A Knowledgeable Professional - Kentucky.pdfMatt Conway - Attorney - A Knowledgeable Professional - Kentucky.pdf
Matt Conway - Attorney - A Knowledgeable Professional - Kentucky.pdfMatt Conway - Attorney
 
RMD24 | Debunking the non-endemic revenue myth Marvin Vacquier Droop | First ...
RMD24 | Debunking the non-endemic revenue myth Marvin Vacquier Droop | First ...RMD24 | Debunking the non-endemic revenue myth Marvin Vacquier Droop | First ...
RMD24 | Debunking the non-endemic revenue myth Marvin Vacquier Droop | First ...BBPMedia1
 
Taurus Zodiac Sign_ Personality Traits and Sign Dates.pptx
Taurus Zodiac Sign_ Personality Traits and Sign Dates.pptxTaurus Zodiac Sign_ Personality Traits and Sign Dates.pptx
Taurus Zodiac Sign_ Personality Traits and Sign Dates.pptxmy Pandit
 
IPTV Subscription UK: Your Guide to Choosing the Best Service
IPTV Subscription UK: Your Guide to Choosing the Best ServiceIPTV Subscription UK: Your Guide to Choosing the Best Service
IPTV Subscription UK: Your Guide to Choosing the Best ServiceDragon Dream Bar
 
Global Interconnection Group Joint Venture[960] (1).pdf
Global Interconnection Group Joint Venture[960] (1).pdfGlobal Interconnection Group Joint Venture[960] (1).pdf
Global Interconnection Group Joint Venture[960] (1).pdfHenry Tapper
 
Falcon Invoice Discounting Setup for Small Businesses
Falcon Invoice Discounting Setup for Small BusinessesFalcon Invoice Discounting Setup for Small Businesses
Falcon Invoice Discounting Setup for Small BusinessesFalcon investment
 
Memorandum Of Association Constitution of Company.ppt
Memorandum Of Association Constitution of Company.pptMemorandum Of Association Constitution of Company.ppt
Memorandum Of Association Constitution of Company.pptseri bangash
 

Recently uploaded (20)

sales plan presentation by mckinsey alum
sales plan presentation by mckinsey alumsales plan presentation by mckinsey alum
sales plan presentation by mckinsey alum
 
Evolution and Growth of Supply chain.pdf
Evolution and Growth of Supply chain.pdfEvolution and Growth of Supply chain.pdf
Evolution and Growth of Supply chain.pdf
 
RMD24 | Retail media: hoe zet je dit in als je geen AH of Unilever bent? Heid...
RMD24 | Retail media: hoe zet je dit in als je geen AH of Unilever bent? Heid...RMD24 | Retail media: hoe zet je dit in als je geen AH of Unilever bent? Heid...
RMD24 | Retail media: hoe zet je dit in als je geen AH of Unilever bent? Heid...
 
HR and Employment law update: May 2024.
HR and Employment law update:  May 2024.HR and Employment law update:  May 2024.
HR and Employment law update: May 2024.
 
Easy Way to Download and Set Up Gen TDS Software on Your Computer
Easy Way to Download and Set Up Gen TDS Software on Your ComputerEasy Way to Download and Set Up Gen TDS Software on Your Computer
Easy Way to Download and Set Up Gen TDS Software on Your Computer
 
Special Purpose Vehicle (Purpose, Formation & examples)
Special Purpose Vehicle (Purpose, Formation & examples)Special Purpose Vehicle (Purpose, Formation & examples)
Special Purpose Vehicle (Purpose, Formation & examples)
 
Business Valuation Principles for Entrepreneurs
Business Valuation Principles for EntrepreneursBusiness Valuation Principles for Entrepreneurs
Business Valuation Principles for Entrepreneurs
 
The Inspiring Personality To Watch In 2024.pdf
The Inspiring Personality To Watch In 2024.pdfThe Inspiring Personality To Watch In 2024.pdf
The Inspiring Personality To Watch In 2024.pdf
 
NewBase 24 May 2024 Energy News issue - 1727 by Khaled Al Awadi_compresse...
NewBase   24 May  2024  Energy News issue - 1727 by Khaled Al Awadi_compresse...NewBase   24 May  2024  Energy News issue - 1727 by Khaled Al Awadi_compresse...
NewBase 24 May 2024 Energy News issue - 1727 by Khaled Al Awadi_compresse...
 
Cracking the Workplace Discipline Code Main.pptx
Cracking the Workplace Discipline Code Main.pptxCracking the Workplace Discipline Code Main.pptx
Cracking the Workplace Discipline Code Main.pptx
 
Cracking the Change Management Code Main New.pptx
Cracking the Change Management Code Main New.pptxCracking the Change Management Code Main New.pptx
Cracking the Change Management Code Main New.pptx
 
8 Questions B2B Commercial Teams Can Ask To Help Product Discovery
8 Questions B2B Commercial Teams Can Ask To Help Product Discovery8 Questions B2B Commercial Teams Can Ask To Help Product Discovery
8 Questions B2B Commercial Teams Can Ask To Help Product Discovery
 
Transforming Max Life Insurance with PMaps Job-Fit Assessments- Case Study
Transforming Max Life Insurance with PMaps Job-Fit Assessments- Case StudyTransforming Max Life Insurance with PMaps Job-Fit Assessments- Case Study
Transforming Max Life Insurance with PMaps Job-Fit Assessments- Case Study
 
Matt Conway - Attorney - A Knowledgeable Professional - Kentucky.pdf
Matt Conway - Attorney - A Knowledgeable Professional - Kentucky.pdfMatt Conway - Attorney - A Knowledgeable Professional - Kentucky.pdf
Matt Conway - Attorney - A Knowledgeable Professional - Kentucky.pdf
 
RMD24 | Debunking the non-endemic revenue myth Marvin Vacquier Droop | First ...
RMD24 | Debunking the non-endemic revenue myth Marvin Vacquier Droop | First ...RMD24 | Debunking the non-endemic revenue myth Marvin Vacquier Droop | First ...
RMD24 | Debunking the non-endemic revenue myth Marvin Vacquier Droop | First ...
 
Taurus Zodiac Sign_ Personality Traits and Sign Dates.pptx
Taurus Zodiac Sign_ Personality Traits and Sign Dates.pptxTaurus Zodiac Sign_ Personality Traits and Sign Dates.pptx
Taurus Zodiac Sign_ Personality Traits and Sign Dates.pptx
 
IPTV Subscription UK: Your Guide to Choosing the Best Service
IPTV Subscription UK: Your Guide to Choosing the Best ServiceIPTV Subscription UK: Your Guide to Choosing the Best Service
IPTV Subscription UK: Your Guide to Choosing the Best Service
 
Global Interconnection Group Joint Venture[960] (1).pdf
Global Interconnection Group Joint Venture[960] (1).pdfGlobal Interconnection Group Joint Venture[960] (1).pdf
Global Interconnection Group Joint Venture[960] (1).pdf
 
Falcon Invoice Discounting Setup for Small Businesses
Falcon Invoice Discounting Setup for Small BusinessesFalcon Invoice Discounting Setup for Small Businesses
Falcon Invoice Discounting Setup for Small Businesses
 
Memorandum Of Association Constitution of Company.ppt
Memorandum Of Association Constitution of Company.pptMemorandum Of Association Constitution of Company.ppt
Memorandum Of Association Constitution of Company.ppt
 

Imagecon 2019 - Aaron Gustafson

  • 1. Media in the Age of PWAs Aaron Gustafson @AaronGustafson slideshare.net/AaronGustafson
  • 2. What exactly is a Progressive Web App? © Brad Frost
  • 3. What exactly is a Progressive Web App? © Brad Frost
  • 4. “Progressive Web App” is a marketing term Progressive Web App © Brad Frost
  • 11. @AaronGustafson A Minimum Viable PWA HTTPS Web App Manifest
  • 12. @AaronGustafson Web App Manifest { "lang": "en", "short_name": "Wash Post", "name": "The Washington Post", "icons": [ { "src": "img/launcher-icon-2x.png", "sizes": "96x96", "type": "image/png" } ], "start_url": "/pwa/", "display": "standalone", "orientation": "portrait", "background_color": "black" }
  • 13. @AaronGustafson A Minimum Viable PWA HTTPS Web App Manifest Service Worker
  • 16. Carnival: 24% opt-in rate and 42% open rate for push notifications Katarzyna Ostrowska aka.ms/carnival-pwa
  • 17. Starbucks: 2x increase in daily active users aka.ms/google-io-2018
  • 18. Tinder: Core experience with 90% less code aka.ms/tinder-pwa-2017
  • 19. Trivago: 97% increase in click-outs to hotel offers aka.ms/trivago-pwa-2017
  • 20. West Elm: 15% increase in time on site 9% increase in revenue per visit aka.ms/west-elm-pwa-2017
  • 21. @AaronGustafson A Minimum Viable PWA HTTPS Web App Manifest Service Worker
  • 23. @AaronGustafson Registering a Service Worker if ( "serviceWorker" in navigator ) { navigator.serviceWorker.register( "/serviceworker.min.js" ); }
  • 24. @AaronGustafson Registering a Service Worker if ( "serviceWorker" in navigator ) { navigator.serviceWorker.register( "/serviceworker.min.js" ); }
  • 25. @AaronGustafson Registering a Service Worker if ( "serviceWorker" in navigator ) { navigator.serviceWorker.register( "/serviceworker.min.js" ); }
  • 26. @AaronGustafson Registering a Service Worker if ( "serviceWorker" in navigator ) { navigator.serviceWorker.register( "/serviceworker.min.js" ); } Path is important!
  • 27. @AaronGustafson The Service Worker Lifecycle Browser Install Activation Ready aka.ms/pwa-lifecycle
  • 28. @AaronGustafson How connections are made Browser Internet
  • 29. @AaronGustafson Along comes Service Worker Browser Internet
  • 30. @AaronGustafson Along comes Service Worker Browser Internet Cache
  • 31. @AaronGustafson Along comes Service Worker Browser Internet Cache !
  • 32. @AaronGustafson Know your (storage) limits Temporary Persistent Browser purges User purges
  • 33. @AaronGustafson Know your (storage) limits Volume Size Domain Limit Overall Limit ≤ 8 GB 20% of overall 50 MB 8–32 GB 500 MB 32–128 GB 4% of volume > 128 GB 4% or 20 GB
  • 34. Except on iOS. Safari gives you 50 MB.
  • 36. Storage is a privilege, don’t abuse it.
  • 37. How?
  • 38. @AaronGustafson Make good choices 1. No animated GIFs (especially as backgrounds) 38
  • 39. @AaronGustafson Make good choices 2. Use responsive images 39 <img src="medium.jpg" srcset="small.jpg 256w, medium.jpg 512w, large.jpg 1024w" sizes="(max-width: 30em) 30em, 100vw" alt="It’s responsive!"> aka.ms/cloudinary-images
  • 40. @AaronGustafson Make good choices 3. Lazy load images 40 <img src="medium.jpg" srcset="small.jpg 256w, medium.jpg 512w, large.jpg 1024w" sizes="(max-width: 30em) 30em, 100vw" loading="lazy" alt="It’s responsive and lazy loads!"> aka.ms/img-lazy-loading
  • 41. @AaronGustafson Make good choices 4. Provide alternate image formats 41 <picture> <source type="image/webp" srcset="my.webp"> <img src="my.jpg" alt="Alt text goes here"> </picture>
  • 42. @AaronGustafson Make good choices 4. Provide alternate image formats (via Cloudinary URLs) 42 https://res.cloudinary.com/demo/image/upload/w_300,f_auto/my.jpg aka.ms/cloudinary-webp
  • 43. @AaronGustafson Make good choices 5. Provide fallback images via Service Worker 43 self.addEventListener( "install", function( event ){ event.waitUntil( caches.open( "static" ).then( cache => { return cache.addAll( ["/i/fallbacks/offline.svg"] ); }) ); }); function respondWithOfflineImage() { return caches.match( "/i/fallbacks/offline.svg" ); } aka.ms/ag-sw
  • 44. @AaronGustafson Make good choices 5. Provide fallback images via Service Worker 44 self.addEventListener( "install", function( event ){ event.waitUntil( caches.open( "static" ).then( cache => { return cache.addAll( ["/i/fallbacks/offline.svg"] ); }) ); }); function respondWithOfflineImage() { return caches.match( "/i/fallbacks/offline.svg" ); } aka.ms/ag-sw
  • 45. @AaronGustafson Make good choices 5. Provide fallback images via Service Worker 45 self.addEventListener( "install", function( event ){ event.waitUntil( caches.open( "static" ).then( cache => { return cache.addAll( ["/i/fallbacks/offline.svg"] ); }) ); }); function respondWithOfflineImage() { return caches.match( "/i/fallbacks/offline.svg" ); } aka.ms/ag-sw
  • 46. @AaronGustafson Make good choices 5. Provide fallback images via Service Worker 46 self.addEventListener( "install", function( event ){ event.waitUntil( caches.open( "static" ).then( cache => { return cache.addAll( ["/i/fallbacks/offline.svg"] ); }) ); }); function respondWithOfflineImage() { return caches.match( "/i/fallbacks/offline.svg" ); } aka.ms/ag-sw
  • 47. @AaronGustafson Make good choices 5. Provide fallback images via Service Worker 47 self.addEventListener( "install", function( event ){ event.waitUntil( caches.open( "static" ).then( cache => { return cache.addAll( ["/i/fallbacks/offline.svg"] ); }) ); }); function respondWithOfflineImage() { return caches.match( "/i/fallbacks/offline.svg" ); } aka.ms/ag-sw
  • 48. @AaronGustafson Make good choices 5. Provide fallback images via Service Worker 48 self.addEventListener( "install", function( event ){ event.waitUntil( caches.open( "static" ).then( cache => { return cache.addAll( ["/i/fallbacks/offline.svg"] ); }) ); }); function respondWithOfflineImage() { return caches.match( "/i/fallbacks/offline.svg" ); } aka.ms/ag-sw
  • 49. @AaronGustafson Make good choices 5. Provide fallback images via Service Worker 49 self.addEventListener( "fetch", event => { const request = event.request, url = request.url; if ( request.headers.get("Accept").includes("image") ) { event.respondWith( return fetch( request, fetch_config.images ) .then( response => { return response; }) .catch( respondWithOfflineImage ); ); } }); aka.ms/ag-sw
  • 50. @AaronGustafson Make good choices 5. Provide fallback images via Service Worker 50 self.addEventListener( "fetch", event => { const request = event.request, url = request.url; if ( request.headers.get("Accept").includes("image") ) { event.respondWith( return fetch( request, fetch_config.images ) .then( response => { return response; }) .catch( respondWithOfflineImage ); ); } }); aka.ms/ag-sw
  • 51. @AaronGustafson Make good choices 5. Provide fallback images via Service Worker 51 self.addEventListener( "fetch", event => { const request = event.request, url = request.url; if ( request.headers.get("Accept").includes("image") ) { event.respondWith( return fetch( request, fetch_config.images ) .then( response => { return response; }) .catch( respondWithOfflineImage ); ); } }); aka.ms/ag-sw
  • 52. @AaronGustafson Make good choices 5. Provide fallback images via Service Worker 52 self.addEventListener( "fetch", event => { const request = event.request, url = request.url; if ( request.headers.get("Accept").includes("image") ) { event.respondWith( return fetch( request, fetch_config.images ) .then( response => { return response; }) .catch( respondWithOfflineImage ); ); } }); aka.ms/ag-sw
  • 53. @AaronGustafson Make good choices 5. Provide fallback images via Service Worker 53 self.addEventListener( "fetch", event => { const request = event.request, url = request.url; if ( request.headers.get("Accept").includes("image") ) { event.respondWith( return fetch( request, fetch_config.images ) .then( response => { return response; }) .catch( respondWithOfflineImage ); ); } }); aka.ms/ag-sw
  • 54. @AaronGustafson Make good choices 5. Provide fallback images via Service Worker 54 self.addEventListener( "fetch", event => { const request = event.request, url = request.url; if ( request.headers.get("Accept").includes("image") ) { event.respondWith( return fetch( request, fetch_config.images ) .then( response => { return response; }) .catch( respondWithOfflineImage ); ); } }); aka.ms/ag-sw
  • 55. @AaronGustafson Make good choices 6. Pay attention to the Save Data header 55 let save_data = false; if ( 'connection' in navigator ) { save_data = navigator.connection.saveData; } aka.ms/ag-sw
  • 56. @AaronGustafson Make good choices 6. Pay attention to the Save Data header 56 self.addEventListener( "fetch", event => { const request = event.request, url = request.url; if ( request.headers.get("Accept").includes("image") ) { event.respondWith( if ( save_data ) { return respondWithFallbackImage( url ); } // … ); } aka.ms/ag-sw
  • 57. @AaronGustafson Make good choices 6. Pay attention to the Save Data header 57 const fallback_avatar = "/i/fallbacks/avatar.svg", fallback_image = "/i/fallbacks/image.svg", avatars = /webmention.io/; // … function respondWithFallbackImage( url ) { const image = avatars.test( url ) ? fallback_avatar : fallback_image; return caches.match( image ); } aka.ms/ag-sw
  • 58. @AaronGustafson Make good choices 6. Pay attention to the Save Data header 58 const fallback_avatar = "/i/fallbacks/avatar.svg", fallback_image = "/i/fallbacks/image.svg", avatars = /webmention.io/; // … function respondWithFallbackImage( url ) { const image = avatars.test( url ) ? fallback_avatar : fallback_image; return caches.match( image ); } aka.ms/ag-sw
  • 59. @AaronGustafson Make good choices 6. Pay attention to the Save Data header 59 const fallback_avatar = "/i/fallbacks/avatar.svg", fallback_image = "/i/fallbacks/image.svg", avatars = /webmention.io/; // … function respondWithFallbackImage( url ) { const image = avatars.test( url ) ? fallback_avatar : fallback_image; return caches.match( image ); } aka.ms/ag-sw
  • 60. @AaronGustafson Make good choices 7. Prioritize certain images 60 const high_priority = [ /aaron-gustafson.com/, /adaptivewebdesign.info/ ]; function isHighPriority( url ) { let i = high_priority.length; while ( i-- ) { if ( high_priority[i].test( url ) ) { return true; } } return false; } aka.ms/ag-sw
  • 61. @AaronGustafson Make good choices 7. Prioritize certain images 61 const high_priority = [ /aaron-gustafson.com/, /adaptivewebdesign.info/ ]; function isHighPriority( url ) { let i = high_priority.length; while ( i-- ) { if ( high_priority[i].test( url ) ) { return true; } } return false; } aka.ms/ag-sw
  • 62. @AaronGustafson Make good choices 7. Prioritize certain images 62 const high_priority = [ /aaron-gustafson.com/, /adaptivewebdesign.info/ ]; function isHighPriority( url ) { let i = high_priority.length; while ( i-- ) { if ( high_priority[i].test( url ) ) { return true; } } return false; } aka.ms/ag-sw
  • 63. @AaronGustafson Make good choices 8. Clean up after yourself 63 const version = "v2:", sw_caches = { static: { name: `${version}static` }, images: { name: `${version}images`, limit: 75 }, pages: { name: `${version}pages`, limit: 5 }, posts: { name: `${version}posts`, limit: 10 }, other: { name: `${version}other`, limit: 50 } }; aka.ms/ag-sw
  • 64. @AaronGustafson Make good choices 8. Clean up after yourself 64 function trimCache( cache_name, limit ) { caches.open( cache_name ).then( cache => { cache.keys().then( items => { if ( items.length > limit ) { cache.delete( items[0] ).then( trimCache( cache_name, limit ) ); } }); }); } aka.ms/ag-sw
  • 65. @AaronGustafson Make good choices 8. Clean up after yourself 65 function trimCache( cache_name, limit ) { caches.open( cache_name ).then( cache => { cache.keys().then( items => { if ( items.length > limit ) { cache.delete( items[0] ).then( trimCache( cache_name, limit ) ); } }); }); } aka.ms/ag-sw
  • 66. @AaronGustafson Make good choices 8. Clean up after yourself 66 function trimCache( cache_name, limit ) { caches.open( cache_name ).then( cache => { cache.keys().then( items => { if ( items.length > limit ) { cache.delete( items[0] ).then( trimCache( cache_name, limit ) ); } }); }); } aka.ms/ag-sw
  • 67. @AaronGustafson Make good choices 8. Clean up after yourself 67 if ( "serviceWorker" in navigator ) { navigator.serviceWorker.register( "/serviceworker.min.js" ); if ( navigator.serviceWorker.controller ) { window.addEventListener( "load", function(){ navigator.serviceWorker.controller.postMessage( "clean up" ); }); } } aka.ms/ag-sw
  • 68. @AaronGustafson Make good choices 8. Clean up after yourself 68 addEventListener("message", messageEvent => { if (messageEvent.data == "clean up") { for ( let key in sw_caches ) { if ( sw_caches[key].limit != undefined ) { trimCache( sw_caches[key].name, sw_caches[key].limit ); } } } }); aka.ms/ag-sw
  • 69. @AaronGustafson Make good choices 8. Clean up after yourself 69 addEventListener("message", messageEvent => { if (messageEvent.data == "clean up") { for ( let key in sw_caches ) { if ( sw_caches[key].limit != undefined ) { trimCache( sw_caches[key].name, sw_caches[key].limit ); } } } }); aka.ms/ag-sw
  • 70. @AaronGustafson Make good choices 1. No animated GIFs (especially as backgrounds) 2. Use responsive images 3. Lazy load images 4. Provide alternate image formats 5. Provide fallback images via Service Worker 6. Pay attention to the Save Data header 7. Prioritize certain images 8. Clean up after yourself 70