Lazysizes: Multiple image types with data-bgset

Created on 17 Apr 2017  Â·  10Comments  Â·  Source: aFarkas/lazysizes

Does the lazysizes bgset plugin support selective image types? For example, on a regular image I might use the code:

<picture>
  <source srcset="/large.webp" type="image/webp">
  <source srcset="/large.jp2" type="image/jp2">
  <img srcset="/large.jpg">
</picture>

And I would like to do something similar with a background image loaded with the bgset plugin. For example:

<a href="/weblink" data-bgset-webp="/large.webp" data-bgset-jp2="/large.jp2" data-bgset-jpg="/large.jpg" class="lazyload">
  <div class="content">
    <p>Some text</p>
  </div>
</a>

Is something like this possible? Or am I being dense and there's an easier way to achieve this functionality for inline background images?

Most helpful comment

@aFarkas

+1 for this feature.

All 10 comments

I was able to hack a solution together by adding Modernizr and modifying the bgset plugin:

addEventListener('lazybeforeunveil', function(e){
  var set, image, elem;

  if(e.defaultPrevented || !(set = e.target.getAttribute('data-bgset')) || !(set = e.target.getAttribute('data-bgwebp')) || !(set = e.target.getAttribute('data-bgjxr')) || !(set = e.target.getAttribute('data-bgjp2'))){return;}

  Modernizr.on('webp', function (result) {
    if (result && (set = e.target.getAttribute('data-bgwebp'))) {
        elem = e.target;
        image = document.createElement('img');
        image.alt = '';
        image._lazybgsetLoading = true;
        e.detail.firesLoad = true;

            createPicture(set, elem, image);

        setTimeout(function(){
            lazySizes.loader.unveil(image);

            lazySizes.rAF(function(){
                lazySizes.fire(image, '_lazyloaded', {}, true, true);
                if(image.complete) {
                    proxyLoad({target: image});
                }
            });
        });
  }
  else {
      Modernizr.on('jpegxr', function (result) {
        if (result && (set = e.target.getAttribute('data-bgjxr'))) {
            elem = e.target;
            image = document.createElement('img');
            image.alt = '';
            image._lazybgsetLoading = true;
            e.detail.firesLoad = true;

                createPicture(set, elem, image);

            setTimeout(function(){
                lazySizes.loader.unveil(image);

                lazySizes.rAF(function(){
                    lazySizes.fire(image, '_lazyloaded', {}, true, true);
                    if(image.complete) {
                        proxyLoad({target: image});
                    }
                });
            });
      }
      else {
          Modernizr.on('jpeg2000', function (result) {
            if (result && (set = e.target.getAttribute('data-bgjp2'))) {
                elem = e.target;
                image = document.createElement('img');
                image.alt = '';
                image._lazybgsetLoading = true;
                e.detail.firesLoad = true;

                    createPicture(set, elem, image);

                setTimeout(function(){
                    lazySizes.loader.unveil(image);

                    lazySizes.rAF(function(){
                        lazySizes.fire(image, '_lazyloaded', {}, true, true);
                        if(image.complete) {
                            proxyLoad({target: image});
                        }
                    });
                });
          }
          else {
            if ((set = e.target.getAttribute('data-bgset'))) {
                elem = e.target;
                image = document.createElement('img');
                image.alt = '';
                image._lazybgsetLoading = true;
                e.detail.firesLoad = true;

                    createPicture(set, elem, image);

                setTimeout(function(){
                    lazySizes.loader.unveil(image);

                    lazySizes.rAF(function(){
                        lazySizes.fire(image, '_lazyloaded', {}, true, true);
                        if(image.complete) {
                            proxyLoad({target: image});
                        }
                    });
                });
            }
          }
        });
      }
    });
  }
});

});

To use this hack, add the attributes data-bgwebp for webp, data-bgjxr for JPEG XR, and data-jp2 for JPEG 2000 to your background images.

@aFarkas : As you are far more skilled at JavaScript, is this something you can add to the bgset plugin (or a separate plugin)?

I figured out a better way to utilize Webp, JPEG XR, and JPEG 2000 without needing Modernizr. Simply add sources for the different image types to the picture element created by the bgset plugin:

var createPicture = function(webps, jxrs, jp2s, sets, elem, img) {
var picture = document.createElement('picture');
var sizes = elem.getAttribute(lazySizesConfig.sizesAttr);
var ratio = elem.getAttribute('data-ratio');
var optimumx = elem.getAttribute('data-optimumx');

if(elem._lazybgset && elem._lazybgset.parentNode == elem){
    elem.removeChild(elem._lazybgset);
}

Object.defineProperty(img, '_lazybgset', {
    value: elem,
    writable: true
});
Object.defineProperty(elem, '_lazybgset', {
    value: picture,
    writable: true
});

webps = webps.replace(regWhite, ' ').split(regSplitSet);
jxrs = jxrs.replace(regWhite, ' ').split(regSplitSet);
jp2s = jp2s.replace(regWhite, ' ').split(regSplitSet);
sets = sets.replace(regWhite, ' ').split(regSplitSet);

picture.style.display = 'none';
img.className = lazySizesConfig.lazyClass;

if(sets.length == 1 && !sizes){
    sizes = 'auto';
}

webps.forEach(function(webp){
    var source = document.createElement('source');

    source.setAttribute('type', 'image/webp');

    if(sizes && sizes != 'auto'){
        source.setAttribute('sizes', sizes);
    }

    if(webp.match(regSource)){
        source.setAttribute(lazySizesConfig.srcsetAttr, RegExp.$1);
        if(RegExp.$2){
            source.setAttribute('media', lazySizesConfig.customMedia[RegExp.$2] || RegExp.$2);
        }
    }
    picture.appendChild(source);
});

jxrs.forEach(function(jxr){
    var source = document.createElement('source');

    source.setAttribute('type', 'image/vnd.ms-photo');

    if(sizes && sizes != 'auto'){
        source.setAttribute('sizes', sizes);
    }

    if(jxr.match(regSource)){
        source.setAttribute(lazySizesConfig.srcsetAttr, RegExp.$1);
        if(RegExp.$2){
            source.setAttribute('media', lazySizesConfig.customMedia[RegExp.$2] || RegExp.$2);
        }
    }
    picture.appendChild(source);
});

jp2s.forEach(function(jp2){
    var source = document.createElement('source');

    source.setAttribute('type', 'image/jp2');

    if(sizes && sizes != 'auto'){
        source.setAttribute('sizes', sizes);
    }

    if(jp2.match(regSource)){
        source.setAttribute(lazySizesConfig.srcsetAttr, RegExp.$1);
        if(RegExp.$2){
            source.setAttribute('media', lazySizesConfig.customMedia[RegExp.$2] || RegExp.$2);
        }
    }
    picture.appendChild(source);
});

sets.forEach(function(set){
    var source = document.createElement('source');

    if(sizes && sizes != 'auto'){
        source.setAttribute('sizes', sizes);
    }

    if(set.match(regSource)){
        source.setAttribute(lazySizesConfig.srcsetAttr, RegExp.$1);
        if(RegExp.$2){
            source.setAttribute('media', lazySizesConfig.customMedia[RegExp.$2] || RegExp.$2);
        }
    }
    picture.appendChild(source);
});

if(sizes){
    img.setAttribute(lazySizesConfig.sizesAttr, sizes);
    elem.removeAttribute(lazySizesConfig.sizesAttr);
    elem.removeAttribute('sizes');
}
if(optimumx){
    img.setAttribute('data-optimumx', optimumx);
}
if(ratio) {
    img.setAttribute('data-ratio', ratio);
}

picture.appendChild(img);

elem.appendChild(picture);
};

var proxyLoad = function(e){
if(!e.target._lazybgset){return;}

var image = e.target;
var elem = image._lazybgset;
var bg = image.currentSrc || image.src;

if(bg){
    elem.style.backgroundImage = 'url(' + (regBgUrlEscape.test(bg) ? JSON.stringify(bg) : bg ) + ')';
}

if(image._lazybgsetLoading){
    lazySizes.fire(elem, '_lazyloaded', {}, false, true);
    delete image._lazybgsetLoading;
}
};

addEventListener('lazybeforeunveil', function(e){
var webp, jxr, jp2, set, image, elem;

if(e.defaultPrevented || !(webp = e.target.getAttribute('data-bgwebp')) || !(jxr = e.target.getAttribute('data-bgjxr')) || !(jp2 = e.target.getAttribute('data-bgjp2')) || !(set = e.target.getAttribute('data-bgset'))){return;}

elem = e.target;
image = document.createElement('img');

image.alt = '';

image._lazybgsetLoading = true;
e.detail.firesLoad = true;

createPicture(webp, jxr, jp2, set, elem, image);

setTimeout(function(){
    lazySizes.loader.unveil(image);

    lazySizes.rAF(function(){
        lazySizes.fire(image, '_lazyloaded', {}, true, true);
        if(image.complete) {
            proxyLoad({target: image});
        }
    });
});

});

@aFarkas : Can you implement this improvement to the bgset plugin?

@frontalot
Yes and no. I would prefer a string solution that is built on top of the current version.

Your code predefines the priority of the types and makes fixes all types (no possibility to add new ones).

I would suggest something like this:

image-200.webp [(max-width: 480px)][type=image/webp] | image-200.jpg [(max-width: 480px)] | image-300.webp [(max-width: 700px)][type=image/webp] |image-300.jpg [(max-width: 700px)] | image-400.jpg [type=image/webp]  | image-400.jpg

@aFarkas,

Any progress on this? I would love to be able to load a webp image as a background image when possible and then default to a png for browsers that don't support webp.

@aFarkas

+1 for this feature.

I will add this feature till next Monday. Please note the following: You should already be able to do this using a normal image and placing it - using position: absolute - in the background. The object-fit polyfill for IE should be also handy in some situations.

In case you use the bgset plugin to get better support for object-fit I highly recommend to use the object-fit polyfill instead.

@aFarkas

Any update on this? Can't wait to start using this in future projects :D

I was looking for webp support when using bgset plugin because using a picture with position: absolute feels like an ugly workaround. That brought me to this issue.

+1 for this feature – would be a huge improvement of the plugin!

@aFarkas do you need any help on this?

any updates? Would be awesome to have this feature...

Sorry guys. I just added this feature to the master branch. Please give it a try, if ti is ok I will make a new release.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

zenderol picture zenderol  Â·  5Comments

thasmo picture thasmo  Â·  6Comments

tomasts248 picture tomasts248  Â·  6Comments

Undistraction picture Undistraction  Â·  5Comments

jpw123 picture jpw123  Â·  6Comments