Categories
Web development

Organize SVG with <use>, but beware of transforms

Organizing SVG files with use and symbol elements offers many advantages, see for instance Sara Soueidan’s article. I did encounter some quirks though, especially with Safari, when using transforms in animations.

Quick solution

Let Greensock handle transformOrigin for you and don’t use the x and y attribute on <use>. Set a transform instead.

Read on if you want to know how I arrived at this conclusion.

What’s the test case?

The test case is derived from a little game I was creating when I encountered these issues.

The above SVG image, exported from Illustrator (4.37 kB) contains four similar crowns. Three encircled at the bottom (representing coins) and one on the head of the figure at the top. It would be nice to use the same code for each crown, instead of repeating the full graphic in the SVG file.

That’s what use and symbol are meant for. This would not only minimize the file size, it would also be more maintainable, and more semantic. Here’s a more structured SVG (only 1,87 kB):

HTML

The last coin was given an id special_coin, in order to transform (or animate) that coin with Greensock:

JS

One of the things that makes Greensock indispensible is it handles transform-origin for you. Doing it yourself is hard. I managed to do it in the last use (in Crown_Pipo), but only by fiddling the translation.

Quirks

All is well, until you check how things look on iPhone.

The first image shows how it is intended, in FireFox. The other Safari on iPhone. Three things have gone wrong. 1. The crown has disappeared from the head of the fellow with the nose. 2. The most right coin has transformed out of the picture and 3. The color of the coins don’t seem right. You may check the test page yourself.

Shadow DOM

Apart from that, if you inspect the code in Firefox with dev tools you’ll see that the shadow DOM doesn’t align with the real DOM, which is confusing.

The fix

The solution is to omit the x attribute on the use element and replace it with a transform instead. Actually it’s not so strange browsers get confused, since the x and y attributes are a shorthand for a transform (a translation). The order of transforms matters and may differ from browser to browser?

Here’s my final SVG, in which I also omitted the <defs> tag, because symbols don’t need that:

HTML

I also handed the crown on the figure’s head over to Greensock:

JS

Do the test

You may check the final test case for your device yourself.