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.

Artificial pagination of articles on news sites - thanks, but no thanks

Posted by John Smith on

TL; DR: the bazillionth whinge about content sites with paginated articles, but picking on businessweek.com as they seem to be doing something particularly iniquitous, that I haven't seen before. (Although it could just be that I'm unobservant or behind-the-times, and that this is old news.)

I was in a branch of W H Smith yesterday, and had a quick flick through the latest issue of Bloomberg Business Week magazine. As usual, there were a number of articles that looked like they'd be worth reading, so I handed over £3.30 for the dead tree edition made a mental note to visit businessweek.com later to digest those articles properly.

I got round to visiting the site just now, and it looked like they might have had a minor redesign since I last visited - nothing particularly outrageous though. The first article I checked was this week's cover story about Twitter. Reading down the first page, it was quite a good piece, if not telling me anything I hadn't previously been aware of.

As I scrolled down to the bottom of the page, there was a pagination nav that indicated the article had been split into four pages. As I clicked on "next >" to go to the following page, I was surprised about how quickly the second page appeared - suspiciously quick, in fact.

Screen grab of a browser showing the bottom of an article at businessweek.com, specifically the page navigation

Being a nosey bugger, I viewed the HTML source of the page, and found that in fact, all of the article content is present in the "first" page, and it isn't even sectionalized in any way.

Screen grab of a browser 'View Source' window, showing that there is article content beyond that shown to the user on a page of a businessweek.com article

It wasn't a big surprise to me to find out that if I turned off JavaScript, my browser would now show the whole story on a single page, with no pagination controls visible anywhere. On my 1050x1680 portrait display, the full story runs for 8 screens in Firefox, which doesn't strike me as especially long and in need of breaking up. (NB: I have Ghostery blocking Disqus comments in Firefox; when I viewed the regular paginated site in a browser, I found that just the first of the four pages ran to 6 screensworth, of which around 50% were the - mostly inane - Disqus user comments.)

Screen grab of the businessweek.com story with JavaScript disabled, now showing all the article content on a single page

I haven't bothered to check the site's JavaScript code, but I assume there's something that measures the height of the <p> elements, and once the height goes above a certain point, starts splitting/hiding them into pages, and inserts the page navigation controls.

Now, pagination of online content is a complicated subject, and I'm no UX guru, conversion wizard or SEO charlatan who can confidently spout chapter-and-verse about what you should or shouldn't do when building a content site. What I do know is that as a user, I don't like having to continually click-scroll-click-scroll-click-scroll to get through an article that could have easily been scrolled through. And I'm pretty sure I'm not alone.

The usual excuse for pagination is that it increases the number of page impressions or ads that can be shown, but I don't think that's valid here:

  • As there's no new page being loaded when I click 'next', a page hit in the traditional sense isn't occurring. I'm sure there'll be some JavaScript analytics code sending something back to the server when I navigate to another page, but surely this could be done by handling onscroll events, similar to how people such as Twitter (ironically enough) implement infinite scrolling.
  • The ad space on a long single page is pretty much the same as on multiple short pages, so the same number of ads could be run. Now, after viewing the story on BusinessWeek a few times, it looks very much like there are only a very small number of ads being repeated on each sub-page of the story, and having the same ads repeatedly shown on a longer single page would look pretty dumb, but this seems to me to be more a failure of their ad sales or syndication systems, than anything else.
  • Most sites that use pagination - Ars Technica is the whipping boy that usually comes to mind - do at least keep up the pretence of having to download new content (whether by a traditional page load, or via Ajax), but this is the first time I've been aware of a site using JavaScript to IMHO actively make things worse for end users.

Tweet rendering code library put on GitHub

Posted by John Smith on

I've made public the code I use to render tweets to marked up HTML on the right-hand side of this blog. It's nothing special, either in terms of what it does or how it does it, but I've tried to be thorough at catching edge cases and doing sensible/useful things, so it might come in useful for someone? I was surprised that I couldn't see anything out there that already did this, but I didn't look especially hard, so maybe I have just reinvented the wheel.

The code is on GitHub at https://github.com/menboku/tweet2html. Licence is GPLv2.

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