If a CSS variable is invalid, it will default to using the SVG fill

In my SVG, there are several rectangles that change their fill color in a gradient effect as they move down the SVG. Users have the option to choose a solid fill color to customize their experience, which replaces the gradient color of the rectangles. I am accomplishing this using CSS variables.

However, I am facing an issue where I want the rectangles to default back to the original fill color defined in the SVG if no theme color is chosen by the user. In such cases, the CSS variable is set to '', making it invalid. Unlike other elements where I can set a default value for fallback, each rectangle in the SVG has a unique fill color. When I tried removing the default value, the fill reverted to its initial CSS value, which is transparent.

For example, if I have a rectangle with the code

<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 would expect the rectangle to be black when --preview-primary is invalid, but instead, it appears transparent.

I am looking for a solution to address this issue. Any help would be greatly appreciated. Thank you.

Answer №1

Unfortunately, there is no direct way to fallback to the fill attribute.

If a valid CSS rule for fill is present, it will always take priority over the fill attribute. For CSSOM, using var(--anything) will always be considered a valid rule. In case the calculation of the var() function fails, it will default back to the specified value. The default value for fill is set to black.

In order to tackle this issue, you have several options to choose from:

  • If altering the SVG is not an option, you can activate user-selected rules only when a non-empty value is provided:

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>

  • If possible, you can individually set each element's CSS color property and then fall back 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>

Answer №2

Update the SVG code by removing the fill style and adding a default "fallback" color in the CSS to handle cases where the variable is not 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>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Display the button on a separate row for smaller screens in Bootstrap 4, but ensure it remains in the same row for larger screens

I'm struggling with what seems like a simple task: My goal is to design a sticky bottom-bar (similar to a cookie notification) containing two lines of text and a button. I need the button to be aligned next to the text on desktop, but on mobile, it s ...

What unique capabilities does canvas offer that are not available with SVG?

Currently tackling a project that requires choosing between SVG and Canvas. After extensive research, it seems like SVG outperforms Canvas in many aspects. Is there anything that Canvas can do but SVG cannot? I'd love to hear your insights. ...

Update the CSS classes exclusively for the specified ID

Attempting to modify and override certain classes within the complex control (dxList) of DevExtreme has been successful thus far. .dx-loadpanel-content { transform: translate(0px, 0px) !important; margin: auto !important; left: 0px !important; ...

Transform three-dimensional models created with three.js into scalable vector graphics (SVG)

I am working on creating a unique tool that will enable designers to import 3D models of furniture parts created in 3ds Max and converted to JSON with Three.js. With this tool, designers can assemble furniture by moving these parts around. Once the assem ...

Tips on customizing the appearance of mat-card-title within a mat-card

Is there a way to truncate the title of a mat card when it overflows? I tried using the following CSS: overflow:hidden text-overflow:ellipsis white-space: nowrap However, the style is being overridden by the default mat-card style. I attempted to use mat ...

Unexpected quirks in Canvg conversion: Strange behavior observed while utilizing a fill URL

I am attempting to use the canvg javascript library to convert an svg to canvas. Within the original svg, there is a rectangle with a fill attribute that references a svg pattern. However, when I convert the svg to canvas using canvg: canvg(document.getE ...

Struggling to import SVG files in Gatsby's TypeScript project? Error message: "Element type is invalid: expected a string"?

Struggling to incorporate SVG files into my Gatsby TypeScript project, I've implemented the gatsby-plugin-react-svg plugin. The app is prompting an error message that reads: One unhandled runtime error found in your files. See the list below to fix it ...

What could be the reason for my ul hover effect not functioning as expected?

I'm struggling to create a menu where hovering over categories reveals another menu below it. I have created both the main menu and sub-menu, but I am unsure how to make the sub-menu appear on hover or apply any styling to it. I've tried various ...

Is there a way to position this Flex-Box Item beside the image?

Please refer to the image How do I rearrange this Flex-Box Item to be positioned next to the image? https://i.sstatic.net/eSy3w.png <div class="brif fb"> <div class="sml-con"><img class="sml-thumb" src="images/chosen/edwa ...

Utilizing Bootstrap to arrange table cells in a shifted manner

I'm new to utilizing bootstrap in web development. I've been exploring various examples of bootstrap templates that include tables, and I noticed that when I resize my browser window, the table adjusts accordingly. Now, I'm curious to know ...

Command field in Javascript

I've crafted an exquisite search box for my website, but I'm struggling to make it functional and display search results. Below are the Html and CSS files pertaining to this section of my site: .searchbox{ /*setting width of the form eleme ...

Does the entire window fade before the URL is loaded?

Is it feasible for me to create an effect where, upon a user clicking on a link, the entire window fades out (perhaps with a black div covering it), and then loads an external URL like 'google'? For example: User clicks 'Here', and th ...

Rotate the mat-select arrow when the dropdown opens (moving in both upward and downward directions)

Currently, I have a mat-select dropdown icon arrow that toggles facing up or down based on user clicks. However, after selecting an option and closing the dropdown, the arrow remains in the upward position unless further clicked and held. I have attempted ...

Show MaterialUI Dialog in fullscreen mode

I'm just starting out with React and Material-UI, and I'm trying to figure out how to print my current dialog. The issue I'm running into is that I can't seem to find a way to set the Dialog to full screen for printing while keeping it ...

Guide on aligning two boxes in the center with HTML, CSS, and Bootstrap

Is there a way to perfectly center two buttons or clickable boxes, creating a layout similar to the image shown below? https://i.sstatic.net/Va1z2.png This is what has been attempted so far: CSS file .container_1 .panel_1 { position: absolute; ...

Difficulties encountered with CSS transitions when using the background

I stumbled upon some interesting examples on Stack Overflow about the fade effect on link hover. Curious, I decided to try it out myself and created this JSFiddle. <div class="fade"/> .fade { -o-transition: 0.3s; -moz-transition: 0.3s; -khtml-tran ...

Is it feasible to have fixed headers adopt the width property?

Is there a way to align the widths of table elements while maintaining a fixed header row? If the 'fixed' property is disabled, the width spaces correctly but the header won't stay fixed and will scroll out of the container div. Enabling the ...

Conceal tab content by clicking outside of the tab or its contents

Here is an example of how Elementor tab works. When you click on a tab, the content section appears. I want to be able to close the content section by clicking on any other part of the page, except for the tabs and tab content themselves. This should not a ...

Bootstrap CSS: image is overlapping text inside a div

In my layout, I have four inner div containers arranged as follows: small picture - text - small picture - text. <div class="container"> <div class="col-md-12"> <div class="row"> <div class="col-sm-2"> <div c ...

Center the background image and adjust it vertically up or down as needed

I am experiencing an issue with a slider div that has a background image on it. The background image is too large, so it is currently centered. You can see the issue here: http://jsfiddle.net/s5qvY/ <div id="slider"></div><hr><hr>& ...