ApoorvSaxena / lozad.js

🔥 Highly performant, light ~1kb and configurable lazy loader in pure JS with no dependencies for responsive images, iframes and more
https://apoorv.pro/lozad.js/demo/
MIT License
7.46k stars 446 forks source link

Feature Request: data-background-image responsive images with data-srcset #90

Open Giovanni-Mattucci opened 6 years ago

Giovanni-Mattucci commented 6 years ago

Currently I use various media queries to include a different background image as needed, and being able to apply lozad to achieve the same result would be great :).

I wish you could define various background images per screen size in the same way you can for responsive images:

<!-- background image example -->
<div class="lozad" data-background-image="image.png" data-srcset="image.png 1000w, image-2x.png 2000w">
</div>
mediabeastnz commented 6 years ago

Bump!

patrickpietens commented 6 years ago

Bump!

ApoorvSaxena commented 6 years ago

@Giovanni-Mattucci @mediabeastnz @patrickpietens what implementation change do you suggest in library?

sprynm commented 6 years ago

The current docs show:

<!-- responsive image example -->
<img class="lozad" data-src="image.png" data-srcset="image.png 1000w, image-2x.png 2000w" />

It would seem this is addressed by applying the same behavior to <div class="lozad" data-background-image="image.png">

I see what is happening, you are just leveraging the native srcset attribute, not actually calculating the browser width and matching the break point. Unfortunately, this doesn't exist background-image: urlset=(image.png 1000w, image-2x.png 2000w);

It would seem supporting this feature would add considerable weight to the script. Perhaps better as a plugin/extension of sorts?

ApoorvSaxena commented 6 years ago

we can document custom loading function to implement this behaviour to start with

allanwhite commented 6 years ago

Definitely wanted to support a Bump on this one.

Another approach, at least for the users of lozad, might be to have different data-breakpoint-___s that are user defined. So someone like me would add a list of breakpoint widths as an array, and then lozad could have different sources per breakpoint.

<img class="lozad" data-src="image.png" data-breakpoint-sm="image-256.png" data-breakpoint-md="image-512.png" />

That's fairly tedious, so maybe an array like Foundation, which solves a similar problem with their Interchange responsive plugin, has a syntax like so:

<img data-interchange="[file.jpg, small], [file-medium.jpg, medium]" />

with the breakpoints defined globally (not actually sure if they are referencing CSS breakpoints, or they're in JS somewhere as values in foundation).

Interchange works pretty well actually; what it does not do is lazy-loading like Lozad.

darrenjacoby commented 6 years ago

I also needed this, so got a version of it working.

I can now pass in data-background-image-md, data-background-image-lg, etc, depending on breakpoint values that I define in the JS.

You need to re-write load from the original, the only thing changing here is this section;

if (item.getAttribute('data-background-image')) {

}

If there is a better way to overwrite something in the existing load() function that would be helpful.

The rest remains as is, full example below;

const isIE = typeof document !== 'undefined' && document.documentMode

// breakpoints for backgrounds
let breakpoints = [
  {
    src: 'sm',
    width: 576,
  },
  {
    src: 'md',
    width: 768,
  },
  {
    src: 'lg',
    width: 992,
  },
  {
    src: 'xl',
    width: 1200,
  },
  {
    src: 'xx',
    width: 1400,
  },
];

// get screen size
let screen = document.documentElement.clientWidth;

// observer
let observer = lozad(el, {
  load: (item) => {
    // picture
    if (element.nodeName.toLowerCase() === 'picture') {
      const img = document.createElement('img')
      if (isIE && element.getAttribute('data-iesrc')) {
        img.src = element.getAttribute('data-iesrc')
      }
      if (element.getAttribute('data-alt')) {
        img.alt = element.getAttribute('data-alt')
      }
      element.appendChild(img)
    }

    // data-src
    if (item.getAttribute('data-src')) {
      item.src = item.getAttribute('data-src');
    }

    // data-srcset
    if (item.getAttribute('data-srcset')) {
      item.srcset = item.getAttribute('data-srcset');
    }

    // data-background-image
    if (item.getAttribute('data-background-image')) {

      // return a breakpoint that qualifies
      let breakpoint = breakpoints
        .filter(function(breakpoint) {
          // return if item is larger than screen width
          // return if data-background-image for the breakpoint exists
          if (screen >= breakpoint.width && item.getAttribute(`data-background-image-${breakpoint.src}`)) {
            return (breakpoint.src);
          }
        })
        // get the last item
        .pop();

      // default data-background-image
      let attr = item.getAttribute('data-background-image');

      // if a breakpoint qualified, then change the attr
      if (breakpoint) {
        attr = item.getAttribute(`data-background-image-${breakpoint.src}`);
      }

      // set the background-image css prop
      item.style.backgroundImage = `url(${attr})`;
    }

    // data-toggle-class
    if (item.getAttribute('data-toggle-class')) {
      item.classList.toggle(item.getAttribute('data-toggle-class'));
    }
  },
  loaded: (item) => {
    item.classList.add('lozad-loaded');
  },
});

// run
observer.observe();
allanwhite commented 6 years ago

@darrenjacoby Would you consider submitting this as a PR?

ZCweb commented 6 years ago

@darrenjacoby That's great that you got the code working. I have the lozad minified file loading in my Wordpress theme. I am running functions in another file. Do I add this to the main Lozad file and where, replace the whole thing? Can you share your complete modified version as a JS file?