edisonmecaj
edisonmecaj

Reputation: 1142

Fallback background-image if default doesn't exist

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 a fallback to an alternative image if the default background doesn't exist?

body{
    background: url(bg.png);
    background-size: 100% 100%;
    width: 100vw;
    height: 100vh;
    margin: 0;
}

Upvotes: 60

Views: 57103

Answers (5)

Chris
Chris

Reputation: 59491

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 display the bg.png on top of the bg.jpg. If the png has any transparency, both images will be partially visible.

Check out the demo here. Test it by breaking any of the image urls'.

Upvotes: 21

DanyAlejandro
DanyAlejandro

Reputation: 1468

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.

Upvotes: 4

Aamir Afridi
Aamir Afridi

Reputation: 6411

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>

Upvotes: 1

Tuomas Hietanen
Tuomas Hietanen

Reputation: 5313

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

Upvotes: 0

user4994625
user4994625

Reputation:

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>

Upvotes: 104

Related Questions