$30 off During Our Annual Pro Sale. View Details »

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. Handling images on the web
    Marco Otte-Witte

    Managing Director, simplabs

    @marcoow

    View Slide

  2. 2
    https://en.wikipedia.org/wiki/Les_Horribles_Cernettes#/media/File:Les_Horribles_Cernettes_in_1992.jpg

    View Slide

  3. src="/images/my-image.jpg
    "

    >

    View Slide

  4. >

    srcset="my-image-608.webp" type="image/webp"
    media="(max-width: 608px)"
    >

    srcset="my-image-1208.webp" type="image/webp"
    media="(min-width: 608px)"
    >

    src="/images/my-image.jpg"
    loading="lazy"
    decoding="async"
    style="background-size: cover;
    background-image: url('data:image/base64;…')"
    >


    View Slide

  5. class="my-image"
    >

    >

    {{#if this.isActive}}
    >

    {{/if}}
    >

    >

    .my-image path
    {

    fill: #818ca2
    ;

    }


    View Slide

  6. https://unsplash.com/photos/1tpLdmxki-c

    View Slide

  7. 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

    View Slide

  8. Images as essential UI
    Icons, status indicators, etc. are essential parts of an
    application’s UI.
    https://unsplash.com/photos/_zKxPsGOGKg

    View Slide

  9. Many but small
    Adapt to application state
    Must be present immediately
    https://www.linkedin.com/feed/

    View Slide


  10. .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');


    }

    View Slide

  11. >

    .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;…');


    }

    View Slide

  12. href="/fontawesome.css"
    rel="stylesheet"
    >

    >

    >



    .fa
    {

    display: inline-block
    ;

    font: FontAwesome
    ;

    }

    .fa-users:before
    {

    content: "\f0c0"
    ;

    }
    https://fontawesome.com/icons/font-awesome-logo-full
    href="/fontawesome.css"
    rel="stylesheet"
    >

    >

    >



    .fa
    {

    display: inline-block
    ;

    font: FontAwesome
    ;

    }

    .fa-users-1:before
    {

    content: "\f01e"
    ;

    }

    View Slide

  13. >

    xmlns="http://www.w3.org/2000/svg"
    >



    >


    https://en.wikipedia.org/wiki/Scalable_Vector_Graphics#/media/File:SVG_logo_h.svg
    >

    xmlns="http://www.w3.org/2000/svg"
    >



    {{#if this.pending}}
    >

    {{this.pending}}
    >

    {{/if}}
    >


    View Slide

  14. View Slide

  15. ember-template-lint
    https://github.com/ember-template-lint/ember-template-lint
    https://github.com/ember-template-lint

    View Slide

  16. ember-asset-sizes-action
    https://github.com/simplabs/ember-asset-size-action
    https://github.com/ember-learn/ember-website/pull/783

    View Slide

  17. 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

    View Slide

  18. Static Images
    Photos, illustrations, etc. make apps look nicer or support other
    data but are not required to enable functionality.
    https://www.linkedin.com

    View Slide

  19. Few but big
    No adaption to application state
    Non-essential
    http://linkedin.com

    View Slide

  20. http://linkedin.com
    src="/landing.jpg
    "

    >

    src="/landing.jpg"
    loading="lazy
    "

    >
    src="/landing.jpg
    "

    loading="lazy"
    sizes="(max-width: 608px) 100vw, 1280px
    "

    srcset="/landing-608.jpg 608w
    ,

    /landing-1280.jpg 1280w
    "

    >

    src="/landing.jpg"
    loading="lazy"
    sizes="(max-width: 608px) 100vw, 1280px"
    srcset="/landing-608.jpg 608w
    ,

    /landing-1280.jpg 1280w"
    decoding="async"
    >
    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;…')"
    >
    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"
    >

    View Slide

  21. 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

    View Slide

  22. WebP
    https://developers.google.com/speed/webp
    https://en.wikipedia.org/wiki/WebP#/media/File:WebPLogo.svg

    View Slide

  23. https://caniuse.com/webp

    View Slide

  24. >

    >





    >

    srcset="landing-608.webp" type="image/webp"
    media="(max-width: 608px)"
    >

    srcset="landing-1208.webp"
    type="image/webp" media="(min-width: 608px)"
    >





    View Slide

  25. PNG, 201KB WebP, 25KB

    View Slide

  26. http://linkedin.com
    >

    srcset="landing-608.webp" type="image/webp"
    media="(max-width: 608px)"
    >

    srcset="landing-1208.webp"
    type="image/webp" media="(min-width: 608px)"
    >

    src="/landing.jpg"
    loading="lazy"
    decoding="async"
    style="background-size: cover;
    background-image: url('data:image/base64;…')"
    width="1280"
    height="400"
    >


    View Slide

  27. 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/

    View Slide

  28. https://www.linkedin.com/feed/
    Similar to static images otherwise
    Discovered at runtime

    View Slide

  29. 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/
    >

    {{@post.title}}>

    {{@post.text}}>

    >


    View Slide

  30. 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/
    >

    {{@post.title}}>

    {{@post.text}}>

    >

    srcset={{@post.picture.url.small}}
    type="image/webp"
    media="(max-width: 608px)"
    >

    srcset={{@post.picture.url.large}}
    type="image/webp"
    media="(min-width: 608px)"
    >

    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"
    >

    >


    View Slide

  31. 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/

    View Slide

  32. 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)

    View Slide

  33. https://www.shutterstock.com/de/image-photo/man-think-how-solve-mathematical-problem-766012597

    View Slide

  34. https://img.zeit.de/kultur/kunst/2018-10/sothebys-auktion-street-art-schredder/wide__1300x731

    View Slide

  35. Thanks!
    Marco Otte-Witte

    Managing Director, simplabs

    @marcoow

    View Slide