2

I have the following scenario - the main page banner should have at any time 1 of 3 images displayed at a given viewport size. These images are art-directed, that is to say, that will differ in content and layout and are created with desktop, tablet and mobile in mind. (All of this is despite my protests).

I'm wondering what are the options for requesting the correct image at the appropriate viewport size? (Optimisation is very much a concern here! I don't want to serve 3 images only to use 1.) My understanding when it comes to D8 and responsive images is that D8 will create versions of the same image for the srcset rather than giving the option to serve different images at different viewport sizes.

So what are my options here? Perhaps the best option is to have 3 image fields that are outputting directly into a srcset in a banner template.

3
  • Hahaha, poor you. But interesting riddle! I'd probably go for either a custom responsive image field formatter (that replaces the different srcset values with images from the node), or quick and dirty with hook_preprocess_responsive_image to do something similar. But definitely with multiple image fields, one for each breakpoint. – leymannx Nov 9 '18 at 13:05
  • Although probably difficult or impossible to get the parent node object from within hook_preprocess_responsive_image... – leymannx Nov 9 '18 at 13:17
  • Go for a pseudo field! There you have to entity and you can grab any field you want to build your custom template. – leymannx Nov 9 '18 at 14:27
3

Are they completely different images?

Then I'd use Paragraphs module and create a heavily customized template outputting your different images as <source srcset="..." media=""> inside a single <picture> tag. Modern browsers will only download the correct version for the visitors viewport. (Manually add a polyfill library if required.)

Is there one large source image rendered with different focal points or different crop areas (Modules "Focal point" or "Image widget crop")?

Then I'd create a specific breakpoint group only for your banner. Create a responsive image style for this group and use Select a single image style for each individual breakpoint width. Drupal will then automatically render a similar markup as above and also add polyfills for older browsers.

In any case, definitely use a <picture> tag with multiple <source srcset="...filename..." media="(...mediaquery...)">s for art directed responsive images.

1
  • I was overthinking this and that the picture element is exactly what I require. See developer.mozilla.org/en-US/docs/Learn/HTML/…. In my case I am outputing the paragraph fields (e.g. {{fields.field_you_field.content }}) in a view and then outputting this in a region – LMG Nov 24 '18 at 10:13
-2

I came across the same problem, solved it, and wrote a tutorial about it.

The key is to use 2 different images (rendered as picture elements), positioned on the same place. An image uses the Mobile only responsive image style; the other images uses the Desktop only style. In this way, for any given viewport, there is only an image loaded and visible.

Implementing a hook, it's possible to add a max-width property to the Mobile only image style to make it not visible in desktop mode. Another can prevent the <img> tag from rendering.

function od_helper_preprocess_responsive_image(&$variables) {
  $responsive_image_style = $variables['responsive_image_style_id'];

  // Prevent mobile images to be shown for viewport-width > 767px.
  if ($responsive_image_style == "mobile") {
    if (isset($variables['sources'])) {
      foreach ($variables['sources'] as $source) {
        $value = $source["media"]->value();
        $value = $value . " and (max-width:767px)";
        $source["media"] = new AttributeString("media", $value);
      }
    }

  // Prevent fallback-image from rendering by removing src and alt and store it in data attributes. This fallback-images are later repaired depending on viewport size by js behaviour px1_ResponsiveImageContainerActivateFallbacks
 
  if ($responsive_image_style == "mobile" || 
      $responsive_image_style == "desktop") {

    $img = $variables["img_element"];
    $img["#attributes"]["data-src"] = $img["#uri"];
    $img["#attributes"]["data-alt"] = $img["#alt"];
    $img["#uri"] = "";
    $img["#alt"] = "";
    $variables["img_element"] = $img;
  }
}

We can later activate the appropriate image via JavaScript, depending on the viewport size. This is relevant for Internet Explorer which doesn't support the picture element.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.