I use two background-image declarations like this to get a fallback:
background-image: url(https://via.placeholder.com/300x150.png?text=regular);
background-image: -webkit-image-set(
url(https://via.placeholder.com/300x150.png?text=1x) 1x,
url(https://via.placeholder.com/600x300.png?text=2x) 2x
);
JS bin: https://jsbin.com/jadoharoyi/edit?html,css,output
The idea is for e.g. Firefox to show the "regular" bg because it doesn't support -webkit-image-set, and for e.g. Chrome to show the "1x" or "2x" bg (depending on resolution) because it does support -webkit-image-set.
So far so good.
But if I try to provide one or more of the image URLs via CSS variables (for convoluted reasons), it falls down:
--image-1x: url(https://via.placeholder.com/300x150.png?text=1x);
background-image: url(https://via.placeholder.com/300x150.png?text=regular);
background-image: -webkit-image-set(
var(--image-1x) 1x,
url(https://via.placeholder.com/600x300.png?text=2x) 2x
);
JS bin: https://jsbin.com/vojiboqije/1/edit?html,css,output
Now, Firefox (85.0.2 on macOS Big Sur 11.1) doesn't show a bg image at all. As far as I can tell, Firefox is suddenly happy to try to use the second background-image declaration, which it doesn't support.
But it works fine in Chrome (88.0.4324.146).
I don't understand why. Any ideas? Is this a bug? Or a misunderstanding on my part?
This how CSS variables are meant to work. When using CSS variables the browser can only evalute the value at run-time so the value will be considered as valid (or lets say in a standby mode) until we evalute the variable and if the browser find the whole value invalid, it will fallback to initial or inherit:
A declaration can be invalid at computed-value time if it contains a var() that references a custom property with its initial value, as explained above, or if it uses a valid custom property, but the property value, after substituting its var() functions, is invalid. When this happens, the computed value of the property is either the property’s inherited value or its initial value depending on whether the property is inherited or not, respectively, as if the property’s value had been specified as the unset keyword. ref
A more explicit example with a clearly non valid value:
html {
background:linear-gradient(red,blue); /* this will be used */
background:strange-gradient(red,blue); /* this is a joke */
min-height:100%;
}
And when using CSS variable, the second one will be used unfortunately making your first instruction useless.
html {
--c:red;
background:linear-gradient(red,blue); /* this will be ignored */
background:strange-gradient(var(--c),blue); /* the joke is being used ..*/
min-height:100%;
}
This behavior is somehow logical since by changing a variable we can make a value valid (if it was previously invalid) or invalid (if it was previously valid) so the browser should consider it.
For your particular case you can consider pseudo element trick:
.my-div {
width: 300px;
height: 150px;
background-color: red;
position:relative;
z-index:0;
--image-1x: url(https://via.placeholder.com/300x150.png?text=1x);
background-image: url(https://via.placeholder.com/300x150.png?text=regular);
}
/* the pseudo element will cover the main background if it's valid */
.my-div::before {
content:"";
position:absolute;
z-index:-1;
top:0;
left:0;
right:0;
bottom:0;
background-image: -webkit-image-set(
var(--image-1x) 1x,
url(https://via.placeholder.com/600x300.png?text=2x) 2x
);
}
<div class="my-div">
</div>