One SVG to rule them all
Table of Contents
Introduction
When I wanted to reuse my SVGs for different colour themes1, I didn't want to manually create and maintain each variant. Tedious and error prone.
In this article series, I describe how a single source of truth can be used to generate production-ready images, in various colours and file formats.
That's where XSLT comes in.
XSLT?
XSLT is a language to transform XML. The output format can be XML, HTML or text.
Since SVG images are XML, XSLT can be used to transform them.
Source image
This image will be used in the examples. A simple grey disc on a transparent background.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-50 -50 100 100"> <!-- a wild circle appears --> <circle r="40" fill="grey"/> </svg>
It looks like this:
The transform script
As mentioned, XSLT can be used to transform XML. This can be done not only with simple attributes, but also with elements. Creating, modifying, and (re)moving, it's all possible.
The following script sets a value to the fill
attributes of all elements in a SVG. For more fine-grained control, you can modify the so-called selectors (think CSS selectors, but for XML). But this is a good starting point.
<?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:svg="http://www.w3.org/2000/svg" exclude-result-prefixes="svg"> <xsl:output method="xml" indent="yes" encoding="UTF-8" omit-xml-declaration="yes"/> <!-- parameters --> <xsl:param name="fillColor" select="'#4b4b4b'"/> <!-- identity template --> <xsl:template match="@* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> <!-- set visible fill --> <xsl:template match="@fill"> <xsl:attribute name="fill"> <xsl:value-of select="$fillColor"/> </xsl:attribute> </xsl:template> </xsl:stylesheet>
And a little shell script to call it with a certain colour:
xsltproc \ --stringparam fillColor "#ce5127" \ --nonet build.xslt base.svg > uluru.svg
The transformed output:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-50 -50 100 100"> <!-- a wild disc appears --> <circle r="40" fill="#ce5127"/> </svg>
And the rendered image:
Development pro-tip
To prevent the base version from accidentally being deployed, I like to make it cyan and magenta. To save your eyes, it's behind a spoiler.
Warning - ugly colours
These colours also make good selectors, because no one ever uses them (right?).
I also add a large “Development mode” text over it. Then, using XSLT, I remove the ugly colours, comments and said text.
Exercise
See if you can remove the comments from the SVG.
Spoiler - remove comments from SVG
<!-- remove comments --> <xsl:template match="comment()"/>
Next up
This is the first part in a series. Other output formats and more cleaning will be covered in future parts.
-
think also branding, dimensions, file formats, dark mode etc.↩