Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

Handling images on the web

Handling images on the web

Handling images on the web seems simple – add an <img> tag, set its src and you're done. But then there's also SVGs that can be embedded directly in the DOM. Or you could inline any image with Base64. There's also images in CSS, images that are part of your app and images uploaded by users, various techniques for (pre-) loading images to maximize efficiency and much more. This talk gives an overview over everything to know and consider when using imagery on the web and some recommendations for common scenarios.

Marco Otte-Witte

March 25, 2021
Tweet

More Decks by Marco Otte-Witte

Other Decks in Programming

Transcript

  1. <picture > <source srcset="my-image-608.webp" type="image/webp" media="(max-width: 608px)" > <source srcset="my-image-1208.webp"

    type="image/webp" media="(min-width: 608px)" > <img src="/images/my-image.jpg" loading="lazy" decoding="async" style="background-size: cover; background-image: url('data:image/base64;…')" > </picture>
  2. <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" class="my-image" > <path d="…"></path

    > {{#if this.isActive}} <path d="…"></path > {{/if}} </svg > <style > .my-image path { fill: #818ca2 ; } </style>
  3. Images as essential UI Icons, status indicators, etc. are essential

    parts of an application’s UI. Images as data Images loaded as part of dynamic data from an API are only discovered at runtime. Static images Photos, illustrations, etc. make apps look nicer or support other data but are not required to enable functionality. https://https://guides.emberjs.com/release/getting-started/anatomy-of-an-ember-app/ https://unsplash.com/photos/_zKxPsGOGKg https://www.linkedin.com
  4. Images as essential UI Icons, status indicators, etc. are essential

    parts of an application’s UI. https://unsplash.com/photos/_zKxPsGOGKg
  5. Many but small Adapt to application state Must be present

    immediately https://www.linkedin.com/feed/
  6. <button class="contacts"></button> .contacts { height: 3.2rem ; width: 3.2rem ;

    background-image : url('/images/contacts.png'); } https://www.linkedin.com/feed/ .contacts.pending { background-image : url('/images/contacts-pending-1.png'); }
  7. <button class="contacts"></button > .contacts { height: 3.2rem ; width: 3.2rem

    ; background-image : url('data:image/png;…'); } https://www.linkedin.com/feed/ .contacts.pending { background-image : url('data:image/png;…'); }
  8. <link href="/fontawesome.css" rel="stylesheet" > <button class="contacts" > <i class="fa fa-users"></i

    > </button>
 
 .fa { display: inline-block ; font: FontAwesome ; } .fa-users:before { content: "\f0c0" ; } https://fontawesome.com/icons/font-awesome-logo-full <link href="/fontawesome.css" rel="stylesheet" > <button class="contacts" > <i class="fa fa-users-1"></i > </button>
 
 .fa { display: inline-block ; font: FontAwesome ; } .fa-users-1:before { content: "\f01e" ; }
  9. <button class="expand" > <svg xmlns="http://www.w3.org/2000/svg" > … </svg > </button>

    https://en.wikipedia.org/wiki/Scalable_Vector_Graphics#/media/File:SVG_logo_h.svg <button class="expand" > <svg xmlns="http://www.w3.org/2000/svg" > … {{#if this.pending}} <text class="pending" > {{this.pending}} </text > {{/if}} </svg > </button>
  10. Image URLs in CSS Base64 in CSS Icon Fonts SVG

    in DOM Immediate rendering ❌ ✅ ❌ ✅ extra weight added – CSS – Templates/JS can adapt to application state ❌ ❌ ❌ ✅ Images as essential UI
  11. Static Images Photos, illustrations, etc. make apps look nicer or

    support other data but are not required to enable functionality. https://www.linkedin.com
  12. http://linkedin.com <img src="/landing.jpg " > <img src="/landing.jpg" loading="lazy " >

    <img src="/landing.jpg " loading="lazy" sizes="(max-width: 608px) 100vw, 1280px " srcset="/landing-608.jpg 608w , /landing-1280.jpg 1280w " > <img src="/landing.jpg" loading="lazy" sizes="(max-width: 608px) 100vw, 1280px" srcset="/landing-608.jpg 608w , /landing-1280.jpg 1280w" decoding="async" > <img src="/landing.jpg" loading="lazy" sizes="(max-width: 608px) 100vw, 1280px" srcset="/landing-608.jpg 608w , /landing-1280.png 1280w" decoding="async" style="background-size: cover ; background-image: url('data:image/base64;…')" > <img src="/landing.jpg" loading="lazy" sizes="(max-width: 608px) 100vw, 1280px" srcset="/landing-608.jpg 608w, /landing-1280.png 1280w" decoding="async" style="background-size: cover; background-image: url('data:image/base64;…')" width="1280" height="400" >
  13. PNG Portable Networks Graphics https://tools.ietf.org/html/rfc2083 JPEG Joint Photographic Experts Group

    https://jpeg.org/jpeg/ https://en.wikipedia.org/wiki/Portable_Network_Graphics#/media/File:PNG_transparency_demonstration_1.png https://en.wikipedia.org/wiki/JPEG#/media/File:Felis_silvestris_silvestris_small_gradual_decrease_of_quality.png
  14. <picture > <source srcset="landing.webp" type="image/webp" > <img src="landing.jpg"> </picture> <picture

    > <source srcset="landing-608.webp" type="image/webp" media="(max-width: 608px)" > <source srcset="landing-1208.webp" type="image/webp" media="(min-width: 608px)" > <img src="landing.jpg"> </picture>
  15. http://linkedin.com <picture > <source srcset="landing-608.webp" type="image/webp" media="(max-width: 608px)" > <source

    srcset="landing-1208.webp" type="image/webp" media="(min-width: 608px)" > <img src="/landing.jpg" loading="lazy" decoding="async" style="background-size: cover; background-image: url('data:image/base64;…')" width="1280" height="400" > </picture>
  16. Images as data 27 Web apps (as opposed to web

    sites) use images a data that is dynamic and will change with changing application state https://www.linkedin.com/feed/
  17. GET /posts HTTP1.1 { "data": [ { "id": "1" ,

    "type": "posts" , "attributes": { "title": "Interface Inventory Workshop" , "text": "Join our remote workshop…" , "picture": "/images/v4545rfre2.jpg" } } , … ] } https://www.linkedin.com/feed/ <article > <h4>{{@post.title}}</h4 > <p>{{@post.text}}</p > <img src={{@post.picture}} > </article>
  18. GET /posts HTTP1.1 { "data": [ { "id": "1" ,

    "type": "posts" , "attributes": { "title": "Interface Inventory Workshop" , "text": "Join our remote workshop…" , "picture": { "url": { "small": "/images/v4545rfre2.webp" , "large": "/images/v4545rfr45g.webp" , "fallback": "/images/v4545rfr45g.jpg" } "placeholder": "data:image/base64;…" , "dimensions": { "width": 200 , "height": 100 } } } } , … ] } https://www.linkedin.com/feed/ <article > <h4>{{@post.title}}</h4 > <p>{{@post.text}}</p > <picture > <source srcset={{@post.picture.url.small}} type="image/webp" media="(max-width: 608px)" > <source srcset={{@post.picture.url.large}} type="image/webp" media="(min-width: 608px)" > <img src={{@post.picture.url.fallback}} style="background-image: url({{@post.picture.placeholder}})" width={{@post.picture.dimensions.width}} height={{@post.picture.dimensions.height}} loading="lazy" decoding="async" > </picture > </article>
  19. async model() { let posts = await this.store.findAll("post") ; await

    Promise.all(posts.map(p) = > preloadImage(p.picture)) ; return posts ; } function preloadImage(src) { return new Promise(function(resolve, reject) { var image = new Image() ; image.onload = resolve ; image.onerror = resolve ; image.src = path ; }) ; } https://www.linkedin.com/feed/
  20. https://www.linkedin.com/feed/ Provide additional data for images rather than just a

    URL via the API (consider preloading images in the Ember routing layer)