Introduction

This is an expanded, blog-form version of a recent thread of mine on Mastodon

I love the SVG format. It's not perfect, but it has some amazing features, and with all the issues in its support across different browsers, it still remains a solid vector graphics format.

One of the things I love the most about SVG is that it allows interaction and dynamic content without requiring JavaScript.

This isn't actually an SVG feature per se, but it's related to the specification integrating support for SMIL, an XML language for dynamic content.

SVG also supports and incredibly powerful element: <switch>. The combination of switch and SMIL allows some impressively sophisticated things do be achieved in SVG, without using JavaScript or serverside funkiness: and honestly, I love these features so much that I really wish HTML was extended to support them too.

In fact, there was an attempt to add SMIL support in HTML: it was called TIME (Timed Interactive Multimedia Extension), and was proposed by Microsoft and Macromedia and, after being submitted to the W3C, evolved into the W3C Note (not even a recommendation) for XHTML+SMIL.

No other browser than Internet Explorer ever added support for it, and honestly, I see that as a loss.

With the integration of MathML and SVG standards into HTML5, there is actually some hope (if just a sliver) of things moving forward in this direction, although I doubt any of the existing implementation actually plans on investing resources in it. One of the benefits of having more competition in this area would be better chances of a growth in this regard.

I actually wonder if some kind of JavaScript polyfill could be created to implement support for these features without UA support. It would be suboptimal, similarly to how MathJax is inferior to UA support for MathML, but could work as a stopgap solution to promote the adoption and standardization of these extensions.

An HTML switch polyfill?

I've tried a quick test to see if you can exploit the HTML5 inclusion of SVG to do without the polyfill, but since you can't just randomly throw SVG elements in the HTML parts of the document and expect it to work, to make it actually work you need a double wrapping, passing through the SVG foreignObject element and put the HTML in there:

body > svg > switch > [foreignObject > your HTML here]+

and this requires a lot of efforts because sizing and spacing have to be handled manually.

You can almost implement the SVG switch element in pure HTML + CSS with something like:

switch > * {
    display: none;
}
switch > *:lang(...) {
    display: initial
}

with only one issue: there's no way to put in that :lang() pseudo-class “whatever the user asked for”.

So you still need some JavaScript or server-side assistance to bridge the gap between the user language selection and the styling.

So close, yet so far away …

An HTML switch polyfill

If we do things a bit more cleanly in CSS (to account for switch elements inside SVGs embedded in HTML5), and add a little bit of JavaScript to handle the language check, it turns out you can polyfill a switch element for HTML!

(How? I'll show this a little bit later.)

Testing this across browsers, however, I ended up discovering that when it comes to the SVG switch element, there are discrepancies in which child is selected when the user voices a preference for multiple acceptable user languages

Choosing the “best” language

So: the switch element is typically employed together with the systemLanguage attribute of its immediate children, as a way to display different content depending on the language choice of the user. Per the specification, the switch element should select

the first child that matches the user's language preference.

Now, there are two ways to do this when the user accepts multiple languages.

One is: for every language accepted by the user, find the first matching element.

The other is: find the first element that matches any of the user languages

It turns out that Firefox adopts the first strategy, while WebKit and Blink browsers the second.

Which one is correct?

If I look at the SVG specification about the systemLanguage attribute, the text says:

Evaluates to "true" if one of the language tags indicated by user preferences is a case-insensitive match of one of the language tags given in the value of this parameter, or if one of the language tags indicated by user preferences is a case-insensitive prefix of one of the language tags given in the value of this parameter such that the first tag character following the prefix is "-".

My interpretation of this is that the correct way to handle the switch element would be the second one (used in WebKit/Blink) rather than the first one. On the other hand, when it comes to the specification of the switch element, we have

In SVG, when evaluating the ‘systemLanguage’ attribute, the order of evaluation of descendant elements of the ‘switch’ element must be as if the 'allowReorder' attribute, defined in the SMIL specification always has a value of 'yes'.

This means that a UA can reorder them so that the match with the highest preference has priority, and this is correct too. In fact, the SMIL specification clear says about allowReorder:

User agents are free to ignore the allowReorder attribute, but if they implement prioritized language ranges as defined in BCP47 they are expected to use that prioritization to reorder children with systemLanguage attributes. The effect should be that the users are presented with the alternative that best matches their language preferences. Any final child without systemLanguage attribute should retain its place as the default item to present.

Authors should add the allowReorder attribute if all items in the switch are equivalent.

So I hate the SVG switch element now. (OK, not really, but I dislike that different results are possible still following the specification).

It turns out that both interpretations are possible: the indication about allowReorder is that if true the UA should prioritize languages by the user preference, but the UA is free to ignore it, so one may consider Firefox to be better adhering to the specification spirit (give the user control), but WebKit/Blink are still correct simply by ignoring the possibility to reorder (which is good for speed, even if by the note above, that is only informative, they would be expected to do the reordering).

Now, why is this important for me? Because I have to choose which strategy to implement in my JavaScript of the polyfill for the switch element in HTML: the “fast” way (no reorder) was easy to implement, but the reordering one should be contemplated too, and possibly given preference.

To reorder or not to reorder?

To clarify, the difference is that with reordering, the reader has priority in choosing the version, without reorder it's the writer that chooses.

Let's say I write a text in Italian, but also produce an English translation. My preference as a writer would be for a reader that understand Italian, even if it's not their preferred language, to read the original Italian text. With the reordering, the user preference for English over Italian means they would get the translation, even if they could understand the original.

One of the interesting advantages of the polyfill is that at least conceptually it can be overridden, for example providing interactive elements to allow users to force a specific language without changing the browser preferences. I'm not sure this is possible in SVG. (I tried, and couldn't make it work without duplication, but this may be a UA issue, I'll have to take it up with them).

SVG switch element in action

By the way, if you're unfamiliar with how the SVG switch element works, you can see it in action in some of the SVGs shown below.

All of them have text in them (some more, some less), and you will see the text in some language, but others will see it in a different language. Which one you see it in depends on a combination of your language preferences configured on the browser, and on the actual browser you're using.

If you wish to actually see the element in action, and the text changing, you will have to (temporarily) configure your browser to prefer different languages, and reload the images.

Hybrids

The first multilingual SVG I explicitly coded for the wok is the printable SVG template I prepared to play Boulet's “Hybrids” game (see also the Italian article I wrote when I first published it):

Printable template to play Hybrids
Hybrids (template)

Whatever little text is there, it should be translated in your language (assuming it's one of: en, it, fr, de, ca, es, pt) —if yours isn't there, and you let me know the singular for dice and player, I'll try adding them. Corrections welcome too.

On the usefulness of prayer

My first attempt at using switch was actually much older than that, and it was an attempt at recreating in SVG a meme on prayer that has been circulating on the Internet at least since 2011:

A flowchar showing that prayer isn't useful, because it all depends on God's plan
On the usefulness of prayer

I'm not interested in debating the meme here, so please spare your time (and most importantly my time) and go debate it somewhere else (such as this 2014 blog article about it), but if you do wish to provide translations for the text in other languages, then please do let me know: currently I only have Italian, French and English (the latter should be the fallback, so the one you see if your primary language is not among the supported ones)

Circular reasoning works because circular reasoning works

The last one is something I originally only did in English only, again based on a who-knows-how-old meme circulating on the Internet, so I took the opportunity of this article to revamp it and add additional languages:

A circular text reading: circular reasoning works because
Circular reasoning works because circular reasoning works

Again, you should be seeing the text in your language, provided it's among the supported ones (Italian and French), or English otherwise. Please do let me know of translations in other languages, I'll gladly add them, and do let me know if any of the translations are not up to par.

HTML switch element

Let's see now how the HTML switch element can be polyfilled. The ingredients are:

  • a browser that handles unknown HTML elements correctly;
  • a few lines of CSS styling to determine when children of the switch element should be shown;
  • a few more lines of JavaScript to actually mark the children appropriately.

The additional conditions are:

  • the default styling should display the fallback switch child (if present) if JavaScript is disabled;
  • neither the styling nor the JavaScript polyfill should handle switch elements that are handled by the browser

An example of all this has been neatly packaged up in this sample test file.

The CSS polyfill

The CSS style is relatively simple:

switch > * { display: none }
svg switch > * { display: initial }
switch > *:not([systemLanguage]):not(.html-switch-false)
{ display: initial }
switch > .html-switch-true { display: initial }

It hides immediate children of the switch element with the following exceptions:

  • when the switch is a descendant of an SVG element (because these will be handled by the SVG renderer in the browser);
  • immediate children without a systemLanguage attribute, unless they are marked with the class html-switch-false: this ensures that the fallback is handled correctly (even if JavaScript is disabled;
  • immediate children with an html-switch-true class.

Obviously, the html-switch-true and html-switch-false classes are the ones that will be set by the JavaScript polyfill to mark items that should (not) be visible.

The style is not perfect. For example, it doesn't handle HTML switch elements that would appear inside a foreignObject inside an SVG, which may cause issues (I haven't tested), and if no JavaScript is used and more than one child has no systemLanguage attribute, they will all be shown.

The JavaScript polyfill

This is where the “magic” happens: on document load, we run a function that goes over every switch element that isn't recognized by the browser (and is thus represented in the DOM as an HTMLUnknownElement), and finds “the first child that matches the user language”. Both reorder and no-reorder versions of the algorithm are possible, and have been implemented in the sample file. (I'm not going to paste the code here; it's not long, but not even short.)

Like for the CSS, the JavaScript I've implemented so far isn't perfect: it doesn't play nice with dynamic content (although one may wonder why a switch element would be generated via JavaScript), and it hasn't been thoroughly tested. I also have no idea how well it plays with accessibility (although I would assume that the display: none CSS would make it work ‘as expected’; do let me know how it works for you, though).

Lessons learned (and things to look into)

Issues with the SVG switch element and its implementation

With all its power, the SVG switch element has some limitations, the most important of which is that only a limited subset of the SVG elements can be used as children, and the element itself can only be use as child to a limited set of other elements.

This leads to a lot of duplication. For example, in reference to the circular reasoning example, the text and textPath elements have to be duplicated for each language, rather than using a single text > textPath nesting with a switch on tspan elements for each of the languages.

While there may be good reasons for these restrictions (for example, different languages may have very different requirements in terms of sizing and proportions of the elements), it makes the use of the switch element exceedingly bothersome whenever those reasons do not apply, and especially when the author has to go n and introduce changes to the wrapping elements that could be shared by all variants.

Even worse, it makes it much harder to build SVGs where language selection can be done both switch-wise and through dynamic interactions.

(Of course it's also possible that I'm just missing some obvious alternative solution —my knowledge of SVG is still largely amateurish anyway— or the browser is failing me.)

The fact that user agents with the same language settings can produce different results is also annoying, and potentially disruptive. It can be argued that the “no reorder” path taken by WebKit and Blink is lazy, but ultimately it's the specification not being stricter in this regard that gives them the leeway to act this way.

Ultimately, the possibly biggest issue at hand is that most UAs don't provide a simple way to change the language preference. I had the opportunity to discuss this also in a separate context in this Mastodon thread started by @partim@social.tchncs.de: we really need some fresh blood in the browser space to bring forward “revolutionary” ideas like … allowing the user to choose a language easily without requiring each website to reinvent the wheel in this regard.

Should I propose an HTML switch element?

The WHATWG apparently has a procedure to ask for new features. I guess if I had some time to throw at this I could go there and submit a proposal to add a switch element to HTML too, or even to incorporate SMIL support into HTML5.

However, I have my doubts, even with a polyfill like the one presented here available for demo purposes, that this would garner enough attention, given implementors can't even be arsed with properly supporting multilingual titles in SVG, or giving users easier (and more fine-grained) controls on their language preferences for websites.

(That being said, if anybody wants to give it a go, I'll be happy to support them. I even have the use case right here.)