TL;DR: using data URIs will delay loading the HTML if the images are large
I built a script that replaced all inline images with data URI's to reduce http requests and seed up loading time on mobile devices.
This is a good idea if the time to perform requests is greater than the time to download the images, since the browser needs to download the image data in any case (whether data URI or not). If the image is embedded in the HTML as a data URI, you will increase the total size of the HTML by the sum of the size of all of the images (plus about 33% for the data URI encoding).
E.g. if the time to open a connection for a new request is 1s, and your images take 0.2s each to download, and you have 10 images, and your HTML takes 0.5s to download then, it will take:
- 1s + 0.5s = 1.5s for the HTML alone
- 10 x (1 + 0.2)s = 12s for the images
If you encoded the images into the HTML as data URIs (which are 33% larger):
- 1s + 0.5s + (10 x 0.2s x 1.33) = 4.2s
- (and no external requests for images)
An important factor here is how long it takes to get the whole HTML source of the page (1.5s vs 3.5s). If it's critical that you have the images when the page is drawn, data URIs would be a good optimization. If it's acceptable to draw most of the page with the images loaded asynchronously, it might be better to optimize for downloading the HTML completely first.
And if your images are large, it's much worse to encode them as data URIs. If each image takes 1 second to download and the other factors are the same:
With external images:
- 1s + 0.5s = 1.5s for the HTML alone
- 10 x (1s + 1s) = 20s for the images
With data URIs:
- 1s + 0.5s + (10 x 1s x 1.33) = 14.8s until the HTML is downloaded!
I figure it depends on that the html file was bigger (around 100kb instead of around 5 kb) :)?
As the browser downloads the HTML source of the page it begins interpreting and displaying it. When it reaches elements that refer to a separate resource, like images with external URIs (not data URIs) and (async) script tags, it will begin or queue downloading them, but continue downloading and processing the HTML of the page.
This means that as the page downloads, the user sees more and more of it, albeit without images and sometimes fonts loaded.
When the browser reaches an image tag with a data URI, it has to download and parse the whole data URI string before it can process anything after that in the HTML source. So if your original HTML was 1kb and you embed an image data URI of 1MB, there's going to be a pause when the browser reaches that image tag as it downloads the 1MB of HTML source occupied by the data URI-encoded image, before it processes any more of the page's HTML.
Must the browser complete download of the full document before it can load liked sources in it? Or will linked sources, for example css and javascript in the top of document, be loaded before browser has completet the full document?
Linked sources have their own loading and parsing logic. <script>
tags will be loaded synchronously - blocking the browser from parsing any more of the HTML source until the referenced script is loaded and executed - unless they have the async
attribute. External stylesheets will be downloaded in parallel but will block rendering until they're loaded.
There's a good explanation here.
If so, is it better to have a sepearate CSS file for data uri like this:
- Load CSS for structure (no data uri's)
- Load CSS for background images (all background images in URI format)
Will a "separate chaced jpg file" load faster than a "URI based image included in a cached css file"?
Any other suggestions on how to use data URIs?
It depends what you want to optimize for. Are you more interested in time to first render, even if the page is incomplete? Or time until the whole page, with all images, is rendered in full?
Like any tool, there's no blanket rule that will apply, like "always use data URIs" or "never use data URIs". A good rule of thumb is use data URIs for small images like icons. Webpack's url-loader
implements this logic automatically, using data URIs for files up to a specified size and otherwise using external URLs.