Menu Search
Jump to the content X X
Smashing Conf Barcelona

You know, we use ad-blockers as well. We gotta keep those servers running though. Did you know that we publish useful books and run friendly conferences — crafted for pros like yourself? E.g. our upcoming SmashingConf Barcelona, dedicated to smart front-end techniques and design patterns.

The Safari Problem With SVG Sprites (Now Fixed)

Update (19.05.2016): The bug was just fixed by Antti Koivisto and has landed in the current update of iOS (9.3.2) and Safari for OS X 9.1.1 (11601.6.17). When a user visits a site using a SVG sprite in a browser with an empty cache, the sprite is cached and will not be loaded multiple times any longer. You’ll find more details here1 (in German), and Sven Wolfermann’s results2 before and after the iOS update.

Sven Wolfermann's tweet3

Using external SVG sprite maps to deliver lossless scalable vector images is widely used in responsive web design today and well-supported by tools like svg4everybody4.

At German newspaper Zeit Online, we embraced this technique quite a lot. However, we recently changed this workflow back to completely inlining the SVG into the HTML owing to a bug in Apple’s Safari browsers (mobile since iOS 9.3, in Mac OS X since Safari 9.1) – the same way GitHub is doing with its octicons5.

Further Reading on SmashingMag: Link

The Problem Link

When using an SVG sprite map, you’re combining all your SVG icons into one file and loading it from an external source (typically through an external CDN). If you need an icon in the web page, it will be referenced by a fragment identifier in a use tag, like this:

<svg class="svg-symbol logo_bar__brand-logo" role="img" aria-labelledby="title">
   <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="icons.svg#svg-logo-zon-black"></use>
</svg>

The idea is to load the file only once, store it in the browser cache, and reference the icons when they are needed. The bug, which is demonstrated on this test case10 thwarts this approach entirely: every time an icon is used in a web page, the whole sprite file is loaded again (load the test case and watch the developer tools). Our homepage suddenly weighed 17MB on an iPhone with iOS 9.3, which is a problem for the user’s data plan and for the web page’s server too.

SVG Bug11
The SVG has been downloaded multiple times.

Indeed, it was the server monitoring that first led us to the bug. A fully updated iPhone loaded our (admittedly too big) SVG icon file, which was clearly identifiable in the server logs. Internally, a bug was filed and assigned to the front-end team, to check which component of the stack was downloading the icon file again and again. The browser string in the server logs directly identified iOS 9.3 versions of Safari, and some quick tests with the developer toolbar (and Charles proxy software12 to sort out possible mismeasurement) clearly showed that if we had 20 icons on a page, the icons SVG was downloaded 20 times if the cache was cold. We also found that Safari 9.1.1 on Mac OS X was affected. And we could see that prior versions of the browser did not contain the bug, which showed that we were hit by a browser bug, not a problem in our code. I filed a bug in Apple’s bug tracker and over in the svg4everybody repository. When I went to add it in the WebKit bug tracker, it was already filed.

Approaching A Solution Link

Mobile traffic is crucial for a news page, and having such a big homepage is a big problem for us and the user. We started to look for alternative approaches. We always made sure that our code followed standards, was progressively enhanced and as accessible as possible.

One solution could have been to Ajax our SVG file13, but that means you only progressively enhance icons that are not really required for a website to look good, and which have a rather decorative character. We use icons as standalone items, like a star to click on for rating items. These cannot use textual user ratings as a base to enhance from because it would lead to an inconsistent layout.

Furthermore, we have some logo SVGs that we crucially need to display when JavaScript is disabled, so for these Ajax was never an alternative. Also, the bug seems not to be feature-detectable and we do not use any browser detection, so we were looking for a cross-browser approach all the time.

In the end, the best approach might have been to split the icons by purpose and use different ways to load and display them. As we have three different use cases for icons, the perfect solution might be using different techniques on each. The large logo files which are critical to layout need to be inlined, as they are part of the content. This might also be the case for clickable standalone icons, where a text replacement would disturb the layout. As these icons are used in several place on a page, it would be a good idea to inline a sprite SVG file for these icons in the document’s head, which would be a bit of micro-improvement, because these files typically are just bytes in size. At least the rest of the decorative icons can use an Ajaxified external sprite file.

We decided that, given the bug will be repaired sometime soon, this approach would be too complicated, and we wanted to start off with a simpler solution. We switched to completely inlining all SVG. We’ll lose the caching effect, but on the other hand win back browser compatibility (from IE9 and up) and could ditch the polyfills and the production of fallback PNG files. On the first load, we’d also spare one or two requests.

Patch On The Way Link

Meanwhile the WebKit team has picked up the bug14 and it’s marked as fixed and resolved, hopefully soon enough for the fix to land in the next version of Safari — probably in fall this year.

Final Notes Link

What do you think about this approach? What other ways would you go to deliver SVG sprites? Let us know in the comments! Thank you!

(ms, ml, og, il)

Footnotes Link

  1. 1 http://nicobruenjes.de/2016/05/safari-svg-sprite-bug-fixed/
  2. 2 https://twitter.com/maddesigns/status/732835070696927232
  3. 3 https://twitter.com/maddesigns/status/732835070696927232
  4. 4 https://github.com/jonathantneal/svg4everybody
  5. 5 https://github.com/blog/2112-delivering-octicons-with-svg
  6. 6 https://www.smashingmagazine.com/2015/09/chrome-firefox-safari-opera-edge-impressive-web-browser-alternatives/
  7. 7 https://www.smashingmagazine.com/2014/03/rethinking-responsive-svg/
  8. 8 https://www.smashingmagazine.com/2014/09/testing-mobile-emulators-simulators-remote-debugging/
  9. 9 https://www.smashingmagazine.com/2012/01/resolution-independence-with-svg/
  10. 10 http://codecandies.github.io/safari-sprite-bug/external-with-symbols.html
  11. 11 https://www.smashingmagazine.com/wp-content/uploads/2016/04/svg-problem-safari-large.png
  12. 12 https://www.charlesproxy.com/
  13. 13 https://css-tricks.com/ajaxing-svg-sprite/
  14. 14 https://bugs.webkit.org/show_bug.cgi?id=156368
  15. 15 http://nicobruenjes.de/2016/04/safari-svg-sprite-bug/
  16. 16 http://nicobruenjes.de/2016/04/svg-yeah-you-know-me/
  17. 17 https://www.youtube.com/watch?v=OAbmDlnq1UE

↑ Back to top Tweet itShare on Facebook

Nico Brünjes works as webdeveloper at german newswebsite ZEIT ONLINE in Hamburg since 2006 and leads the frontend team for several years now. You can follow him on Twitter or contact him via his personal weblog.

  1. 1

    Martijn Wijmer

    May 19, 2016 10:51 am

    Replace svg sprite with a custom icon font? Not a good workaround for logo’s, but for icons it works fine. I find icomoon a real helpfull tool in converting svg files to a single font file.

    -3
    • 2

      Nico Brünjes

      May 19, 2016 4:06 pm

      We don’t use icon fonts for the reason the used unicode characters are read aloud on assesitive browsers. Also fonts are often blocked out by content blocker apps on iOS, which would leave our site w/o a logo for instance.

      3
  2. 3

    Inlining the sprite is probably the best move, though you should watch out for sprite size, and avoid putting some heavy stuff such as complex illustrations in your “icon” sprite. I’ve seen projects where a SVG sprite had several big illustrations in it and weighed around 150 kB or more.

    A more nuanced approach would be to only inline the icons you’re actually using in a page. This requires some templating helpers that either inline the icon’s code for each use, or “register” the icon as used and then outputs a page-specific sprite at the top of the body.

    For the record, the aria-labelledby="title" attribute in your original HTML code is wrong. It’s referencing the first element in your page which has id="title". This element probably doesn’t exist or doesn’t actually give a label for that icon.

    2
    • 4

      Nico Brünjes

      May 19, 2016 4:39 pm

      One problematic thing in the case was our way too big icon file, which weighted over 200kB. After the bug is fixed now, I guess we will switch back to external sprites for only thr large logos and regular used icons, for instance in the commenting area. Dynamically inlining these icons might bye the golden way, but would be a very complex programmatically task.

      Thanks for pointing out the wrong aria attribute. We use aria-label for the inline svgs now, so the problem does not exist anymore. Using aria-labeledby would only work with an inlined sprite sheet with e.g. title elements with id attribute.

      2
  3. 5

    I’ve been digging into svg sprites recently, too.
    The task was to assign a svg fragment identifier as a background-image in css –
    Works fine in most browsers, only ieOS and Safari cannot do this, though.

    After some hours of experimenting my solution to this was to use grunticon, which inlines me all svg resources into a single icon-stylesheet. ( and does not leave me with the headaches of sprite creation and maintenance).

    I prefer the css-icons over inline svg, since one does not have to worry about the svg markup in the html-source.

    0
  4. 6

    Firefox has a bug, too, if you’re using an external SVG sprite with img elements, and the fragment ID to reference the specific sprite from the src attribute: It’s also downloading the file over and over again.

    0

↑ Back to top