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.

Visualization of, and musings on, recent Hacker News threads about liked and disliked languages

Posted by John Smith on

For a while now, I've been itching to find an excuse to something in SVG again, so when there were a couple of threads last week on Hacker News about people's most liked and most disliked languages, it felt like an ideal opportunity.

You can view a wider, more legible, version of the scatter plot via this link. I've used logarithmic scaling, as using a regular linear scale, there was just a huge mess in the bottom left corner.

'Like' votes are measured horizontally, 'dislikes' vertically - so the ideal place to be is low down on the right, and the worst is high up on the left. The results are as captured at 2012/03/28 - I'd taken a copy a couple of days earlier, and there had been some changes in the interim, but only by single-digit percentages.

Some thoughts and observations:

  • The poll this data comes from is somewhat imperfect, as already mentioned in the comments in the thread itself. I should also point out that another poster on that thread also did a similar like vs dislike analysis, but I didn't see that post until I'd already started on this.
  • HN is a very pro-Python place - just compare all the threads related to PyCon 2012 versus the lack of noise after most other conferences - so it's hardly surprising who the "winner" is in such a voter base. I do find it odd though that Python doesn't seem to have such a good showing in other corners of the HN world. e.g. of the (relatively few) HN London events I've been to, I don't recall hearing many (any?) of the speakers using Python for their projects/companies - whereas "losers" such as Java and PHP do get namechecked fairly often.
  • I'm amused that CoffeeScript is liked at exactly the same ratio as JavaScript - 76%.
  • I was tempted to do some sort of colour-coding by language type (interpreted vs compiled), age etc - but at initial glance, I don't see any real trends that might indicate why a certain school/group of languages do well or badly.

Incomplete implementation of getElementsByClassName for SVG in IE9

Posted by John Smith on

Now that IE9 has been officially released, I thought it would be wise to check that this blog looked OK in it - it certainly didn't in older versions, but given the audience I'm writing for, I wasn't especially bothered about fixing things.

For the most part it seems acceptable - it's mainly the cosmetic CSS stuff like transitions and gradients that aren't working properly. However, skimming through my older posts, I noticed a glitch which is more subtle than you might expect...

In this post I have an SVG file with some perfunctory interactivity implemented via JavaScript. Some of the more mundane functionality works - hovering over a segment in the bar chart changes the segment colour to indicate that it is clickable. However, clicking has no effect, whereas this works fine in other modern browsers.

Investigation shows that IE9's implementation of getElementsByClassName isn't all there for SVG. Within an SVG file, you can do document.getElementsByClassName("foo") to get all the matching elements in the entire SVG document, and that works fine, but document.getElementById("foo").getElementsByClassName("bar") to get the matching child elements within an element doesn't work.

There's a cut-down test file here. It works fine in Chrome, Safari, Firefox (4+) and Opera, but in IE9, its developer console reports this: Screengrab of IE9 showing it reporting a JavaScript error on a test SVG file that uses getElementsByClassName

A similar test on an HTML5 document's element does work fine in IE9, so it would seem to be an issue with their implementation of the SVG DOM. As this seems to only affect SVG, and an uncommon usage of the method - it looks like most people will use it against the document, not an element - this problem is unlikely to affect a large number of people, but it's certainly a pain in the backside for those of us who like to play with SVG :-(

Experimental stacked bar chart in SVG with JavaScript interactivity

Posted by John Smith on

Stacked bar charts are quite nice for presenting a relatively large amount of data in a compact space, but they have a major failing, in that it's difficult to compare similar values in different columns, unless the value is the bottom-most one in the bars.

As an experiment, I've played with adding some basic interactivity to try to address this. Below is an SVG chart that initially appears to be nothing out of the ordinary.

However, you can click on the individual parts of each bar to align baseline of the similar parts in the other bars, which then makes comparisons much easier. Clicking on a part twice reverts the alignment to the default state. This is all done via standard JavaScript and DOM event handlers - the main pain was that no browser supports CSS3 transitions in SVG, so I had to knock up some simple animation code. (I'm sure jQuery and similar libraries also facilitate this, but I wanted to have a completely standalone file.) EDIT: On reflection, I think I'm talking rubbish - CSS3 transitions can't be used on shape positions/sizes because they are part of the element itself, not a separate styling that's applied to it.

This is obviously super-basic; it might be good to do things like adjusting the Y-axis label numbering so that 0 is aligned with the selected element's baseline. However, I'm bored of this now, so I'm posting this up before I forget about it completely :-) The SVG code is currently entirely handcrafted, but now that all the basic concepts are in place, creating a graph from some datasource would be a fairly mundane exercise.

EDIT: I've just realized the SVG file has some console.log()s still in, which caused the animation not to work on Firefox 3.x - should now be fixed.

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.

Animation of newsprint reel change in SVG and JavaScript

Posted by John Smith on

Just been mucking around with SVG and JavaScript, and knocked out this fairly basic animation...

Something that's a tad annoying is that if you include an SVG file via an <img> tag, it doesn't seem to execute any JavaScript that it might contain - as such, I've had to resort to an <iframe> above. Whilst I can understand why an <img> isn't executed, it's mildly annoying - animated GIFs work, after all.

Just in case browser support does change, here's the SVG again, but this time pulled in as an <img>... SVG animation of the reel change process in a newspaper printing plant

Anyway, this is all well and good, but I imagine that >99% of the people who might view this will have no idea of what this is supposed to be. In brief (?), it's a very simplified side-on view of how paper is consumed in a newspaper printing press.

To avoid having to literally "stop the press", each press tower can hold two (or less commonly, three) reels of paper. One of these reels will be "webbed up", and unwinds the reel to feed the paper into the press. Note that these reels can weight between 500kg and two tonnes, with - very approximately - 20 kilometres of paper on them, which takes around 20 minutes to be consumed when a press is running at full tilt. (Bear in mind that I'm referring to the specifications of the presses and reels at a place I used to work, and other print sites are likely to differ considerably.)

As one is about to expire, the other moves into position to take over. There's some clever mechanical/electrical engineering magic involving double sided sticky tape (no joke) and automated cutters, which I'm not going to mention further, as I don't know enough about it to speak with any degree of accuracy. The finished reel drops down into a bin below, for later removal to a waste area, and a new reel takes its place.

The SVG/JS code is pretty hacky, and could do with a lot of improvement; however this was primarily for me to have a proper play with SVG for the first time, rather than to produce something "professional".

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