Using CSS variables (custom properties) as content property value
CSS custom properties can be used to set values on any other CSS property. Combining it with content
property to set some content in pseudo-element works as you would expect it. As long as content value is of type String that is (more on that follows).
// This works
:root {
--copy: 'hello world';
}
body::before {
content: var(--copy);
}
But what if you want to set property value using JavaScript?
document.body.style.setProperty('--copy', 'hello');
// This does not work :(
body::before {
content: var(--copy);
}
I was puzzled until landing on this SO question and seeing this answer.
Turns out, if you use setProperty
to set CSS custom property, result will look something like this:
<body style="--copy:hello;">
Without quotation marks, the parser is unable to determine that value is a string so it won’t render. And simply passing an actual string to setProperty
is not enough. What’s worse, using a second value in var
as fallback also won’t work since --copy
is defined (just with an invalid value).
// This still does not work :(
body::before {
content: var(--copy, 'fallback');
}
Instead, you have to do it like this:
document.body.style.setProperty('--copy', `'hello'`);
Notice backticks around the string. This way, quotation marks make their way into an inline style declaration and everything works. Using "'" + 'hello' + '"'
is another valid approach but I find template literals cleaner.
¶ Note about numbers
If the value custom property holds is of type String is will just work. But for numbers, we need to combine it with CSS counter like so:
:root {
--x: 123;
}
div:before {
counter-reset: variable var(--x);
content: counter(variable);
}
Great trick from that same StackOverflow topic.