Playing with SVGs
Gradient SVGs, customising SVGs, icon sets, and more.
SVG is one of my favourite formats for images in apps.
Different background colours on the same page? Works well since we have icon sets now.
But what about site logos? Custom icons downloaded from Figma? Do we make the user download multiple files?
Instead, identify the hard-coded values in the SVG. If you read the SVG code, you’ll notice that the colour comes from a block of linear gradient code. Specifically, the stop-color attribute. This may vary for other SVGs.
How do we make one SVG do it? For HTML, you’ll need to update the fill using JS.
For React:
- Save the SVG as a component
- Replace “g1” with a UUID. This is because we are referencing a DOM element in the fill by its ID, and it’ll take the value of the first occurrence. If different instances need to have different colours, they require a unique ID. (Don’t miss the # in the url() access)
- Assign CSS variables to the stop-color attribute. I prefer adding a default fallback value to the variables for safety.
And that is it. You can now use a single SVG component for multiple variations.
https://codesandbox.io/p/devbox/svg-hardcoded-forked-dkzp45?workspaceId=ws_LcM1M7Xx1cHsFgbnCXZfij
What about icon sets like Hugeicons, where gradients are only allowed for pro users?
Define a gradient inside a separate SVG.
<svg className="absolute inline h-0 w-0" viewBox={`0 0 24 24`}>
<defs>
<linearGradient
id={id}
x1=0 y1=0 x2=0 y2="100%" -> direction to bottom
className={className}
gradientUnits="userSpaceOnUse"
>
<stop offset="0%" style={{ stopColor: 'var(--gradient-from)' }} />
<stop offset="100%" style={{ stopColor: 'var(--gradient-to)' }} />
</linearGradient>
</defs>
</svg>
Use it like this:
const id='the_uniq_id'
<span>
<SvgDefinedAbove id={id}>
<IconFromIconset style={{
stroke: `url(#${id})!important`,
}}>
</span>
Notes:
- The defined gradient needs to be position absolute with no width or height so that it doesn’t take up space on your page.
- If this gradient is brand color, add it to the top of the body tag to reduce overhead. No span wrapper needed in this case, just use the icon with the adjusted stroke value.
- I didn’t forget the overflow mentioned in the image 1 :D. To avoid overflows, we can use a similar approach on the width and height attributes. Don’t touch the viewbox. That’s the internal SVG guideline.
- I have tested this approach on size, stroke widths, fill, and filter attributes. Let me know if you find something intersting or have any feedback :D ¯