Reputation: 1327
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.
Upvotes: 1
Views: 2965
Reputation: 136618
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>
Upvotes: 3
Reputation: 114991
Remove the fill
style from the SVG and place a default "fallback" color in the CSS for when the variable has not been defined.
rect {
fill: var(--preview-primary, 000);
}
rect {
fill: var(--preview-primary, black);
}
.red {
--preview-primary: red;
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect x="10" y="10" height="100" width="100"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect class="red" x="10" y="10" height="100" width="100"/>
</svg>
Upvotes: 1