SVG Style application inconsistent between light/dark mode when overriding color

I am trying to see if there is a way to force currentColor for an iconset.
From what I could read, when applying multiple css instruction, when they are targetting the same attributes, the last declaration supersedes the previous one.

So here's what I ended up doing:

  • Creating an iconset
  • Declaring two styles (id="dark" and id="light")
  • Within these styles:
    • Redefine the color variable (e.g. svg {color: #61d0ff;})
    • While I was at it, I also created a style for duotone icons (e.g. .fill-duotone { fill: #61d0ff; opacity: 0.4; }) with the objective to replace attributes opacity="0.2" by class=fill-duotone.
    • Colors are defined with different values in dark and light styles.

Here's what the XML looks like:

<?xml version="1.0" encoding="utf-8"?>
<iconset name="test-duotone">
	<display_name>test-duotone</display_name>
	<set size="svg">
		<style id="dark">
			svg {
				color: #61d0ff;
			}
			.fill-duotone {
				fill: #61d0ff;   /* Équivalent à l'attribut fill */
				opacity: 0.4;    /* Vous pouvez aussi gérer l'opacité ici si vous le souhaitez */
			}
		</style>
		<style id="light">
			svg {
				color: #d17315;
			}
			.fill-duotone {
				fill: #d17315;   /* Équivalent à l'attribut fill */
				opacity: 0.4;    /* Vous pouvez aussi gérer l'opacité ici si vous le souhaitez */
			}
		</style>
		<icon name="acorn-duotone">
			<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
				<rect width="256" height="256" fill="none"/>
				<path d="M216,112v16c0,53-88,88-88,112,0-24-88-59-88-112V112Z" class="fill-duotone"/>
				<path d="M216,112v16c0,53-88,88-88,112,0-24-88-59-88-112V112" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
				<path d="M80,56h96a48,48,0,0,1,48,48v0a8,8,0,0,1-8,8H40a8,8,0,0,1-8-8v0A48,48,0,0,1,80,56Z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
				<path d="M128,56V48a32,32,0,0,1,32-32" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
			</svg>
		</icon>
		<icon name="address-book-duotone">
			<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
				<rect width="256" height="256" fill="none"/>
				<path d="M208,32H64a8,8,0,0,0-8,8V216a8,8,0,0,0,8,8H208a8,8,0,0,0,8-8V40A8,8,0,0,0,208,32ZM136,144a32,32,0,1,1,32-32A32,32,0,0,1,136,144Z" class="fill-duotone"/>
				<circle cx="136" cy="112" r="32" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
				<line x1="32" y1="72" x2="56" y2="72" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
				<line x1="32" y1="128" x2="56" y2="128" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
				<line x1="32" y1="184" x2="56" y2="184" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
				<path d="M88,168a60,60,0,0,1,96,0" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
				<rect x="40" y="48" width="192" height="160" rx="8" transform="translate(264 -8) rotate(90)" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
			</svg>
		</icon>
		<icon name="address-book-tabs-duotone">
			<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
				<rect width="256" height="256" fill="none"/>
				<path d="M48,40a8,8,0,0,0-8,8V208a8,8,0,0,0,8,8H184V40Zm64,104a24,24,0,1,1,24-24A24,24,0,0,1,112,144Z" class="fill-duotone"/>
				<line x1="184" y1="160" x2="216" y2="160" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
				<line x1="184" y1="96" x2="216" y2="96" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
				<rect x="40" y="40" width="176" height="176" rx="8" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
				<circle cx="112" cy="120" r="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
				<path d="M80,168c3.55-13.8,17.09-24,32-24s28.46,10.19,32,24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
				<line x1="184" y1="40" x2="184" y2="216" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
			</svg>
		</icon>
		<icon name="air-traffic-control-duotone">
			<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
				<rect width="256" height="256" fill="none"/>
				<path d="M66.19,160a8,8,0,0,1-7.52-5.27l-26.18-72A8,8,0,0,1,40,72H216a8,8,0,0,1,7.52,10.73l-26.18,72a8,8,0,0,1-7.52,5.27Z" class="fill-duotone"/>
				<line x1="128" y1="72" x2="128" y2="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
				<path d="M104,24h48" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
				<polyline points="168 72 152 160 152 232" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
				<polyline points="88 72 104 160 104 232" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
				<path d="M66.19,160a8,8,0,0,1-7.52-5.27l-26.18-72A8,8,0,0,1,40,72H216a8,8,0,0,1,7.52,10.73l-26.18,72a8,8,0,0,1-7.52,5.27Z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
			</svg>
		</icon>
		<icon name="airplane-duotone">
			<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
				<rect width="256" height="256" fill="none"/>
				<path d="M152,96l80,40v32l-80-16v32l16,16v32l-40-16L88,232V200l16-16V152L24,168V136l80-40V48a24,24,0,0,1,48,0Z" class="fill-duotone"/>
				<path d="M152,96l80,40v32l-80-16v32l16,16v32l-40-16L88,232V200l16-16V152L24,168V136l80-40V48a24,24,0,0,1,48,0Z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
			</svg>
		</icon>
	</set>
</iconset>

And the associated .dis file: test-duotone.dis (1.3 KB)

Dark mode works almost as expected (the fill part is not exactly as I expected when opacity remains low).
But in light mode, color is not replaced: everything is black.

Dark mode:
image

Light mode:
image

When I try and create these icons in "standalone mode" (e.g. integrating the styles inside the svg node) and save them as single svgs, external viewers render what I was expecting:

But even pasting that same code into the button SVG editor does not render the same.

Is this a limitation coming from mixing the way styles are applied with Opus light/dark mode?
Or is there anything wrong in these results?
Would you see another way to achieve my goal (e.g. replacing currentColor with something defined at iconset level, without having to change every instance of currentColor + being able to apply some styles at top level).

Initial test done with 13.23.7
Seems to be the same with 13.23.9

currentColor doesn't come from styles, it explicitly comes from outside the SVG. In Opus it's the text/toolbar label color.

I think you probably don't want to be using currentColor at all but should just use styles for this., e.g. take the stroke attributes out of the SVG and put them into the dark/light styles instead.

Thanks for your answer Jon.
I realize that my post was unclear due to me trying to recreate the process leading me to the unexpected result.
I'll try and make it clearer and explain it in a different way.

As you understood, my goal is to define what currentColor will be. My understanding is that it uses the value of the color variable that can either be defined:

  • Out of the svg scope (CSS in a browser for instance)
  • Or inside the svg using a style that sets its value (svg {color: #61d0ff;})

Step1: So I altered an existing svg to test that:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
	<style>
		svg {
			color: #61d0ff;
		}
	</style>
	<rect width="256" height="256" fill="none"/>
	<path d="M216,112v16c0,53-88,88-88,112,0-24-88-59-88-112V112Z" opacity="0.2"/>
	<path d="M216,112v16c0,53-88,88-88,112,0-24-88-59-88-112V112" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
	<path d="M80,56h96a48,48,0,0,1,48,48v0a8,8,0,0,1-8,8H40a8,8,0,0,1-8-8v0A48,48,0,0,1,80,56Z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
	<path d="M128,56V48a32,32,0,0,1,32-32" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
</svg>

That actually works fine: Opus preview pane, button icon editor, Opus iconset (shows OK in Prefs and on button), external apps (Illustrator, Inkscape, Quicklook).
svg zipped (can not upload svg): test_redefined_color.zip (530 Bytes)
Iconset: set_color_inside_svg.dis (645 Bytes)

Step 2: I tried to take it a step further.
Since Opus seems to apply what's defined in the style node defined by the id attribute value (dark/light), I tried to insert two styles with ids and define that color with different values.
As a side note, I also tried to define a fill-duotone class to deal with paths using the opacity attribute, expecting Directory Opus will put in the context whatever is in the appropriate style.

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
	<style id="dark">
		svg {
			color: #61d0ff;
		}
		.fill-duotone {
			fill: #61d0ff;   /* Équivalent à l'attribut fill */
			opacity: 0.4;    /* Vous pouvez aussi gérer l'opacité ici si vous le souhaitez */
		}
	</style>
	<style id="light">
		svg {
			color: #d17315;
		}
		.fill-duotone {
			fill: #d17315;   /* Équivalent à l'attribut fill */
			opacity: 0.4;    /* Vous pouvez aussi gérer l'opacité ici si vous le souhaitez */
		}
	</style>
	<rect width="256" height="256" fill="none"/>
	<path d="M216,112v16c0,53-88,88-88,112,0-24-88-59-88-112V112Z" class="fill-duotone"/>
	<path d="M216,112v16c0,53-88,88-88,112,0-24-88-59-88-112V112" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
	<path d="M80,56h96a48,48,0,0,1,48,48v0a8,8,0,0,1-8,8H40a8,8,0,0,1-8-8v0A48,48,0,0,1,80,56Z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
	<path d="M128,56V48a32,32,0,0,1,32-32" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
</svg>

As a result:

  • external apps (Inkscape, Illustrator, Quicklook): Since they are not aware of the id attribute, they just use whatever last definition they find in the svg file (i.e. "light" style definition here).
  • Preview pane / Button / Icon set: gets confused. The class (fill-duotone) gets applied correctly (taking into account Opus light/dark mode), but the color does not get applied anymore. In dark mode, strokes are white, and in light mode, they are black.

For repro purposes:
SVG File zipped: test_multi_style.zip (661 Bytes)
Iconset:
set_style_inside_svg.dis (646 Bytes)
set_style_outside_svg.dis (694 Bytes)

I also put the second iconset where these syles are defined outside of the SVG scope since it's the ultimate goal.

I can understand that Opus would need to tweak context in order to apply the proper styles and colors, so maybe a way to achieve that would be to be able to redefine the color/currentColor value within the dark/light style in an Opus specific way ....

My suggestion was to stop relying on currentColor and style the stroke attribute directly, e.g.

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
	<style id="dark">
		svg {
			stroke: #61d0ff;
		}
		.fill-duotone {
			fill: #61d0ff;   /* Équivalent à l'attribut fill */
			opacity: 0.4;    /* Vous pouvez aussi gérer l'opacité ici si vous le souhaitez */
		}
	</style>
	<style id="light">
		svg {
			stroke: #d17315;
		}
		.fill-duotone {
			fill: #d17315;   /* Équivalent à l'attribut fill */
			opacity: 0.4;    /* Vous pouvez aussi gérer l'opacité ici si vous le souhaitez */
		}
	</style>
	<rect width="256" height="256" fill="none"/>
	<path d="M216,112v16c0,53-88,88-88,112,0-24-88-59-88-112V112Z" class="fill-duotone"/>
	<path d="M216,112v16c0,53-88,88-88,112,0-24-88-59-88-112V112" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
	<path d="M80,56h96a48,48,0,0,1,48,48v0a8,8,0,0,1-8,8H40a8,8,0,0,1-8-8v0A48,48,0,0,1,80,56Z" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
	<path d="M128,56V48a32,32,0,0,1,32-32" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
</svg>

You could also make a class for it like you have with the filled shape, e.g.

	<style id="dark">
		.stroke-duotone {
			stroke: #61d0ff;
			stroke-linecap: round;
			stroke-linejoin: round;
			stroke-width: 16;
		}
		.fill-duotone {
			fill: #61d0ff;   /* Équivalent à l'attribut fill */
			opacity: 0.4;    /* Vous pouvez aussi gérer l'opacité ici si vous le souhaitez */
		}
	</style>

Then you wouldn't need to keep repeating all the stroke attributes on every path.

Thanks Jon.
I'll try and work in that direction.