IT TIP

Is there a srcset equivalent for css background image

itqueen 2020. 10. 21. 22:13
반응형

Is there a srcset equivalent for css background image


img with srcset attribute looks like a great way of doing responsive images. Is there an equivalent syntax that works in css background-image property?

HTML

<img src="small.jpg" srcset="medium.jpg 1000w, large.jpg 2000w" alt="yah">

CSS

.mycontainer {
    background: url(?something goes here?);
}

image-set is the equivalent CSS feature. We should add equivalent srcset functionality (defining resources according to their dimensions) to the spec.

Currently it's only implemented in Safari, Chrome and Opera with the -webkit- prefix, and it's only support the x descriptors.


Pretty sure that:

background: -webkit-image-set( url('path/to/image') 1x, url('path/to/high-res-image') 2x );

works the same way. The browser will examine the images, see which fits best and will use that one.


For a polyfill, you can use an img with srcset as a mechanism for downloading the correct image size, then use JS to hide it and set the background-image of a parent element.

Here's a fiddle: http://jsbin.com/garetikubu/edit?html,output

The use of onload and putting the JS as a blocking script in the <head> is important. If you put the script later (say at the end of <body>), you can get a race condition where img.currentSrc hasn't been set yet by the browser. It's best to wait for it to be loaded.

The example allows you to see the original img being downloaded. You can easily hide it with some CSS.


Another approach, which is quite frankly more robust, would be to adapt the characteristics and options of background images to an image with the srcset attribute.

To do this, set the image to be width: 100%; height: 100%; and object-fit: cover or contain.

Here is an example:

.psuedo-background-img-container {
  position: relative;
  width:400px;
  height: 200px;
}
.psuedo-background-img {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
<div class="psuedo-background-img-container">

<img class="psuedo-background-img" src="https://cdn3.tnwcdn.com/wp-content/blogs.dir/1/files/2016/12/Keep.jpg" srcset="https://cdn0.tnwcdn.com/wp-content/blogs.dir/1/files/2016/12/Keep.jpg 640w, https://cdn0.tnwcdn.com/wp-content/blogs.dir/1/files/2016/12/Keep-280x175.jpg 280w, https://cdn0.tnwcdn.com/wp-content/blogs.dir/1/files/2016/12/Keep-432x270.jpg 432w, https://cdn0.tnwcdn.com/wp-content/blogs.dir/1/files/2016/12/Keep-216x135.jpg 216w" sizes="(max-width: 640px) 100vw, 640px">

</div>

This may not be the best approach for everyone but I imagine it will get most the desired results without any javascript workaround.


You can use media queries for your purpose. It's easy as this:

.mycontainer {    
    background-image:url("img/image-big.jpg"); // big image   
}

@media(max-width: 768px){
   .mycontainer {
        background-image:url("img/image-sm.jpg"); // small image  
    }
}

And I think it works on every browser who support media queries ;)


Similar solution using <picture> element: Tutorial here

Tutorial's case:

I’m doubtful that if I use the same image for a smaller screen size, the primary subject of my image may become too small in size. I want to display a different image (more focused on the primary subject) in a different screen size, but I still want to display separate assets of the same image based on device-pixel ratio, and I want to customize height and width of the image based on viewport.

Example code:

<picture>

<source media="(max-width: 20em)" srcset="images/small/space-needle.jpg 1x,
images/small/space-needle-2x.jpg 2x, images/small/space-needle-hd.jpg 3x">

<source media="(max-width: 40em)" srcset="images/medium/space-needle.jpg 1x,
images/medium/space-needle-2x.jpg 2x, images/medium/space-needle-hd.jpg 3x">

<img src="space-needle.jpg" alt="Space Needle">

</picture>

Based on @Weston's answer, I've built a more general jQuery solution, you can basically just copy&paste the JS and CSS and focus on the HTML part ;)

TL;DR - fiddle: https://jsfiddle.net/dpaa7oz6/

CSS

...to ensure images will be hardly visible while loading

.srcSet{
  position: fixed;
  z-index: 0;
  z-index: -1;
  z-index: -100;
  /* you could probably also add visibility: hidden; */
}

JS / jQuery

This script will go through all images that have srcSet class and bind load event that takes currentSrc (or src if not supported) and puts it as a background-image CSS to the closest parent with bgFromSrcSet class.

That itself would not be enough! So it also puts an interval checker on window load event to test if the load events have been completed, if not, it triggers them. (img load event is very often trigger only on first-time load, on following loads, image source could be retrieved from cache, resulting in img load event NOT being fired!)

jQuery(function($){ //ON DOCUMENT READY
  var $window = $(window); //prepare window as jQuery object

  var $srcSets = $('.srcSet'); //get all images with srcSet clas
  $srcSets.each(function(){ //for each .srcSet do...
    var $currImg = $(this); //prepare current srcSet as jQuery object

    $currImg
      .load(function(){ //bind the load event
          var img = $currImg.get(0); //retrieve DOM element from $currImg

          //test currentSrc support, if not supported, use the old src
          var src = img.currentSrc ? img.currentSrc : img.src;

          //To the closest parent with bgFromSrcSet class,
          //set the final src as a background-image CSS
          $currImg.closest('.bgFromSrcSet').css('background-image', "url('"+src+"')");

          //remove processed image from the jQuery set
          //(to update $srcSets.length that is checked in the loadChecker)
          $srcSets = $srcSets.not($currImg);

          $currImg.remove(); //remove the <img ...> itself 
      })
    ;      

  });

  //window's load event is called even on following loads...
  $window.load(function(){    
    //prepare the checker
    var loadChecker = setInterval(function(){
        if( $srcSets.length > 0 ) //if there is still work to do...
            $srcSets.load(); //...do it!
        else
            clearInterval(loadChecker); //if there is nothing to do - stop the checker
    }, 150);  
  });

});

HTML

...could look like this:

<div class="bgFromSrcSet">
  <img class="srcSet"
       alt=""
       src="http://example.com/something.jpeg" 
       srcset="http://example.com/something.jpeg 5760w, http://example.com/something-300x200.jpeg 300w, http://example.com/something-768x512.jpeg 768w, http://example.com/something-1024x683.jpeg 1024w, http://example.com/something-1000x667.jpeg 1000w"
       sizes="(max-width: 2000px) 100vw, 2000px"
  >
  Something else...
</div>

Note: class bgFromSrcSet must not be set to the img itself! It can only be set to the elements in the img DOM parent tree.


If you are using Foundation framework (https://foundation.zurb.com/), you can use Interchange plugin for that:

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

https://foundation.zurb.com/sites/docs/interchange.html#use-with-background-images

참고URL : https://stackoverflow.com/questions/26801745/is-there-a-srcset-equivalent-for-css-background-image

반응형