Sensitive syntax

In a recent project involving an SVG document I stumbled on an interesting issue, and a reminder of the true nature of the vector language. To understand the point, however, consider the following, extremely trimmed down graphic.

<svg viewBox="0 0 100 100">
	<circle r="50" cx="50" CY="50" />
</svg>

Here you have a squared canvas, 100 units wide and tall. In this canvas, then, you find a circle, positioned in the very center and sized to occupy the entire visible area.

Paste the snippet in any REPL, any .html document and you see the round shape with a default black color. You may want to consider currentColor for the fill attribute to match the tone of the page, but that is beside the point.

The moment you save the graphic with an .svg extension, the moment you try to open this file directly in a web browser or include it with one of the possible HTML elements, img, object and the like, you don’t have the same result.

<img alt="HTML and XML" src="./svg-icons.svg" width="600" height="200" />

The browser might prompt a warning, but in the larger context of an .html document, referenced with the src or data attribute, you won’t even have feedback. Instead, you’ll be left with a chunk of white space, with a blank canvas.

The reason: SVG is an XML namespaced language.

Scalable vector graphics work wonders in HTML, where they are processed by the HTML parser, but ultimately are an extension of the Extensible Markup Language. And on their own, they are processed by the XML parser. If you were to check the Network panel in the developer console you will indeed find the following line in the HTTP header.

Content-Type
	image/svg+xml

image/svg+xml. XML, and not HTML. And the difference is far from trivial, as the pointless example confirms. The code simply doesn’t work as XML. And from the point of view of the XML parser, for very good reasons.

XML is far more strict, far less forgiving than HTML when it goes through the document. For starters, where the hyper-text format might try to work around typing quirks, to the best of its abilities, the extensible language doesn’t allow the same freedom. In HTML you might be forgiven for forgetting to close an element. In most instances, the browser will take care of terminating the element on your stead.

<circle r="20">

In XML, the same code would be a mistake.

But that doesn’t happen with the snippet, problematic for two other mishaps.

Immediately, you have the XML namespace. I’ve cited the xmlns attribute more than once, to the point where I often joke about the feeling I have skipping the value.

xmlns!

When you process the file, when you do not add the vector inline, you cannot escape the namespace, and a specific string after the cryptic argument.

-<svg viewBox="0 0 100 100">
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">

With the attribute the round shape appear, but something else is afoot. In the canvas the circle is drawn with the proper radius and the appropriate horizontal offset. Vertically, the element sticks to the top, and is cut halfway through the visible area.

You might have been glaring at this article ever since you realized the problem in the snippet, but believe you me, the issue is far less easy to spot in the context of a much larger graphic you’ve managed to draw with considerable effort. And possibly a break or two, where you might have switched tabs, continued with your life and managed to lock all caps.

-<circle r="50" cx="50" CY="50" />
+<circle r="50" cx="50" cy="50" />

A small change? For HTML it certainly is. But in XML attributes are case sensitive, and the instruction is simply dropped.

Of course the differences between the two formats go beyond the namespace and the mentioned rules. If you were to work with JavaScript, for instance, and you wanted to create SVG elements directly, you’d have to rely on dedicated methods reinforcing the namespace.

-const svg = document.createElement('svg');
+const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');

Without the precaution the browser would create an unknown element, and show nothing once more. A further reminder to test the output and double check your assumptions working with SVG. With or without HTML.