Is there a srcset equivalent for css background image

HtmlCssBackground ImageSrcset

Html Problem Overview


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('what goes here?');
}

Html Solutions


Solution 1 - Html

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

Currently implemented in all major Browsers (Firefox, Chrome, Safari, Edge) with the -webkit- prefix. Safari only supports supports the x descriptors.

Solution 2 - Html

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:

.pseudo-background-img-container {
  position: relative;
  width:400px;
  height: 200px;
}
.pseudo-background-img {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

<div class="pseudo-background-img-container">

<img class="pseudo-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.

Solution 3 - Html

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.

Solution 4 - Html

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 ;)

Solution 5 - Html

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.

Solution 6 - Html

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>

Solution 7 - Html

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

Solution 8 - Html

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.

Solution 9 - Html

According to CSSTricks, image-set() should be used for this purpose as of 2021.

Here's the full snippet that it recommends using for support of all modern browser versions:

.hero {
  /* Fallback */
  background-image: url("platypus.png");

  /* Chrome/Edge/Opera/Samsung, Safari will fallback to this as well */
  background-image: -webkit-image-set(url("platypus.png") 1x, url("platypus-2x.png") 2x);

  /* Standard use */
  background-image: image-set("platypus.png" 1x, "platypus-2x.png" 2x);
}

Solution 10 - Html

I have used the Lazysizes plugin called bg-set for adding responsiveness to background images. It works similarly as srcset does and provides a set of multiple background images based on the device width.

<div class="lazyload" data-bgset="image-200.jpg 200w, image-300.jpg 300w, image-400.jpg 400w" data-sizes="auto">

The images in the data-bgset are the same, we are just providing the width specified image which the browser will be able to choose from.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMartin AlgestenView Question on Stackoverflow
Solution 1 - HtmlYoav WeissView Answer on Stackoverflow
Solution 2 - HtmlParksView Answer on Stackoverflow
Solution 3 - HtmlSRingView Answer on Stackoverflow
Solution 4 - HtmlgtamboreroView Answer on Stackoverflow
Solution 5 - HtmlWestonView Answer on Stackoverflow
Solution 6 - HtmlPiotr ŚcigałaView Answer on Stackoverflow
Solution 7 - HtmlMartti HyvönenView Answer on Stackoverflow
Solution 8 - Htmljave.webView Answer on Stackoverflow
Solution 9 - HtmlHashim AzizView Answer on Stackoverflow
Solution 10 - HtmlArchit RathiView Answer on Stackoverflow