While answering a question about styling SVG with CSS in the Freenode #svg IRC channel (yes, people still use IRC), I threw together a simple example to illustrate. I like to do this, since in keeps me in practice, and gives me a chance to check the state of current implementations in the fast-changing world of SVG browser support.

The question was how to use CSS stylesheets, both internal and external, with SVG in Inkscape. While I know that Inkscape makes heavy use of CSS inline style declarations on elements (more than is to my personal taste, to be honest), I didn’t (and don’t) know if it has any UI features for adding internal stylesheet blocks, or links to external stylesheets. So I made a little test…

svgstyle.svg

<?xml-stylesheet type="text/css" href="svgstyle.css" ?> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%" viewBox="40 0 145 70"> <style type="text/css"><![CDATA[ ellipse { fill: lime; stroke: green; stroke-width: 10px; } ]]></style> <rect id="inline" x="50" y="10" width="30" height="50" rx="5" ry="5" style="fill:lime; stroke:green; stroke-width:3px;"/> <ellipse id="internal" cx="103" cy="35" rx="15" ry="25" style="stroke-width:3px;"/> <circle id="external" cx="150" cy="35" r="25" style="stroke-width:3px;"/> </svg>

svgstyle.css

circle { fill: lime; stroke: green; stroke-width: 10px; }

Which looks like this (at least, in Firefox, Opera, Safari, and presumably Chrome):

Please use FF1.5+, Opera 9+, WebKit/Safari3.0, or IE with an SVG plugin!

Both internal styles worked fine in Inkscape, but the external reference did not, showing just a black circle. I’m not really surprised. Note the clunky way that you have to link to external stylesheets in SVG:

<?xml-stylesheet type="text/css" href="svgstyle.css" ?>

That’s really XSLT-licious. I have to confess, I don’t really care for PI s (insert dated Magnum PI joke here), or XML prologs in general… they seem somehow clumsy and un-XMLy, like a throwback to SGML. And as far as I know, they can’t be created or changed dynamically via clientside script. Compare that to the relatively easy and straightforward X/HTML way of linking to external stylesheets:

<link href="svgstyle.css" rel="stylesheet" type="text/css"/>

In the SVG WG, we intend to allow authors to reference external stylesheets in a manner a little more modern and consistent with what authors are already used to using, in some upcoming spec. We could do that a couple of different ways. We could allow them to use an xlink:href attribute on the <style> element, in the same way we currently treat the <script> element (that is, if there’s a resolvable external link, we use that, otherwise we use the child content of the element), or we could add a <link> element like X/HTML, or both. I kinda like the idea of allowing either.

To that end, I made a couple of tests, just playing around, to see if any browsers accidentally supported either of those options, by merit of having some shared codebase with X/HTML in their implementations. Unsurprisingly, neither worked.

But then I had another idea… use the an <xhtml:link> element in the XHTML namespace…

<xhtml:link href="svgstyle.css" rel="stylesheet" type="text/css"/>

With this rather happy result, which works in at least Firefox, Opera, and Safari.

external-link-xhtml.svg:

Please use FF1.5+, Opera 9+, WebKit/Safari3.0, or IE with an SVG plugin!

I don’t know if this is by design, or if it just fell out of the model, but I have to say I’m pleased as punch that it works. If nothing else, it’s a great proof of concept for adding more ways of linking to CSS in the SVG spec. This one goes in my toolkit, and I’m going to try to ensure that it gets standardized, if it’s not already there in some corner of some other spec. Probably somebody already knows about this (hell, probably everybody does, and I’m late to the party), but for me it was a w00ty discovery.

Update: heycam speculated that you might also be able to use @import rules, and indeed you can:

<style type="text/css">@import url(svgstyle.css);</style>