I want to set an image as a background, however the image name might be either bg.png
or bg.jpg
.
Is there any non-javascript way to create
You can use multiple backgrounds if there is no transparency involved and they occupy all available space or have the same size:
div{
background-image: url('http://placehold.it/1000x1000'), url('http://placehold.it/500x500');
background-repeat:no-repeat;
background-size: 100%;
height:200px;
width:200px;
}
<div></div>
If the first doesn't exit, the second will be displayed.
div{
background-image: url('http://placehol/1000x1000'), url('http://placehold.it/500x500');
background-repeat:no-repeat;
background-size: 100%;
height:200px;
width:200px;
}
<div></div>
You can have background image with css and use the same image URL in a hidden image tag and onError, change the image URL and make it show it
<div
style={{ backgroundImage: `url(${imageSrc})` }}
>
<img
style={{ display: "none" }}
src={imageSrc}
onError={(e) => {
e.currentTarget.src = brokenImageFallbackUrl;
e.currentTarget.style.display = "block";
// or keep this image hidden and set the backgroundImage of the parent div
}}
/>
</div>
I wanted to have a solution that doesn't load the images twice. For example CDN with a fallback is not very good if it always loads the original images also. So I ended up writing a Javascript to manipulate the loaded CSS DOM.
var cdn = "https://mycdn.net/"; // Original location or thing to find
var localImageToCssPath = "../"; // Replacement, Css are in /css/ folder.
function replaceStyleRule(allRules){
var rulesCount = allRules.length;
for (var i=0; i < rulesCount; i++)
{
if(allRules[i].style !== undefined && allRules[i].style !== null &&
allRules[i].style.backgroundImage !== undefined &&
allRules[i].style.backgroundImage !== null &&
allRules[i].style.backgroundImage !== "" &&
allRules[i].style.backgroundImage !== "none" &&
allRules[i].style.backgroundImage.indexOf(cdn) > -1
)
{
var tmp = allRules[i].style.backgroundImage.replace(cdn, localImageToCssPath);
//console.log(tmp);
allRules[i].style.backgroundImage = tmp;
}
if(allRules[i].cssRules !== undefined && allRules[i].cssRules !== null){
replaceStyleRule(allRules[i].cssRules);
}
}
}
function fixBgImages(){
var allSheets = document.styleSheets;
if(allSheets===undefined || allSheets===null){
return;
}
var sheetsCount = allSheets.length;
for (var j=0; j < sheetsCount; j++)
{
var allRules = null;
try{
allRules = allSheets[j].cssRules;
} catch(e){
// Access can be denied
}
if(allRules!==undefined && allRules!==null){
replaceStyleRule(allRules);
}
}
}
// use fixBgImages() in e.g. onError
Although this solution does involve JS, it will download the first image using CSS, and will only use JS to download the fallback image if the main image failed to download.
First, set the main image with CSS as usual, for example:
.myImage {
background-image = "main-image.png";
}
And add the following JS that will only act if loading the main image fails (otherwise, fallback image will never be downloaded).
var img = document.createElement("img");
img.onerror = function() {
var style = document.createElement('style');
style.innerHTML = '.myImage { background-image = url("http://fallback_image.png"); }';
document.head.appendChild(style);
}
img.src = "main_image.png";
Note that you can add multiple rules to the CSS block added with javascript, for example if you need to do this with multiple elements.
To specify multiple possible backgrounds, you could do:
background-color: green;
background-image: url('bg.png'), url('bg.jpg');
This will set the background to bg.png
if it exists. If it doesn't exist, it will be set to bg.jpg
. If none of those images exist, the background will be set to the static green
color.
Note that it will prioritize whatever image is specified first. So if both images exist, it will choose the bg.png
over the bg.jpg
.
Check out the demo here. Test it by breaking any of the image urls'.