This post will become a short one but I'm pretty sure it's very helpful!

By default JSS supports srcSets on an image, the srcSet is passed like this:

<img alt="Sitecore JSS Logo" sizes="(min-width: 960px) 300px, 100px" class="img-fluid" srcset="/data/media/img/jss_logo.png?mw=300 300w, /data/media/img/jss_logo.png?mw=100 100w">

Pretty straight forward. With the srcset-attribute you can define the image size for every viewport you want to support.

You may notice that it's always the same image source which is just rendered in different sizes.

In a real life scenario it might happen that a picture looks perfect in a landscape format on a desktop device, but a portrait format would fit much better on a mobile device. Worst case would be you may want to have a seperate image source for every viewport.

This is not possible in JSS out of the box!

After searching a bit through the web I found this useful documentation: Responsive images | MDN

Many stuff to read... 😁

But there is one area that piqued my interest:

Art direction

To recap, the art direction problem involves wanting to change the image displayed to suit different image display sizes. For example, a web page includes a large landscape shot with a person in the middle when viewed on a desktop browser. When viewed on a mobile browser, that same image is shrunk down, making the person in the image very small and hard to see. It would probably be better to show a smaller, portrait image on mobile, which zooms in on the person. The "picture" element allows us to implement just this kind of solution.

Like "video" and "audio", the "picture" element is a wrapper containing several "source" elements that provide different sources for the browser to choose from, followed by the all-important "img" element.

Hey! That's exactly what I want to achieve!

It's pretty easy now to render Sitecore image fields for each viewport in a srcSet like this. In my case I'm working in an Angular JSS App so the idea was to extract this as an easy to use component.

The model for the component looks like this:

import { ImageField } from "@sitecore-jss/sitecore-jss-angular";

export interface ResponsiveImageModel {
    Smartphone: ImageField;
    Tablet: ImageField;
    Laptop: ImageField;
    Desktop: ImageField;
}

I did a bit more logic behind that to get at least one alternative text, but that is not relevant here.

export class ResponsiveImageComponent implements OnInit {

  @Input()
  model: ResponsiveImageModel;

  smartphoneImageSrc: string;
  tabletImageSrc: string;
  laptopImageSrc: string;
  desktopImageSrc: string;
  defaultImageSrc: string;
  defaultImageAlternateText: string;

  ngOnInit() {
    this.setImageSources();
  }
  ...
}

The output is very easy:

<picture>
  <source *ngIf="smartphoneImageSrc" media="(max-width: 600px)" srcset="{{this.smartphoneImageSrc}}">
  <source *ngIf="tabletImageSrc" media="(max-width: 960px)" srcset="{{this.tabletImageSrc}}">
  <source *ngIf="laptopImageSrc" media="(max-width: 1280px)" srcset="{{this.laptopImageSrc}}">
  <source *ngIf="desktopImageSrc" media="(min-width: 1281px)" srcset="{{this.desktopImageSrc}}">
  <img src="{{this.defaultImageSrc}}" alt="{{this.defaultImageAlternateText}}">
</picture>

If you think the browser will render four images you're wrong, he doesn't. The browser will reload the appropriate image if you scale the browser window, but if you are on a mobile or tablet device only one image will be loaded.

That's it, have fun

Best regards Dirk

The author

dirk-autor
Dirk Schäfauer
Dirk bei LinkedIn