Rasterday: Rack Middleware for SVGs

Making SVGs a little more frictionless to use.

We love vector graphics. They scale beautifully, they can be very small and easy to generate, and they’re just a delight in general.

So whenever we can, we use SVG. It certainly has its quirks, but it is simple to generate and is supported almost everywhere.

Almost Everywhere, Indeed

The word “almost” is the killer, there. It’s only the last few years that support became widespread, and there are still a few problematic browsers out there. In particular, Firefox and most Webkit-based browsers (e.g., Chrome and Safari) do a good job, but old versions of those browsers do not, and there are some browsers for which SVG support is either missing or buggy.

There are a few options to this problem, and none of them are particularly appetizing:

  • Avoid SVG altogether until all the browsers you need to support handle it the same way. This is the usual approach, although inline SVG is gaining some popularity.
  • Identify which browser is making the request and serve different content based on whether the browser supports SVG. This is called “browser sniffing”.
  • Build multiple versions of graphical assets, and decide which images to show using client-side JavaScript to test for SVG support.
  • Use SVG anyway, and don’t worry about universal browser support.

All of the above approaches have trade-offs, and every project has constraints on time, developers, and hardware.

Enter Rasterday

We’ve been building an app for a really cool client, and he’d decided to kick in for IE support. IE does a somewhat lousy job with all of the SVG images that we use: older versions don’t display it at all, and even newer versions have issues with scaling.

This particular application is done in Ruby, using Rack, a standard part of the stack for Ruby web applications. A solution occurred to me and it didn’t seem like it would take long to code up something generally useful, and I offered to skip billing for it if we open-sourced it, to which the client said, “Any time you want to ask whether to bill me or open-source it, just open-source it.” So here’s Rasterday!

Rasterday is intended for the browser-sniffing approach. For most types of content, this is usually a bad idea: if you’ve ever seen a web application that worked but kept giving you annoying warnings that your browser is not supported, or if it redirected you to a degraded version on some browsers, you’ve been hit by a bad use of browser-sniffing. In this case, we just present a different version of exactly the same content, but rendered server-side in a format that’s a little nicer for the target browser.

The software isn’t limited to browser-sniffing, although that’s the intended use-case, and it’s what Rasterday does by default. The correct way to do this would be to parse the “Accept:” header (except that in this case, some browsers will claim support for SVG without providing the level of support we need). So if you’d like to parse that header instead, the API allows you to define arbitrary criteria. You can use a cookie, you can always convert images, you can even respond at random.

By default we convert it to a GIF (due to older IE’s tendency to also render PNGs poorly), but that can be changed to anything RMagick supports.

We have implemented it as Rack Middleware, so you do not need to change your application’s logic: just add it to the pipeline. Another advantage of this approach is that static SVG images work just fine if you use Rack::Static to serve them.

As always, we’ve made a good effort to document the project, provide a clear example, and make it easy to use.

It’s possible to build out a reverse proxy to support applications not written in Ruby or using Rack. We expect to refine the user-agent detector, and probably add a few more default types of check. If you happen to find a bug or, better yet, want send a patch or a pull-request, feel free.