John Smith's Blog

Ramblings (mostly) about technical stuff

What's the best way of including SVGs in a responsive web page?

Posted by John Smith on

TL; DR: <object> seems the best bet - although Safari 5.1 has issues compared to the other browsers. Second choice is having the SVG inline in the HTML, but that has issues for WebKit and IE.

As a diversion from my more usual diet of Python, I've spent a fair bit of time over the past week or so revisiting SVG. My previous experiments have usually been done using fixed sizes, but I've always wanted to do something that fits in better with what these days is called "responsive design", especially given as these are supposed to be scalable vector graphics.

For an example of the sort of thing I've been aiming for, take a look at the main chart on a Google Finance page. This Flash chart resizes horizontally as you change the size of the browser window. (NB: the chart makes extra data visible as you make the browser window wider, which isn't exactly what I want, but you should get the idea.)

Unless I've been particularly boneheaded about the way I've investigated this, this isn't as straightforward a problem as it first seemed. If you put a regular bitmap image in an HTML page with something like <img src="whatever.png" width="100%" /> the image will scale as you'd hope when the browser window is resized. This isn't necessarily the case with SVG.

As outlined in the W3C docs, there are five ways that you can pull SVGs into a page in a modern browser:

  • <embed>
  • <frame> / <iframe>
  • <object>
  • <img>
  • Inline <svg>
(You can also create an SVG via DOM function calls, but I'm not particularly interested in that approach right now.)

I've built tests for each of these, and run them through the latest versions of the five main browsers. This obviously ignores a lot of issues with older browsers and mobile browsers, many of which don't even support SVG at all, but as it turns out, the "big 5" are enough to worry about on their own :-(

In the following sections, when I refer to a particular browser, the tests were done in the following versions, which (AFAIK) are the current ones as of early April 2012:

  • Firefox 10
  • Opera 11.62
  • Chromium 17 or 19 (I didn't notice any difference between the two
  • Internet Explorer 9
  • Safari 5.1
Where relevant, issues are illustrated with screengrabs from the Windows version of a browser, but much of my testing was done with Linux versions - except in the case of IE and Safari. I also tested whether JavaScript functionality worked - both within the SVG itself, and from the enclosing document trying to manipulate the SVG.

Just for clarity's sake: all of this messing around is (probably?) only needed if you want an SVG to be scalable within your web page. If you're happy for it to be a fixed size, then you shouldn't have to worry about any of the following stuff.

<embed>

Test link: http://js-test.appspot.com/svg/embedscaling.html

The image gets scaled correctly in Firefox, Chromium and IE. The image does not get scaled correctly in Opera or Safari.

Screengrab of SVGs using the embed tag in Opera 11.62 Screengrab of SVGs using the embed tag in Safari 5.1

<iframe>

Test link: http://js-test.appspot.com/svg/iframescaling.html

(I've assumed <frame>s behave the same; I couldn't be bothered to write a separate test for them.)

Only Chromium rendered the page completely as desired. Screengrab of SVGs using the iframe tag in Chromium 19

IE and Safari both failed to scale the images properly, but were able to modify the SVGs from the enclosing document's JavaScript. Screengrab of SVGs using the iframe tag in IE9 Screengrab of SVGs using the iframe tag in Safari 5.1

Firefox and Opera failed to scale the images, or modify them via the JavaScript in the enclosing document. I'm not sure if the JS issue is down to some DOM API difference and/or security problem - but as the scaling is broken, I couldn't be bothered to investigate further. Screengrab of SVGs using the iframe tag in Firefox 10 Screengrab of SVGs using the iframe tag in Opera 11.72

(All browsers did at least run the JavaScript contained within the SVG files.)

<object>

Test link: http://js-test.appspot.com/svg/objectscaling.html

Only Safari lets the side down, by failing to scale the SVGs. All other browsers work as desired. Screengrab of SVGs using the iframe tag in Safari 5.1

<img>

Test link: http://js-test.appspot.com/svg/imgscaling.html

If you have any JavaScript-based interactivity, forget about using <img> tags - the JS in the SVGs won't be run, and the JS in the document doesn't do anything either. WebKit-based browsers also have weird issues with additional padding and squashed images. You might hope that the preserveAspectRatio might be able to solve that, but I was unable to find any value which fixed things. Screengrab of SVGs using the img tag in Chromium 19 Screengrab of SVGs using the img tag in Safari 5.1

Inline <svg>

Test link: http://js-test.appspot.com/svg/inlinexhtmlscaling.html

This method is what the BBC uses for the position chart in its football tables, which is the highest profile use of SVG in a mainstream site that I know of.

Scaling works in all browsers, except IE. Screengrab of SVGs using inline SVG in IE9

However, WebKit browsers suffer from excessive vertical padding - it seems that WebKit assumes the height of the image is the same as the browser window, rather than the viewBox attribute in the <svg>. A slightly messy fix is to manually alter the height of the SVG elements after the page has loaded - this wasn't incorporated into this particular test, but an example from another test is here, and other people have documented similar workarounds. There are some open bugs on the WebKit tracker that might be related, here and here. Screengrab of SVGs using inline SVG in Chromium 19 Screengrab of SVGs using inline SVG in Safari 5.1

Whilst doing some earlier tests in this area, I also found a couple of bugs in Opera where

  • An HTML5 page wouldn't properly render, and would never trigger the load event - but an effectively identical XHTML page was fine. Warning: this bug also causes Opera to consume 100% CPU on the processor it is running on Screengrab showing bug in Opera in HTML5 page with embedded SVGs
  • If a page had multiple copies of the same SVG pulled in via the <img> tag, then if the page was reloaded, most of the duplicates would not appear: Screengrab showing bug in Opera after a page with duplicate SVGs is reloaded
Both of these have been reported to Opera via the tool built into their browser

Summary

As can be seen, of the five methods available, none is 100% foolproof. It seems to me that the best bet is <object>, as it works fine on all browsers except Safari, without need for JavaScript hacks. Second-place is embedding the SVG into the HTML, which entails a simple hack for WebKit browsers - but unfortunately is still broken in IE.

Disparity in requestAnimationFrame behaviour between Chrome and Firefox

Posted by John Smith on

This is a brief prelude to another post I hope to make in a couple of days or so, once I've solved my problem to my satisfaction. In the meantime, here's a related curio that I hadn't seen documented online before I had to start digging...

requestAnimationFrame is something that's been pushed in the last year or two as a more efficient way of doing animations in JavaScript than the traditional technique of using setInterval. In particular, it aims to avoid having your machine burn CPU on executing animations in a tabbed page that's not currently visible.

At time of writing, only Firefox and Chrome seem to actually support this function, albeit with moz and webkit vendor prefixes. caniuse.com doesn't have too much information about future support in other browsers - it'll appear in IE10, but it's unclear about Safari or Opera. Certainly the Opera Next 12.0 I downloaded yesterday doesn't appear to have it.

Now, for the most part this isn't the end of the world, as there are published shims to implement a workable alternative using setInterval() or setTimeout(). Unfortunately, these will just churn away as normal in a background tab, whereas what I wanted to do was to see how things were different in a background tab.

It turns out that the two implementations we have so far differ in their behaviour. Chrome comes to a dead stop when a page is in a background tab, which is probably what you'd naively expect to happen. Firefox on the other hand does some gradual throttling - you'll get one frame in the first second of being backgrounded, then another after a further two seconds, then a further four seconds, eight seconds, sixteen seconds, etc.

I knocked up a very rough demo for this, so that you can see for yourself - take a look here, and see what happens when you r-click the link on the page and open it in another tab - the function called via requestAnimationFrame() updates the page title, so you can see how often it gets called from the text in the tab.

I'm not completely clear why Mozilla have implemented this the way they have - I've not dug out any official specs, but going by the year old Chromium issue to add this functionality, I don't expect this behaviour to show up in Chrome/Chromium.

In the next post I'll elaborate on the problem I've been trying to solve - suffice to say, using requestAnimationFrame was a bit of a hacky way of trying to achieve something that I'd have thought should have been extremely straightforward...

NYT Chrome app is probably the buggiest thing I've ever seen

Posted by John Smith on

I should probably have read the Hacker News thread first, but Christ, what an atrocious piece of buggy shit this is. How on earth it managed to get positioned as one of the top launch apps on the Chrome App Store, one can only guess at.

Running in Chrome 8 initially, I noticed that the pagination algorithm seems completely borked. Very minor resizing of the browser window causes the indicated number of pages for the story to randomly fluctuate - I think I managed to get the same article to claim to be between 1 and 13 pages in length, at least if the footer on the right is to be believed.

Screengrab of NYT Chrome app, claiming to show page 1 of a 6 page story Screengrab of NYT Chrome app, now saying the same story is 4 pages long Screengrab of NYT Chrome app, this time saying story is 10 pages long

OK then, let's start advancing through this ten page story. The second page is fine - if rather text-heavy and image light - but the third page is slightly empty though...

Screengrab of NYT Chrome app, showing page 3 of 10, but the story seems to end

... I'm sure there must be more to come though ...

Screengrab of NYT Chrome app, showing a blank page 4 of 10

... oh.

Safari is unsurprisingly similar. What is a surprise though, is that this is as good as it gets.

Opera 10.63 just keeps kicking you back to the front page every time you click on a story link, whereas on Firefox you have a choice of illegibility or invisibility...

Screengrab of NYT Chrome app in Firefox 3.6.13 - text is illegible due to multiple paragraphs appearing on top of each other Screengrab of NYT Chrome app in Firefox 4 beta - only the navigation sidebar appears, the rest of the page is blank

One can only imagine what further travesties might await were I to dare view it in IE...

The de-facto standard icon for "microphone" is rubbish

Posted by John Smith on

I've been mucking around a bit with the speech recognition stuff that's been added to the <input> element in Chrome 8, and I have to wonder how discoverable this functionality is going to be for the average user.

If you add speech x-webkit-speech to your <input> tag, the resultant form looks something like this: Screen grab from Chrome 8 showing an input field with a speech icon Clicking on the icon opens up a small popup prompting the user to say something, the popup also has the same icon.

Now, when I see that icon, I don't personally immediately think, "Aha, a microphone". Assuming I'm not completely abnormal, how many users are going to click on an icon they don't recognize, without some sort of external prompting text telling them what it is? (NB: this isn't a design decision specific to Chrome; my Dell netbooks also have a similar icon on their microphone jack inputs.)

As a sanity check, I've done some brief checks on Google and Bing's image searches for "microphone", and fail to find anything that looks like this icon - the top results are a mix of "bisected globe" microphones (which is what I'd consider to be the most widely known variant), and "rounded cuboid" ones, which are closer to the icon Chrome uses, but not a close resemblance in my opinion. Google image search top results for the term 'microphone'

Now rather than merely whinge as usual I've tried to be constructive for once, so here's my crude attempt at an icon that looks more like what I'd expect. As I'm not a graphic designer or UI expert, I'm sure something much better could be done - it doesn't scale down to 16x16 very well for starters - but hopefully it's better than nothing. The first file below is the original SVG, so anyone could tweak it in InkScape or similar apps; licence is WTFPL.

Original SVG file for microphone icon 64x64 PNG version of microphone icon, converted by rsvg-convert 32x32 PNG version of microphone icon, converted by rsvg-convert 16x16 PNG version of microphone icon, converted by rsvg-convert

UPDATE: I've just found that there's a Unicode microphone glyph, which looks to use the "bisected globe" type. However, I haven't found a machine/font yet which contains this glyph, and the sample image contains musical notes, which are a bit out-of-context for speech recognition text inputs.

About this blog

This blog (mostly) covers technology and software development.

Note: I've recently ported the content from my old blog hosted on Google App Engine using some custom code I wrote, to a static site built using Pelican. I've put in place various URL manipulation rules in the webserver config to try to support the old URLs, but it's likely that I've missed some (probably meta ones related to pagination or tagging), so apologies for any 404 errors that you get served.

RSS icon, courtesy of www.feedicons.com RSS feed for this blog

About the author

I'm a software developer who's worked with a variety of platforms and technologies over the past couple of decades, but for the past 7 or so years I've focussed on web development. Whilst I've always nominally been a "full-stack" developer, I feel more attachment to the back-end side of things.

I'm a web developer for a London-based equities exchange. I've worked at organizations such as News Corporation and Google and BATS Global Markets. Projects I've been involved in have been covered in outlets such as The Guardian, The Telegraph, the Financial Times, The Register and TechCrunch.

Twitter | LinkedIn | GitHub | My CV | Mail

Popular tags

Other sites I've built or been involved with

Work

Most of these have changed quite a bit since my involvement in them...

Personal/fun/experimentation