grunt-svgstore
grunt-svgstore copied to clipboard
Cross-icon gradient use
I'm having an issue with sharing gradients across icons. This circle will work:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#009fe3" />
<stop offset="100%" stop-color="#662483" />
</linearGradient>
<circle cx="50" cy="50" r="75" fill="url(#grad1)"/>
</svg>
But then I can't reference that same gradient later, eg:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<rect width="75" height="75" fill="url(#grad1)" />
</svg>
It seems to be because of the way SVG store handles the ids. It prepends the file hash on to the beginning of the ids to make it unique (which it rightly should) but this change doesn't seem to permeate through the rest of the file. so you end up with a sprite like this:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" class="hide">
<defs>
<linearGradient id="[hash]grad1" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#009fe3"/>
<stop offset="100%" stop-color="#662483"/>
</linearGradient>
</defs>
<symbol viewBox="0 0 100 100" id="icon__circle">
<title>circle</title>
<circle cx="50" cy="50" r="75" fill="url(#[hash]grad1)" />
</symbol>
<symbol viewBox="0 0 100 100" id="icon__rectangle">
<title>rectangle</title>
<rect width="75" height="75" fill="url(#grad1)" />
</symbol>
</svg>
Everything would work fine if the reference to the gradient in the second (rectangle) icon was updated to use the hashed id. Alternatively, if there was a way to preserve the ID that would be even better. It would allow you to write the following CSS:
.icon__grad-1{
fill: url(#grad1);
}
Obviously I would use a more specific ID in production code, but you get the idea.
Pre-defining the defs could be a good way around this too. If I could define the following in a separate file (without the ids being modified), that would be pretty nice:
<defs>
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#009fe3"/>
<stop offset="100%" stop-color="#662483"/>
</linearGradient>
</defs>
The philosophy of grunt-svgstore is to take a folder of existing (valid and complete) svg icons and concatenate them to a "svgsprite". I don't like the idea of breaking that because it would introduce much more complexity to this task.
But I like your idea with using a separate svg that gets merged into the resulting svg. If you have time implementing it I am open for a PR (I don't have time to do that myself)
That's a good point, no use breaking the philosophy for one edge-case. Having the gradient as an extra SVG should still adhere to that philosophy though so I'll look at making a PR soon.