Use image-set() while supporting Firefox with dynamically loaded background images
Tags: css, imageset, firefox
Published: 2020-11-27 14:20:14

You don't need to do anything special anymore 🥳 There is full support for `image-set` in Firefox since version 89 (released Jun 2021). Go browser standards!

Here's a demo. You'll see it works in Firefox:

{% embed https://stackblitz.com/edit/react-ts-fwysuw?file=App.tsx,style.css %}

The below is an INVALID, old article about a problem that once existed when Firefox didn't support `image-set`. Only kept for questionable archival purposes. I will probably unpublish this article later.

---

```html
<div style="
/* fallback */
background-image: url('fallback-img.jpg');
/* responsive */
background-image: -webkit-image-set(url( ... responsive image set ...));">
```

**Solution: put those rules in a `<style>` tag instead** to support fallbacks.

Note: this blog post was a learning from a project at [Columbia Road](https://www.columbiaroad.com/), an updated version can be found on the company site: [Tech logs: Use image-set() while supporting Firefox with dynamically loaded background images](https://www.columbiaroad.com/blog/use-image-set-while-supporting-firefox-with-dynamically-loaded-background-images)

---

Modern browsers widely support the HTML `srcset` attribute that enables responsive images ([MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-srcset), [CanIUse](https://caniuse.com/srcset)). But for its CSS `background-image` equivalent `image-set()` (accessible through `-webkit-image-set()`), there is no support for *IE11*, *Firefox*, *Firefox for Android* and *Opera Mini* ([MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/image-set()), [CanIUse](https://caniuse.com/css-image-set)). (I'm ignoring IE11 overall).

![Screen Shot 2020-11-20 at 10.34.32](https://dev-to-uploads.s3.amazonaws.com/i/9o9rp9w86idkp9428csa.png)
 
<figcaption>Support of major browsers for image-set() as of November 20, 2020. Source: <a href="https://caniuse.com/css-image-set" target="_blank">CanIUse</a></figcaption>

Of course you'll want to have a non-responsive fallback image for these non-supporting browsers. Well, that's not as obvious as it sounds.

# Problem: using `style=""` doesn't work

You might be tempted to try the following CSS with a fallback `url()` expression, that gets overwritten with the `-webkit-image-set()` expression whenever available.

```html
<div style="
/* provide a fallback for Firefox */
background-image: url('../img/image-2x.jpg');
/* override with a responsive image */
background-image: -webkit-image-set(url('../img/image-1x.jpg') 1x, url('../img/image-2x.jpg') 2x);
">
```

Unfortunately, if you add the above code to a `style=""` attribute (as you would often do when you generate responsive background images somewhere), Firefox 84 will complain with this error in the console:

```
⚠️ Error in parsing value for 'background-image'. Declaration dropped.
```
 

How sad. It dropped the whole style attribute value because it could't load the `-webkit-image-set()`. As a result, it does also not display the fallback.

# Solution: use a `<style>` tag

The following code works however:

```html
<head>
	<style>
		.my-image-id {
			/* provide a fallback for Firefox */
			background-image: url('../img/image-2x.jpg');
			/* override with a responsive image */
			background-image: -webkit-image-set(url('../img/image-1x.jpg') 1x, url('../img/image-2x.jpg') 2x);
		}
	</style>
</head>
<body>
	<!-- this div should have an image background on it -->
	<div class="my-image-id background-box"><div/>
</body>
```

It seems that a style tag *can* still be parsed, even though one rule in it is not supported by the browser.

A few things to consider here.

## You need a unique class name for each image.

The reason you came here in the first place might have been that you wanted to use the `style=""` attribute, because you were dynamically adding background images to a template using client-side/server-side image data.

In that use case, you now you need to perform a few intermediate steps:

1. Generate a unique class name for the background image set
2. Add that class to the desired `<div>` (or other element)
3. Add a CSS rule for that class to a `<style>` tag somewhere. This could be a new tag in the `<head>` OR `<body>`. It should contain the fallback & responsive background-image URLs for that specific images. 

For step 1, you could use a GUID generator. In my project however, I used [a JS function](https://codepen.io/th0rgall/pen/abmbQYa?editors=0001) to generate valid class names from an alphanumeric image ID string that I got from an API.

## Tricky to add style rules to the `<head>`?<br>You *could* add them to the `<body>` too!

If you were previously trying to add the styles to a style tag, it might be tricky to add styles to a `<head>`, for example, when coding in a restricted server-side template where you can't access the `<head>`

One solution: it's actually possible to add `<style>` tags to the `<body>` as well. This is [not a good practice since it's non-standard](https://stackoverflow.com/questions/2830296/using-style-tags-in-the-body-with-other-html). But it seems to work in most browsers. I tested this in BrowserStack, and so far only UC Browser on Android seemed to have problems with this technique. Here's an adaptation of the previous example with body style tags:

```html
<!-- this div should have an image background on it -->
<div class="my-image-id background-box"><div/>
<style>
	.my-image-id {
		/* provide a fallback for Firefox */
		background-image: url('../img/image-2x.jpg');
		/* override with a responsive image */
		background-image: -webkit-image-set(url('../img/image-1x.jpg') 1x, url('../img/image-2x.jpg') 2x);
	}
</style>
```

Hope this helped! Feel free to leave a comment if anything is not clear.