CSS variables don't work with the url() function

CSS variables don't work with the url() function


2 min read

CSS custom properties (a.k.a CSS variables) have been a great addition to CSS. We can set or update a CSS variable in a single place and have that value available to other locations in our CSS code using the var() CSS function.

I recently came across a situation where I needed to update a background image using a CSS variable. Here is a snippet of the code that I first tried. It didn't work. ๐Ÿ˜ญ

:root {
    --bg-image: 'https://some-bg-image.jpg';

#box {
   /* This doesn't work */
   background-image: url(var(--bg-image));

Why didn't this work?

To begin to understand why this didn't work, we need to understand the url() CSS function specification. Below is an excerpt from the MDN web docs.

A URL, which is a relative or absolute address, or pointer, to the web resource to be included, or a data URL, optionally in single or double quotes. Quotes are required if the URL includes parentheses, whitespace, or quotes, unless these characters are escaped, or if the address includes control characters above 0x7e. Double quotes cannot occur inside double quotes and single quotes cannot occur inside single quotes unless escaped. <MDN> url()

This states that a URL of var(--bg-image) is not valid syntax as the parentheses should be escaped as var\(--bg-image\). However, escaping the parentheses would be useless as it would be invalid syntax for the var() CSS function which like most functions requires parentheses when called.

The reason why the parentheses must be escaped is related to a CSS parsing issue that treats url(https://some-image.jpg) differently to url('https://some-image.jpg') and url("https://some-image.jpg") . You can read more about it from this GitHub issue.

How can we use CSS variables with url() function?

The solution is reasonably straightforward. We need to move the url() function call to the CSS variable declaration as shown below. In this situation, we will get the same behaviour regardless of whether we use quotes or not. However, whatever is included within the url() function must have valid syntax as described above.

Try removing the quotes in the example below.