Hacker News new | comments | show | ask | jobs | submit login
CSS Sprites vs. Data URIs: Which is faster on mobile? (mobify.com)
101 points by shawnjan8 1543 days ago | hide | past | web | 23 comments | favorite

I’m all for research and hard data, but I can’t help being a little sceptical of these results.

We use data: URIs all over the place, typically storing icons and other small graphics as background-image sources in CSS. Over the broadband connection I’m using right now (roughly 5Mb/s download speeds) and with a cleared cache, our home page seems to be downloading and rendering in about 1.5s in all of the major browsers, and the lion’s share of that is downloading the HTML file first and then downloading various standalone images that we haven’t yet optimised at the end. Over a 3G mobile connection of dubious quality, in the browsers I can readily test with, there’s a lot of extra lag up-front, but little difference in the middle section where we download and render the CSS/data: images. These results are both fairly consistent with what we’ve seen throughout development and testing, across a decent range of test scenarios over an extended period.

So while I’m not sure from these articles where the difference might lie, I don’t see how to reconcile the results we’ve seen with the idea that switching to data: URIs somehow slows things down by 6x or 10x as reported in the linked article series. I wonder whether either the people doing these experiments weren’t measuring what they thought they were measuring or perhaps they’ve hit an awkward use cases that some/all major browsers don’t optimise well rather than a general problem with using data: URIs. The latter is certainly plausible, as there are cases with for example SVG where some browsers seem absurdly slow but everything works with the kind of performance you’d expect in others.

Meanwhile, data: URIs continue to have some concrete practical advantages for mobile, perhaps most obviously that they tend to circumvent mobile Internet providers “helpfully” compressing your graphics on the fly so they look terrible on your visitor’s 300dpi smartphone/tablet display, which is a particular problem with image sprites if their compression starts bleeding one image into the next. For reasons like this, we’ve found that in practice our decisions about how to send graphics on web pages are rarely dominated by speed considerations anyway — though they surely would be if using data: URIs really slowed down our pages by a factor of 6-10x!

For completeness, it could be interesting to also test:

• separate image files: after the cost of the initial many-separate-loads (which might be minimized by pipelining/SPDY), once reaching the cached-condition, might having them as individual artifacts again show some wins (no translations/trimming; shorter/simpler CSS)?

• data URIs inside CSS rather than HTML: on the off chance that leads to better post-data-decode image caching than re-parsing the cached HTML

The main takeaway seems to be: "This is in spite of the fact that the CSS sprite actually requires an extra connection and incurs all the associated connection overhead including TCP slow start!"

However, if the CSS file and sprite reside on the same server, and HTTP/1.1 with keepalives is used, chances are that the sprite will come down a preheated TCP connection (and thus also foregoing an SSL handshake, if fetching via https). The article doesn't actually mention how client and server are set up, and what the base network latency between them is.

It would be nice to see the test results with and without keepalives to see how this influences the results, as well as what the median network latency between client and server were during these tests.

Data URIs use base64 which adds quite a lot more the to image size. Ofcause it will be slower. Also, using Data URI over images will hang the users connection longer waiting for the Css to load before being able to see the page.

even though base64 increases raw size by about a third, this is mitigated by gzip or deflate encoding by the webserver. The actual transmitted size is only about 5% bigger

I measure less than that:

    dd if=/dev/urandom bs=1024 count=64 | base64 | gzip | wc -c
    64+0 records in
    64+0 records out
    65536 bytes (66 kB) copied, 0.0127386 s, 5.1 MB/s
This particular run comes out to ~2.7% overhead, and in fact it's very repeatable. The half dozen runs I did were within 20 bytes of each other.

The overhead is slightly worse when it's compressed alongside normal HTML content (the Huffman trees aren't so favorable).

    $ wget http://en.wikipedia.org/wiki/ASCII
    $ (cat ASCII;dd if=/dev/urandom bs=8000 count=1 | base64) | gzip | wc -c
    $ (cat ASCII;dd if=/dev/urandom bs=9000 count=1 | base64) | gzip | wc -c
Around 4% overhead. Either way, it's negligible.

Dead on! The overhead with gzip is very tiny. The size of the payload should also not be a factor in the cached condition.

IIRC CSS downloading is not blocking until the browser have to execute some JS.

The first CSS file on a page is blocking for all modern browsers regardless of JS or no JS.

Exceptions for:

* media queries, which are evaluated, if the CSS is not applicable it isn't downloaded

* disabled stylesheets which are ignored

(edited for formatting)

I'd be curious as to the underlying why here.

I imagine that CSS parsers aren't particularly designed with any kind of parallel operation, whereas grabbing images (& decoding them) is largely done in parallel (up to the number of max connections). So while you're parsing the CSS you can be getting the images, offsetting the connection cost.

In the CSS case, the device needs to get the (slightly larger) CSS, un-gzip it (with more complex tables), Base64 decode - and then decode the image as before. I wouldn't be surprised if this is a completely sequential activity with the rest of the CSS parsing.

I'd be interested in seeing these results with SVG.

There's a lot of commonality between the images, http://g-ecx.images-amazon.com/images/G/01/common/sprites/sp...

Even with Base64 encoding, much of that commonality would remain and thus I'd think that if you had all these sprites as SVG in a single file, as Data URIs, gzip would do a very good job indeed on the CSS file.

In a PNG sprite I wouldn't be so sure.

Inlining all of your images as data URIs in your CSS is not a good idea because it will block the rest of the stylesheet from loading whilst images will not.

and thusly will block the document from loading, most likely delaying first paint.

I must have missed the Data URI hype, because I'm not at all shocked that CSS spriting is faster than using Data URI. We are comparing using a binary image format, and a base64 encoded image inlined into CSS/HTML.

What isthe basis or the source of the idea that base64 encoded images inlined into the CSS would be faster?

I have the same question as Jochem Bökkers and Anil Namde had in the comments - why wouldn't you use both? I'm sure there's a good answer, but I don't understand.

I see the author has previous posts about what is not causing the delay, but what are the mostly likely culprits and do all browsers suffer similarly?

Might want to see whether this varies with the number of images (instead of 1) and the size (instead of 25kb).

I wouldn't imagine having two or more images would make much of a difference until you start reaching the max # of TCP connections per host, since these images would download in parallel. Would still be interesting to see results for.

Article author here -- I agree, it would be interesting to see results. One reason for using more than a single image: no navigation timing API in iOS.

iOS may now lag behind Android in handsets shipped -- but it's still a dominant player in web visits on mobile!

Unfortunately that means that for RUM tests I needed to have results that were insensitive to differences of a few ms.

Here's a petition asking Apple to include the navigation timing API in a future iOS release:


As someone who is grateful for your research and analysis, thank you, but filing a bug report is going to be WAY more effective, at least for iOS. https://bugreport.apple.com/ will get the ball rolling, even if it's been filed already. The more reports they get, the more likely they'll look at fixing the issue, especially if good use cases are provided.

Noted and filed! Thank you!

I was recently looking into some prebuilt libs for emoji support on web. One of them had a sprite, the other used data URI's in all of the background-image:url() parts of their core CSS. The sprite was crunched down to about 500k after some optimization tweaks (pngout, etc.) the data uri version could not be optimized, it's CSS file weight in at over 5MB.

The decision was pretty easy to make after that discovery.

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | DMCA | Apply to YC | Contact