Inline MHTML+Data URIs
MHTML and Data URIs in the same CSS file is totally doable and gives us nice support for IE6+ and all modern browsers. But the question is - what about inline styles. In other words can you have a single-request web application which bundles together markup, inline styles, inline scripts, inline images? With data URIs - yes, clearly. But MHTML?
I remember hacker extraordinaire Hedger Wang coming up with a test page, which proved it's doable. Problems with the test are that a/ I can't find the page anymore, his domain has expired b/ there was some funky IE7/Vista stuff (probably now solvable) in there which even included an undesired redirect c/ was complex - the whole HTML becomes a multipart document, if I remember correctly there was something that required html served as text/plain....
So I tried something simple - shove an MHTML doc inside an inline style comment. It so totally worked! Including IE6 and IE8 in IE7 mode on Windows 7 (which in my experience behaves as badly as IE7 proper on Vista)
Here's the test page. Look ma', no extra HTTP requests
So it's a simple HTML doc:
<!doctype html> <html> <head> <title>Look Ma' No HTTP requests</title> <style type="text/css"> /* magic here */ </style> </head> <body> <h1>MHTML + Data:URIs inline in a <code>style</code> element</h1> <p class="image1">hello<br>hello</p> <p class="image2">bonjour<br>bonjour</p> </body> </html>
And the magic is two parts: the MHTML doc inside a CSS comment and the actual CSS which uses data URIs for normal browsers and refers to the MHTML parts in IE6,7.
/* Content-Type: multipart/related; boundary="_" --_ Content-Location:locoloco Content-Transfer-Encoding:base64 iVBORw0KGgoAAAAN ... [more crazyness]... QmCC --_ Content-Location:polloloco Content-Transfer-Encoding:base64 iVBORw0KGgoAAAANSUh ... [moarrr] ... ggg== --_-- */ .image1 { background-image: url("data:image/png;base64,iVBORw0KGgoAAAAN ... QmCC"); *background-image: url(mhtml:http://phpied.com/files/mhtml/mhtml-html.html!locoloco); } .image2 { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUh ... ggg=="); *background-image: url(mhtml:http://phpied.com/files/mhtml/mhtml-html.html!polloloco); } body { font: bold 24px Arial; }
How cool is that!
Please report any issues you might find in any browser/os combination
The obvious drawback is repeating the long base64'd image content twice, but it's solvable with either server-side sniffing or... one crazy hack, found on the Russian site habrahabr.ru. I should talk about it separately and help spread the word to the larger English-speaking audience, but for the impatient - click!
So there you go - MHTML inline in CSS inline in HTML or building single-request x-browser web apps
This entry was posted on Sunday, October 3rd, 2010 and is filed under CSS, HTTP, IE, images, performance. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.
Get notification for future posts: follow me on Twitter or subscribe to my RSS feed

October 3rd, 2010 at 10:40 pm
There is a possibility to include only 1 base64-chunk into the document. http://bolknote.ru/2009/03/21/~2050#21 should tell more
October 4th, 2010 at 2:09 am
This is very useful for hard-core optimizations like in-lining core CSS in your homepage and boost start render / progressive rendering, only one request (html+css+datauris) and you’re done, your homepage shows some content to the user.
After that you can download real css files in background for the next user click that will generate a standard page.
Thanks !
October 4th, 2010 at 2:49 am
Btw, repeating the base64 content twice is not an issue as long as 2nd repetition comes right after (or close enough to) the 1st one. In this case gzip-ing will eliminate the difference:
Samples: http://sandbox.extjs-ux.org/datauri-gzip/
1) Images embedded into datauris (one repetition for each), size 174K: http://sandbox.extjs-ux.org/datauri-gzip/once.js
Gzipped, size 129K: http://sandbox.extjs-ux.org/datauri-gzip/once.js.gz
2) Images as data-uris 2 repetitions for each, 2nd is being placed right after original, size: 325K: http://sandbox.extjs-ux.org/datauri-gzip/twice.js
Gzipped, size: 131K: http://sandbox.extjs-ux.org/datauri-gzip/twice.js.gz
3) Images as data-uris, whole file content is repeated twice, repetitions are far from each other, size 348K: http://sandbox.extjs-ux.org/datauri-gzip/twice-whole.js
Gzipped, size: 259K: http://sandbox.extjs-ux.org/datauri-gzip/twice-whole.js.gz
As you can see in the 2) the difference between gzip-ed files is negligible even that source file is twice bigger. And in 3) gziped file is twice bigger with the roughly the same size of source file as in 2)
Question is – how far the 2nd repetition can be placed from the 1st? Probably it depends from some kind of “buffer size” in the gzipping algorithm.
October 4th, 2010 at 3:45 am
So may be instead that hack it will be possible to just create 2 styles near each other – one for normal browsers and another for IE. Some CSS frameworks like Less or SASS can ease this task.
October 4th, 2010 at 6:28 am
Nice.
Although it’s not ideal, to prevent having the base64 strings included twice you could have the strings as JavaScript variables (or properties of a hash lookup) and have JavaScript write out the style element for you.
October 4th, 2010 at 9:55 am
Stoyan,
imagine you use @font-face in the CSS for 1 special font and you want to minimize HTTP requests and go with this inlining images with data uri & mhtml and inlining the whole CSS.
In your opinion, is there a good reason *not* to base64 encode the OTF, TTF and WOFF files and inline those as well, just like the images? SVG and EOT font files have to stay external, so not all users will benefit, but many will.
The main benefit is the font file being available in the browser sooner and the Flash of Unstyled Text happens less often.
October 4th, 2010 at 2:12 pm
*Very* Interesting! Thanks for sharing this.
Two things I have noticed:
1) After playing around with this further and have worked around the problem that the mhtml: protocol has with relative URLs problem as described on your previous post at http://www.phpied.com/data-uris-mhtml-ie7-win7-vista-blues/ . My solution involves using IE’s CSS expressions.
background-image: expression(“url(mhtml:” + document.location + “!polloloco)”);
I have a working example here:
http://www.useragentman.com/tests/dataURL/selfContained.html
Unfortunately, this workaround doesn’t work with @font-face, although it’s fun to know one can embed fonts using absolute URLs:
http://www.useragentman.com/tests/dataURL/fontFace.html (IE 6 and 7 only)
I usually wouldn’t want to embed fonts this way (the HTML file is *huge*) but it’s neat to know this can be done. If we could work around the relative URL issue, maybe it could be used for HTML emails.
2) I noticed that if you transfer your resultant HTML from a Windows to a non-Windows environment using FTP, it must be done in binary mode. Using an ASCII transfer will cause it not to work (I assume because IE’s implementation of MHTML only works with Windows “\r\n” carriage-return encoding).
October 5th, 2010 at 3:59 am
I created a test page for inlining fonts. It’s a HTML with inline CSS and 2 EOT font files base64 encoded and inlined in the CSS. I tested it on IE7 on Vista and it works fine.
All in a single HTTP request.
Test page is here with my notes on file size increase, effect of Gzip and some early conclusions: http://www.aaronpeters.nl/sandbox/base64-fonts-eot.html
Yes, I know, I wrote in a previous comment that EOT files have to stay external. This appears not to be true. I’ve asked FontSquirrel for their opinion/experiences via Twitter. Will post their reponse here.
October 5th, 2010 at 4:39 pm
Hi Stoyan,
You mentioned that Hedger Wang’s site was down and you couldn’t find the page, it looks like Ajaxian did the same as well, but they copied some code. Is this what you were refering to?
http://ajaxian.com/archives/using-base64-encoded-images-on-ie-too
Thanks for the awesome article.
October 6th, 2010 at 3:32 pm
Stoyan! Copying and pasting your code does not work … At least not in Webkit/Safari on a Macintosh. Because MHTML requires CRLF for the linebreaks .. but the CRLF’s disappears when copy-pasting. Took some rounds of scratching my head before I found out …
October 6th, 2010 at 11:16 pm
Stoyan: If you create a line break between the
styleelement and the preceding element (title) in your your demo page, then the trick stops working. It somethiing related to the semantics of two consecutive CRLF line breaks in MHTML, I think.Zoltan Hawryluk: Your demo-page are invalid: neither HTML4, nor HTML5 or XHTML permit two hypens inside a comment.
To avoid that arbitray double consecutive CRLF’s matter, then either one must only use CRLF where they matter (I have not tested this). But this is difficult to keep control over … Preferrably all line-breaks should be the same, no?
Another alternative is to mak entire page a polyglot, then two consecutive CRLF’s are somehow ignored except when there is a preceding
--boundary-string. Hence, the MHTMLContent-Typestring must be placed preferrably before the DOCTYPE. However, doing so, brings IE in Quirks-Mode, even when string is placed inside inside a comment … So, we must bring up our box of conditional comment tricks to hide it from IE … In addition, my goal was to be able to place the MHTML inside ascriptelement. Below I show an HTML5 valid example.October 6th, 2010 at 11:27 pm
PS: Stoyan, remember to replace – with two -- before you publish taht code … I am thinkig about the 3 occurrences of
–=_data-uri, which each should be changed to--=_data-uri. Would be nice if you did something to your script.December 7th, 2010 at 10:21 pm
[...] summarize IMHO dataUris/MHTML of Stoyan is a better technique because you save the sprite request. However, using dataUris you [...]
December 8th, 2010 at 5:31 pm
[...] En mi opinion dataUris/MHTML de Stoyan es mucho mejor tecnica, porque nos ahorramos el request del sprite. Sin embargo cuando [...]
December 13th, 2010 at 3:41 pm
Thank You for Sharing Your Knowledge
January 8th, 2011 at 2:30 am
It’s super page, I was looking for something like this
January 8th, 2011 at 2:55 am
It’s good page, I was looking for something like this
February 24th, 2011 at 4:02 pm
[...] Для совсем маленьких изображений используем data:URI+MHTML: http://www.phpied.com/inline-mhtml-data-uris/ [...]
April 29th, 2011 at 9:37 am
[...] [...]
July 15th, 2011 at 9:04 am
[...] совсем маленьких изображений используем data:URI+MHTML: http://www.phpied.com/inline-mhtml-data-uris/ (это работает не во всех [...]
January 28th, 2013 at 5:51 am
[...] niitä varten pitää olla jokin toinen ratkaisu. Ongelman voi IE-selaimilla ratkaista esimerkiksi MHTML:n avulla. Käytännössä tämä tuo kuitenkin lisätyötä verrattuna CSS-spriteen, joka toimii [...]
March 29th, 2013 at 6:49 am
Hi all, here every person is ѕharing such
knowledgе, thus it’s good to read this web site, and I used to pay a visit this blog daily.