Data URI Performance: Don't Blame it on Base64
This article is a follow-up to my recent post: On Mobile, Data URIs are 6x Slower than Source Linking.
In a previous post, I introduced new research which showed that using the data URI scheme inline is significantly slower to materialize an image on mobile than using an image tag directly (and if the image is known to be in the browser cache). I suggested that mobile web developers focus on using data URIs only for smaller resources and look at alternatives such as CSS sprites instead.
As a result of discussions with Ilya Grigorik from the Google Make the web Faster team and other developers from the web community such as Andy Davies, Tim Kadlec and Alex Sexton, I decided to run a follow-up test to give web developers a more precise insight into the source of the performance bottleneck of using data URIs.
In this article, I’ll investigate one possible candidate for the bottleneck: decoding the Base64 encoded data. This decoding process is used with binary images to transform the data into a format that is safe to include inline in HTML or CSS.
Spoiler: the bottleneck does not lie in Base64 encoding but may reside in resource scheduling of data URIs in general!
A New Approach: SVG
This new research focused on materializing a Scalable Vector Graphic (SVG). SVGs can be materialized on a page in two ways: as a Base64 data URI and as an unencoded data URI.
This flexibility is exactly what I needed to do a direct ‘apples-to-apples’ test with and without Base64 to see whether the decoding step of Base64 is actually causing the slow performance of data URIs.
I know that some of you had been hoping for a direct comparison with CSS sprites — don’t worry, that’s coming! But a CSS sprite test also won’t let me test the Base64 component in particular the way SVG does.
As with my other research, this experiment was conducted as a Real User Monitoring (RUM) test. I collected 911,206 samples of iOS 6, Android 4.2+, and Firefox 20+ browsers executing the test.
There were three test conditions, two with an SVG and one control condition to benchmark load performance when no SVG was used at all. The SVG used was a simple, 19.5kb creative commons graphic on Wikipedia.
The first test condition used an unencoded SVG, and the condition is called unencoded. The second test condition used a Base64 encoded SVG, this condition is called Base64. The control condition is called no SVG. This was a between-subjects experiment, and each phone would execute only one of the three conditions a single time.
I wanted to use SVGs included in a CSS stylesheet and not in an image tag, despite the fact that a load event cannot be hooked to the element itself. To get around this limitation, I used the page onload event of an HTML iframe containing only the stylesheet and element to contain the materialized SVG.
I included the control condition, no SVG, to baseline the performance of creating this iframe with no image at all in it. As you might expect, creating an empty iframe consumed almost no time, with the exception of Firefox mobile which was inexplicably slow.
This snippet illustrates the content of the tested iframe and the simplicity of the test.
My results show that there is a tiny performance penalty for using Base64 for SVG with Chrome for Android, much too small to account for the performance discrepancy identified in my original data URI article. The control condition, where there was no SVG in the iframe at all, is an order of magnitude faster, although inexplicably slow on Firefox.
For the Android 4.2 native browser and iOS, performance was very similar. In iOS, surprisingly, the Base64 condition is actually marginally faster, but the difference is small enough to be inside of the margin of error.
The chart above is taken from my previous research, and as you can see, there are performance differences of over 100ms between the data URI and binary conditions.
However, the SVG data I collected in this experiment fails to account for a performance gap of that size. As a result of this test, I don’t believe the performance problem of data URIs can be attributed to Base64 decoding.
Secondary Result: SVGs are Surprisingly Slow!
One interesting outcome of this experiment is that SVGs appear to be quite slow on mobile. iOS in particular was very slow to display this graphic, taking an amazing one quarter of a second to display it. Even at 128ms to display on Chrome suggests you shouldn’t include more than one or two SVGs in a page or your visitors will experience a perceivable lag in page load.
Additional guidance from this test would be to minimize SVG usage and focus on using it for logos or other key resources, and keep them under 10KB.
This research is a step closer to the root of the data URI performance issue. If the problem isn’t Base64 encoding, could it be something to do with resource scheduling of data URIs in general? Could that also be the reason why the SVG in this experiment took so long to load?
Stay tuned for the next instalment of our data URI analysis, which will directly compare data URI performance against CSS spriting (as requested in the comments of the first article).
As always, questions, concerns and feedback are welcome.