Reputation: 13620
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?');
}
Upvotes: 136
Views: 81024
Reputation: 2270
image-set
is the equivalent CSS feature. We should add equivalent srcset functionality (defining resources according to their dimensions) to the spec.
All major browsers released since May 4, 2023 support this without prefix. To support older browsers (mainly Chrome & Edge), you can add a variant with a -webkit-
prefix, see Can I use.
Upvotes: 109
Reputation: 6135
From 2021 onwards image-set()
should be used for this purpose, according to CSSTricks.
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(url("platypus.png") 1x, url("platypus-2x.png") 2x);
}
Upvotes: 6
Reputation: 11
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.
Upvotes: 1
Reputation: 648
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.
Upvotes: 35
Reputation: 3212
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 ;)
Upvotes: 12
Reputation: 31
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
Upvotes: 3
Reputation: 15042
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 ;)
...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; */
}
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);
});
});
...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.
Upvotes: 1
Reputation: 1992
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.
Upvotes: 11
Reputation: 49
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>
Upvotes: 4
Reputation: 694
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.
Upvotes: 27