I have an SVG with a number of rects that change fill colour as they move down the SVG (in a sort of gradient look). Users are able to choose a solid fill colour to 'theme' their experience. This colour replaces the 'gradient' color of the rects. I'm doing this using CSS variables.
However, I want to default back to the fill colour defined in the SVG if they don't choose a theme colour. In this case the CSS variable is set to ''
making it invalid. For other elements I'm using a default that the element falls back to. I can't do this with the SVG rects as they're all different. I tried removing the default but I believe this sets the fill to it's initial CSS value, which is transparent.
If I have the following rect:
<rect id="rect" fill="#000000" x="0" y="0" width="200" height="50" rx="6"></rect>
and the following CSS: rect { fill: var(--preview-primary); }
I'd expect it to be black when --preview-primary
is invalid, but it's transparent.
Is there a way I can do this? Thanks.
No, there is no way to fallback to the fill
attribute.
Having a valid fill
CSS rule will take precedence over the fill
attribute.
For CSSOM, var(--anything)
is always a valid rule. If ever the computation of the var()
function is invalid, then it will fallback to the default value. And the default value for fill
is black
:
#f {
fill: var(--foobar);
}
<svg>
<rect id="f" x="0" y="0" height="80" width="80" fill="green"/>
</svg>
So to workaround this situation, you have a few choices available:
""
.sel.onchange = e => {
document.documentElement.style
.setProperty('--selected-color', sel.value);
// toggle a class so we know we have to handle it
document.documentElement.classList
.toggle('user-selected-color', sel.value !== "");
};
.user-selected-color rect {
fill: var(--selected-color);
}
select{vertical-align:top}
<svg height="180" width="180">
<rect x="0" y="0" height="80" width="80" fill="green"/>
<rect x="90" y="0" height="80" width="80" fill="blue"/>
<rect x="0" y="90" height="80" width="80" fill="red"/>
<rect x="90" y="90" height="80" width="80" fill="black"/>
</svg>
<select id="sel">
<option value="">none</option>
<option>orange</option>
<option>pink</option>
<option>violet</option>
<option>aqua</option>
</select>
color
and then fallback to the CSS value currentColor
:sel.onchange = e => {
document.documentElement.style
.setProperty('--selected-color', sel.value);
};
rect {
fill: var(--selected-color, currentColor);
}
select{vertical-align:top}
<svg height="180" width="180">
<rect x="0" y="0" height="80" width="80" fill="green" style="color:green"/>
<rect x="90" y="0" height="80" width="80" fill="blue" style="color:blue"/>
<rect x="0" y="90" height="80" width="80" fill="red" style="color:red"/>
<rect x="90" y="90" height="80" width="80" fill="black" style="color:black"/>
</svg>
<select id="sel">
<option value="">none</option>
<option>orange</option>
<option>pink</option>
<option>violet</option>
<option>aqua</option>
</select>