DEV Community

The SVG Color Cascade Nobody Explains (fill, stroke, currentColor, and why img src breaks it)

Change an SVG's color by editing fill and stroke , either as attributes or through CSS. Simple in theory. In practice there are three places a color can be declared in the same file, they follow the normal CSS cascade, and if you don't know that, "I changed the fill and nothing happened" turns into a twenty-minute debugging session. Here's the part of SVG color handling that usually doesn't get spelled out. fill and stroke are separate properties Every shape has an inside (fill ) and an outline (stroke ), set independently: Unset fill defaults to black. Unset stroke defaults to none. If an icon is pure fill with no stroke at all (most converted icon-font SVGs are), editing stroke-width is never going to do anything visible, and that's usually the first dead end people hit. The cascade is the actual bug source A color can come from three places, and they don't have equal priority: - A presentation attribute: - An inline style attribute: - A block or external stylesheet:path { fill: red; } Normal CSS specificity applies: style attribute beats stylesheet, stylesheet beats presentation attribute. Edit the fill="red" attribute directly, and if a block elsewhere in the same file also targets that path, your edit is overridden and nothing changes on screen. No error, no warning, it just loses. If a color edit isn't sticking, grep the file for .icon { color: #ff0000; } ... Change .icon 's color and the SVG updates with zero edits to the SVG itself. It's why most icon libraries ship currentColor by default: one file, infinite colors, controlled entirely by CSS at the call site. If you're publishing your own icon set, this is the property to reach for instead of hardcoding hex values into every export. The one that actually surprises people: The moment an SVG is referenced this way, the browser treats it as an opaque raster-like image. There's no DOM access, no CSS targeting fill , and currentColor resolves to nothing because there's no inheritance path across the document boundary. filter: invert() gets you a rough approximation at best, not a real color swap. Three actual fixes, in order of how much they cost you: Inline the SVG in the HTML. Once the markup is literally on the page, it's a normal element and every CSS trick above works. Use it as a mask instead of a source: .icon { background-color: currentColor; mask: url(icon.svg) center / contain no-repeat; -webkit-mask: url(icon.svg) center / contain no-repeat; } The shape becomes a stencil, the visible color comes from background-color , and you never touch the SVG file. Use a sprite with , setting fill on the element, assuming the source paths don't already have a hardcoded fill fighting you (see the cascade section above, same rule applies here too). Multi-path SVGs need more than one edit A two-tone logo is rarely one shape. It's usually four or five elements, each carrying its own fill . Changing one and expecting the whole icon to shift is the second-most common gotcha after the cascade issue. Either: - put fill="currentColor" on every path that should track the parent's text color, or - set fill on a wrapping , keeping in mind any child path with its own explicitfill still wins over the group value Past two or three paths this gets tedious fast when you're doing it by hand in a text editor, hunting fill= occurrences one at a time with no visual feedback on which shape you're actually touching. CSS custom properties work fine inside SVG :root { --icon-color: #3366ff; } .body-fill { fill: var(--icon-color); } One variable, referenced by every shape that shares it. If the SVG is inlined (not loaded via img ), the page's own CSS can override that variable directly, giving a multi-part graphic a single external color hook instead of duplicated hex values scattered across paths. Doing this visually SVG Lab is a free browser SVG editor I built: visual fill and stroke editing plus path and node editing (bezier control points, anchor manipulation), no install. It doesn't replace knowing how the cascade works, it just means you click the shape you want to change instead of hunting through markup for it. Top comments (0)

Comments

No comments yet. Start the discussion.