Using the same process (combining data into a png => sending to browser => reading out specific chunks from the png), could you also have a script that combines all the images in your stylesheet into a CSS sprite, sends it to the browser, and then crops out each image on the client-side?
Then you wouldn't have to mess with all the trickery required to layout a CSS sprite and positioning it properly in your stylesheet. Of course the compromise would be the performance hit the first time the browser loads your site and has to crop the images out.
Interesting. What are your experiences with handling the disadvantages of using data URIs? [1] The biggest disadvantage that I see is:
Data URIs are not separately cached from their containing documents (e.g. CSS or HTML files) so data is downloaded every time the containing documents are redownloaded.
Content must be re-encoded and re-embedded every time a change is made.
Based on this, it seems like this would still work well for images specified in your stylesheet, but not so much for images that are specified directly in your HTML, because it would bloat HTML file size, and unless the user's browser caches the HTML file itself, they'll have to re-download the large HTML file over and over again.
Also, according to Wikipedia, base64 encoding makes the file size 33% larger than the binary file, and compressing it (as with gzip) only shaves off 2-3% of the base64 file size. Is this accurate? If so, it seems gzip encoding the transfer doesn't really recover the file size bloat you mentioned.
EDIT: Now that I think about it, if you base64 encode all the images in your stylesheet, won't that make your website look like ass for as long as it takes to download that stylesheet? Usually, this isn't a big deal because a text stylesheet gets downloaded pretty quickly, but now it will be larger in file size than the total sum of all the images that were specified in the stylesheet.
Also, according to Wikipedia, base64 encoding makes the file size 33% larger than the binary file, and compressing it (as with gzip) only shaves off 2-3% of the base64 file size.
Nope, the second part is wrong. See also the discussion here http://news.ycombinator.com/item?id=1491165 - overhead of compressed base64 tends to be very small, smaller than the HTTP protocol overhead. Base64 has only 6 bits of entropy and Huffman coding is able to take advantage of this.
Well, our approach works great for rich JavaScript web applications like those built with Cappuccino, not so much for websites. We don't have image URLs specified in stylesheets at all, but rather we use JavaScript to build up the DOM and set the src of all img tags (or background-image style properties, or canvas drawing, etc). That gives us the opportunity to replace the URLs with these data/MHTML URIs looked up through a map (URL -> data/MHTML) that gets populated when you load the sprite.
Regarding the "Flash of Unstyled Content" effect (http://en.wikipedia.org/wiki/Flash_of_unstyled_content), I believe this has been fixed by modern browsers, as long at the stylesheet is loaded in the head section, since the browser won't display anything until those resources have been loaded (not 100% sure about this, it doesn't affect the kinds of apps I'm talking about anyway)
Regarding Base64 + Gzipping, no, that's not accurate:
"Base64-encoded data URIs are 1/3 larger in size than their binary equivalent. This overhead is reduced to 2-3% if the HTTP server compresses the response using HTTP's Content-Encoding header."
This is saying the overhead is reduced from 33% to 2-3% over the raw image sizes, which is insignificant relative to the performance gained by significantly reducing the number of HTTP requests.
You last point doesn't apply to web applications where, for example, a progress bar can be displayed before showing any of the application UI.
Oh cool. Yes, I must have misread that compression stat.
We don't have image URLs specified in stylesheets at all, but rather we use JavaScript to build up the DOM and set the src of all img tags (or background-image style properties, or canvas drawing, etc).
That's really interesting. Since that's not explained in the article you had linked to, I'm assuming Cappuccino did this before switching to data URIs?
Thanks for taking the time to explain this approach more in depth.
Yeah, you should read a bit about Cappuccino, it makes drastically different decisions about how an application should be built on top of the browser, but as a result it gets to do complex things like this image spriting extremely simply.
Then you wouldn't have to mess with all the trickery required to layout a CSS sprite and positioning it properly in your stylesheet. Of course the compromise would be the performance hit the first time the browser loads your site and has to crop the images out.