MHTML - when you need data: URIs in IE7 and under
In the previous post I described what data: URIs are and how they are useful to reduce the number of HTTP requests. Now, the problem with data: URIs is that they are not supported by IE < 8. But, thanks to this article (in Russian), here's a way to work around that limitation: using MHTML for IE7 and under.
MHTML-a-what?
MHTML is MIME HTML, or if you insist on me spelling it out completely is like "Multipurpose Internet Mail Extensions HyperText Markup Language". In short it's HTML but like email with attachments. In one "multipart" email you can have several... hm, things - HTML version of the email, text-only version, attachment, another attachment...
MHTML is the same but for HTML. In one file you put a bunch of stuff (e.g. image files) and you save on the precious HTTP requests.
MHTML example
Let's check out an example. The HTML is actually not important, it's the CSS where we'll stick all our inline images. Once with data: sheme for all normal browsers and once with the mhtml: scheme for IE before 8.
The overall "template" would look like so:
/* Content-Type: multipart/related; boundary="_ANY_SEPARATOR" --_ANY_SEPARATOR Content-Location:somestring Content-Transfer-Encoding:base64 iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAA[...snip...]SuQmCC */ #myid { /* normal browsers */ background-image: url("data:image/png;base64,iVBORw0[...snip...]"); /* IE < 8 targeted with the star hack */ *background-image: url(mhtml:http://phpied.com/mhtml.css!somestring); }
The multipart stuff goes into a CSS comment. You then use data: URI scheme for all normal browsers. Then you use the star hack to target IE browsers before 8. For these browsers you give the URL of the CSS, exclamation and then a string that uniquely identifies the desired "part" in the multipart comment. Simple, eh? Didn't think so, but hey, it's not exactly rocket science.
Demo example with more parts
Check out a demo page that has two "parts" in the multipart MHTML comment.
The HTML is noting special and the CSS goes like:
/* Content-Type: multipart/related; boundary="_ANY_STRING_WILL_DO_AS_A_SEPARATOR" --_ANY_STRING_WILL_DO_AS_A_SEPARATOR Content-Location:locoloco Content-Transfer-Encoding:base64 iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAGElEQVQIW2P4DwcMDAxAfBvMAhEQMYgcACEHG8ELxtbPAAAAAElFTkSuQmCC --_ANY_STRING_WILL_DO_AS_A_SEPARATOR Content-Location:polloloco Content-Transfer-Encoding:base64 iVBORw0KGgoAAAANSUhEUgAAABkAAAAUBAMAAACKWYuOAAAAMFBMVEX///92dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnYvD4PNAAAAD3RSTlMAACTkfhvbh3iEewTtxBIFliR3AAAAUklEQVQY02NgIBMwijgKCgrAef5fkHnz/y9E4kn+/4XEE6z/34jEE///A4knev7zAwQv7L8RQk40/7MiggeUQpjJff+zIpINykbIbhFSROIRDQAWUhW2oXLWAQAAAABJRU5ErkJggg== */ #test1 { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAGElEQVQIW2P4DwcMDAxAfBvMAhEQMYgcACEHG8ELxtbPAAAAAElFTkSuQmCC"); /* normal */ *background-image: url(mhtml:http://phpied.com/files/mhtml/mhtml.css!locoloco); /* IE < 8 */ } #test2 { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAUBAMAAACKWYuOAAAAMFBMVEX///92dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnYvD4PNAAAAD3RSTlMAACTkfhvbh3iEewTtxBIFliR3AAAAUklEQVQY02NgIBMwijgKCgrAef5fkHnz/y9E4kn+/4XEE6z/34jEE///A4knev7zAwQv7L8RQk40/7MiggeUQpjJff+zIpINykbIbhFSROIRDQAWUhW2oXLWAQAAAABJRU5ErkJggg=="); /* normal */ *background-image: url(mhtml:http://phpied.com/files/mhtml/mhtml.css!polloloco); /* IE < 8 */ } div { width: 100px; height: 100px; font: bold 24px Arial; }
Drawback
In addition to the drawbacks of data: URIs (bigger CSS, small CSS change invalidates your cached inline images), this method has the obvious drawback that the inline images are repeated twice. But sometimes... a person's gotta do what a person's gotta do ![]()
This entry was posted on Friday, April 10th, 2009 and is filed under CSS, 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

April 10th, 2009 at 9:53 am
[...] Continued here: MHTML - when you need data: URIs in IE7 and under [...]
April 10th, 2009 at 6:05 pm
Interesting article! Unfortunately, this doesn’t work for me in both IE6 and IE7 (on Windows XP). The divs just have a blank background. There are no special security settings for the browsers (it’s a stock Windows XP install, with nothing more than IE). I don’t really know what further information I can supply that would be helpful for debugging.
April 10th, 2009 at 6:07 pm
For some reason, I can’t save other webpages as .mht either. Maybe my installation is broken, but I actually don’t know what could have broken it.
April 10th, 2009 at 6:11 pm
It worked in another VM in IE6. I don’t quite know why it’s broken in the other VM (as I said, it’s a straight-from-disc Windows XP installation with no further modifications).
April 10th, 2009 at 8:34 pm
Thanks for the comment/report, Konstantin. I tested with an XP VM (on a Mac) and it worked for me, dunno what can be happening with your install, but please drop a comment if you figure it out.
Thanks again,
Stoyan
April 11th, 2009 at 9:00 pm
[...] MHTML - when we need data: URIs in IE7 as well as under [...]
April 13th, 2009 at 1:27 am
Great post! Thanks for sharing.
Did you test it on IE7 on Vista?
I’ve found this http://www.eggheadcafe.com/software/aspnet/33808138/mhtml-doesnt-work-in-vis.aspx
Thanks.
April 13th, 2009 at 1:51 am
Hey Hedger, nope, only XP virtual machine.
April 14th, 2009 at 12:33 pm
Tested this technique out on Windows Vista with IE7 and the background images are not viewable.
April 14th, 2009 at 9:53 pm
But now isn’t your CSS file is getting the image twice, once in the comments for IE<8 and then once again for everyone else?
April 15th, 2009 at 6:22 pm
[...] MHTML - when you need data: URIs in IE7 and under / phpied.com [...]
April 17th, 2009 at 10:44 am
@anthony - yep, that’s a drawback. One solution would be to include browser-specific stylesheets.
April 21st, 2009 at 2:52 pm
Though IE7 is the default browser on Vista, I’d assume that the MHTML issue would apply to all IEs on Vista.
To make MHTML work on IE with Vista, all we need is to do two things.
* Output the MHTML document with the content-type “text/plain”.
There are a lot test examples on http://people.dsv.su.se/~jpalme/ietf/mhtml-test/mhtml.html
You may try this one http://people.dsv.su.se/~jpalme/ietf/mhtml-test/mhtml-1.txt for example.
* Redirect do that MHTML file to its hosted URI which “mhtml:” as prefix.
eg: mhtml:http://people.dsv.su.se/~jpalme/ietf/mhtml-test/mhtml-1.txt
This would work on IE7/Vista http://www.hedgerwow.com/360/dhtml/base64-image/demo.php?v=2009
Thanks.
April 22nd, 2009 at 3:27 pm
There is a solution where you don’t have to put both images (IE + others) into one file.
It’s not a must to put the image-data for the mhtml source into the same css file. It’s possible to reference to an other file, that can have any file extension, so it’s possible to put the mhtml data into an own txt file, wich is delivered as text/plain by the webserver, so it’s also working in IE7 Vista.
Take a look at: http://www.betalon.com/html/release.htm
I’ve tested this with: IE 6 (XP), IE 7 (XP), IE 7 (Vista), FF 3 (XP), Safari (XP)
The CSS file is: http://www.betalon.com/static/release/css/screen.css
The MHTML contents are in this file: http://www.betalon.com/static/release/css/screen.iecss!imagk
So in the browsers which support data-urls the image contents will be loaded only once.
Don’t be afraid to contact me if there is any problem with this solution.
April 27th, 2009 at 2:15 am
[...] MHTML - when we need data: URIs in IE7 as well as under [...]
April 29th, 2009 at 3:48 am
[...] Explorer: Data-URIs in IE7 and under – Der IE8 kann es von Haus aus und mit diesem Trick auf die älteren [...]
May 15th, 2009 at 8:13 am
[...] Stoyan wrote an interesting post today onMHTML - when you need data: URIs in bIE7/b and under / phpied.comHere’s a quick excerptUnfortunately, this doesn’t work for me in both IE6 and bIE7/b (on bWindows/b XP). The divs just have a blank background. There are no special security settings for the browsers (it’s a stock bWindows/b XP install, with nothing more than IE). … [...]
May 18th, 2009 at 12:58 pm
Sorry, Stoyan - please delete the above. My mind was still switched to German mode…
What I wanted to say: very nice tipp!
I made use of this technique on one of my customers’ site, where the customer always complained that the loading times of the image gallery pages took so long. Which is no wonder, as they consist of up to 130 thumbs that induce a lot of HTTP-overhead. In addition he used to visit his page with IE7/8, which made it even worse (Google Chrome dealt quite OK with it for example).
So now I do a serverside check for the user agent, and serve the right technology for the respective browsers: The IEs get all thumbs stuck together in an external MHTML-file (which is nice, as it makes it browser-cacheable), Webkit and Firefox get the thumbs embedded as Data URIs. All other browsers take the traditional route, with a little tweaking in that I load the images from 3 different subdomain (all pointing to the same folder) and therefore get around the HTTP-1.1-limitation of only 2 connects per host in parallel (now up to 6 in parallel).
The MHTML and HTML-files are being GZIP-compressed which saves about 50% of the image-data load. THE MHTML-file also gets browser-cached through the help of mod_expires. And all the base64-transcoded data gets cached on the server-side in order to save CPU-cycles and time.
Here is the page in question:
http://www.sky-fun.de/fallschirmspringen-fotos-bilder.php
Thank you very much again for your blog and regards from Germany!
Schepp
May 29th, 2009 at 11:20 am
This article (and the accompany data: URI one) saved me! Thanks for your efforts.
A tip for other readers: the format of the MHTML template is important. In my experience, the boundary declaration needs double-quotes (not single-quotes), and the blank lines after Content-Type and before data string must be present.
Thanks!
Stuart
May 31st, 2009 at 10:44 pm
[...] Phpied.com - MHTML - when you need data: URIs in IE7 and under [...]
June 14th, 2009 at 12:06 pm
Has anybody written a canvas API for this yet?
June 21st, 2009 at 4:18 pm
[...] same trick is used to for CSS and to reduce HTTP requests. And by reading that post I learned that we have to do it another way in IE. In IE we have to use MHTML and it involves a little more work on the server but we can still end [...]
July 13th, 2009 at 11:15 pm
Thanks for the great post here!
I was trying to produce the same result by putting the CSS and mhtml stuff in the tag in the html file. However, it didn’t work. Have you ever tried this? Thanks!
July 14th, 2009 at 1:49 am
Which tag, Caren? Seems like the tag was stripped from your comment
July 14th, 2009 at 11:56 am
Thanks for the quick response, Stoyan!
What I was trying to do is put the multipart and CSS stuff in the tag in the html file. I’m not entirely sure what to put in the url which points to the path to the multipart , i.e. mhtml:http://phpied.com/files/mhtml/mhtml.css!locoloco. Does the path now point to the html file path itself? I also did some google search and found out that maybe content-id is another way to serve as the location here, but I’m still out of luck to get it work.
I appreciate your help !
July 29th, 2009 at 12:46 am
Is there to specify relative urls instead of absolute urls
for example
use something like below
*background-image: url(mhtml:mhtml.css!locoloco);
instead of this
*background-image: url(mhtml:http://phpied.com/files/mhtml/mhtml.css!locoloco);
thanx
August 15th, 2009 at 11:57 am
[...] MHTML和Data URI还比较类似,有更强大的功能和更复杂的语法,并且没有Data URI中“无法被重复利用”的缺点,但MHTML使用起来不够灵活方便,比如对资源引用的URL在mht文件中可以是相对地址,否则必须是绝对地址。hedger在《Cross Browser Base64 Encoded Images Embedded in HTML》针对IE的解决方案使用的是相对路径就是因为声明了Content-type:message/rfc822使IE按照MHTML来解析,如果不修改Content-type则需要使用MHTML协议,这个时候必须使用绝对路径,如《MHTML – when you need data: URIs in IE7 and under》。 [...]
August 24th, 2009 at 3:19 pm
@schepp: What do you think of the technique called “CSS Sprites”? It creates one big images (which can be generated on server side) and send it to the client, instead of sending many small images. For more information: http://www.alistapart.com/articles/sprites
September 1st, 2009 at 12:24 am
I having a problem with *.mht/mhtml. First, I can save web-pages as *mht - no problem. The problem is that I cannot open ANY *.mht/mhtml saved web-page from Microsoft. I save the “fact sheets” (knowledge base articles) for respective MS updates so that, when or if needed I have them available rather than having to always go online to view/read. Some time ago, exactly when I don’t remember, I had no problem with this. However now, when I attempt to open a *.htm saved MS web-page, IE7 grinds to a halt and stops responding. I have to run Task Manager to “end process” for IE. The same holds true for IE8. Additional info … I can open any *.mht saved web-page from any other web-site (so far) without any problem. Also, I can save MS web-pages a *.htm (html) and can open them without any problem. It’s only the MS web-pages I’m having problems with when saved as *.mht. I am using Windows XP Home w/SP2 (fully up-to-date as far as I know) and currently using IE7. MS help is worthless for any kind of assistance. I have been googling various topics and not finding anything that is close to what I am experiencing. Can you help? Thanks for listening.
September 3rd, 2009 at 5:12 am
very nice post
September 28th, 2009 at 4:36 am
Problem with IE7 on some XP machines.
The sample page in this article (http://phpied.com/files/mhtml/mhtml.html) will not run with IE7 on some XP machines in my intranet, on other XP machines with IE7 it works fine. I have compared IE settings but there are no differences. There is no error message, the images will just do not show. Any thoughts on this?
September 28th, 2009 at 12:18 pm
Hi Mats,
Other comments also reported an issue with XP. Looks like the solution would be to serve the MHTML document with text/plain and inside have the different multi-parts: css and images.
I don’t have a test page for you to try, but check some of the URLs in the comments above.
Thanks and please drop a comment if you can/cannot make it work.
S
September 29th, 2009 at 6:54 am
This thread brings to our attention that sometimes IE7 can not save an archive file (mht) which seem to be related to my problem above, since what we are trying to accomplish actually is to include a web archive (mhtml) in the CSS.
http://groups.google.com/group/microsoft.public.internetexplorer.general/browse_thread/thread/43f0ebcf38372f5d/60b609a62697af29?hl=en&q=%22web+page+could+not+be+saved%22+group:microsoft.public.*#60b609a62697af29
Could this be it? I really can not have customers re-install IE7…
October 6th, 2009 at 1:05 am
[...] they’re not supported in IE7 and earlier. Recent blogs from web dev performance rock stars Stoyan Stefanov and Hedger Wang discuss a workaround for early versions of IE using MHTML. Aptimize has already [...]
October 6th, 2009 at 1:43 am
[...] This post was Twitted by zigazou [...]
October 6th, 2009 at 2:44 am
@Sander van Veen You are right, this would have been the other option. In this case that image-gallery backend was already existing and I just revamped the frontend-part. Sprites would have worked OK here (if they would hit the server’s memory-limit while beeing built). But in CSS I definitely prefer dataURIsation over sprites as I now have a setup where I can code as usual and PHP transforms everything on the fly (MHTML for IE < 8, dataURIs for the rest). Sprites are more taxing on the server and take longer to autobuild and, depending on the combination of images, are not too effective in using their pixel-space.
October 27th, 2009 at 8:04 am
[...] fair amount written about data URIs recently: my colleague Stoyan Stefanov has written a couple of posts about data URIs, and my former colleague Hedger Wang also penned a post about how to use data URIs [...]
October 28th, 2009 at 8:02 am
[...] Stoyan, http://www.phpied.com/data-urls-what-are-they-and-how-to-use/, http://www.phpied.com/mhtml-when-you-need-data-uris-in-ie7-and-under/ R Reid, Detecting IE 8 Compatibility Modes with [...]
October 29th, 2009 at 4:04 am
Hi, thanks for the useful post! just wonder how it’s going to work if I embed the css within the html file? I have twisted the mhtml link in the css many ways but couldn’t get it work. Thanks again!
November 2nd, 2009 at 11:48 am
Excellent technique, but executed with conditional comments instead of stuffing everything in the same CSS file, you avoid all of the drawbacks you mention without adding any (to my knowledge, at least) new ones.
November 5th, 2009 at 5:21 am
Awesome! But why not just use the MHTML method for all browsers, instead of implementing both?
November 5th, 2009 at 5:42 am
nevermind… mhtml is not supported…
November 16th, 2009 at 1:52 pm
[...] in Internet Explorer 6 & 7, where data: URIs aren’t supported. (See the blog post from Stoyan Stefanov and examples from Hedger Wang for more info on this MHTML [...]
November 16th, 2009 at 4:33 pm
[...] only came across the MHTML image hack over the weekend, while listening to @jeresig on the new jQuery podcast (incidentally not the only [...]
November 26th, 2009 at 11:15 am
You can use online generator of data:uri css sprites
http://duris.ru/lang/en/
Supports MHTML for IE<8 & data:URI for other browsers
January 13th, 2010 at 3:57 pm
Has anybody successfully used this technique on a site protected with SSL? We are encountering a problem where IE7/8 is detecting the page contains “mixed content” and pops up that nasty Security Warning dialog even though all of the requests are over HTTPS (confirmed with wireshark).