Data URI——也就是图片转成代码插入网页
Data URI
Data URI是由RFC 2397定义的一种把小文件直接嵌入文档的方案。目的是将一些小的数据,直接嵌入到网页中,从而不用再从外部文件载入,目前,IE8、Firfox、Chrome、Opera浏览器都支持这种小文件嵌入。通过如下语法就可以把小文件变成指定编码直接嵌入到页面中:
data:[<MIME-type>][;charset="<encoding>"][;base64],<data>
- MIME-type:指定嵌入数据的MIME。其形式是
[type]/[subtype]; parameter
,比如png图片对应的MIME是image/png。parameter可以用來指定附加的信息,更多情況下是用于指定text/plain和text/htm等的文字编码方式的charset参数。默认是text/plain;charset=US-ASCII。 - charset=”<encoding>”: 指定数据的字符集
- base64:声明后面的数据的编码是base64的,否则数据必须要用百分号编码(即对内容进行urlencode),默认编码方案由base64 指定,如果缺省,数据必须使用 URL Encoding[2] 转换为有效 ASCII 格式。如果 <MIME-type> 缺省,默认参数为 text/plain 类型,字符集为 US-ASCII 方案
- base64简单地说,它把一些 8-bit 数据翻译成标准 ASCII 字符,网上有很多免费的base64 编码和解码的工具,在PHP中可以用函数base64_encode() 进行编码,如echo base64_encode(file_get_contents(‘wg.png’)),因为Url是一种基于文本的协议,所以gif/png/jpeg这种二进制属于需要用base64进行编码。换句话说,引入base64以后,就可以支持任意形式的数据格式。
- [1] MIME: http://zh.wikipedia.org/wiki/MIME
- [2] URL Encoding: http://www.w3schools.com/TAGS/ref_urlencode.asp
- [3] MHTML: http://en.wikipedia.org/wiki/Mhtml
在上个世纪HTML4.01引入了Data URI方案,到今天为止除了IE6和IE7之外,所有主流浏览器都支持,但IE8对Data URI的支持还是有限制的,只支持object(仅是图片时)、img、input type=image、link和CSS中的URL,且数据量不能大于32K。
优点:
- 减少HTTP请求数,没有了TCP连接消耗和同一域名下浏览器的并发数限制。
- 对于小文件会降低带宽。虽然编码后数据量会增加,但是却减少了http头,当http头的数据量大于文件编码的增量,那么就会降低带宽。
- 对于HTTPS站点,HTTPS和HTTP混用会有安全提示,而HTTPS相对于HTTP来讲开销要大更多,所以Data URI在这方面的优势更明显。
- 可以把整个多媒体页面保存为一个文件。
缺点:
- 无法被重复利用,同一个文档应用多次同一个内容,则需要重复多次,数据量大量增加,增加了下载时间。
- 无法被独自缓存,所以其包含文档重新加载时,它也要重新加载。
- 客户端需要重新解码和显示,增加了点消耗。
- 不支持数据压缩,base64编码会增加1/3大小,而urlencode后数据量会增加更多。
- 不利于安全软件的过滤,同时也存在一定的安全隐患。
MHTML
MHTML是MIME HTML (Multipurpose Internet Mail Extension HTML)的缩写,是由RFC 2557定义的把一个多媒体的页面所有内容都保存到同一个文档解决方案。这个方案是由微软提出从IE5.0开始支持,另外Opera9.0也开始支持,Safari可以把文件保存为.mht(MHTML文件的后缀)格式,但不支持显示它。
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》。
应用
Data URI和MHTML两者的配合可以完整的解决所有的主流浏览器,它们由于无法被缓存和重复利用的缺陷,所以并不适合直接在页面中使用,但在CSS和JavaScript文件中对图片适当地使用有非常大的优越性:
- 大大减少请求数,现在大型网站的CSS引用了大量的图片资源。
- CSS和JavaScript都可以被缓存,间接的实现了数据的缓存。
- 利用CSS可以解决Data URI的重复利用问题
- 告别CSS Sprites,CSS Sprites的出现是为了减少请求数,但它除了带来在不确定情况下的异常外,CSS Sprites还需要人为的图片合并,即使有合并工具也依旧必须人为地在如何有效的拼图上耗费大量的时间,并带来维护的困难。当你遵循一定的设计原则后, 你就可以完全抛弃CSS Sprites来编写CSS,最后使用工具在上传到服务器环节把图片转换成Data URI和MHTML,如《利用data-uri合并样式表和图片》中用python实现的工具,这可以节约大量的时间。
- base64编码把图片文件增加了1/3,Data URI和MHTML同时使用相当于增加了2/3,但CSS和JavaScript可以使用gzip压缩,其可以节省2/3的数据量,所以使用gzip压缩后的最终数据量是
(1 + 1/3) * 2 * (1/3) = 8/9
,所以最终流量是减少的。
1)在网页上显示出来的标准方法是:
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAGElEQVQIW2P4DwcMDAxAfBvMAhEQMYgcACEHG8ELxtbPAAAAAElFTkSuQmCC" />
换句话说我们把图像文件的内容内置在 HTML 文件中,节省了一个 HTTP 请求。
2)在 CSS 中使用
body { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAGElEQVQIW2P4DwcMDAxAfBvMAhEQMYgcACEHG8ELxtbPAAAAAElFTkSuQmCC");}
为了方便在CSS中实现Data URI和MHTML,我写了一个Data URI & MHTML 生成器,你可以看利用其生成Data URI & MHTML应用实例。
在CSS文件中使用应用MHTML时URL必须使用绝对路径,导致非常不灵活,所以可以考虑使用CSS expression来解决(DEMO),比如:
/* http://old9.blogsome.com/2008/10/26/css-expression-reloaded/ http://dancewithnet.com/2009/07/27/get-right-url-from-html/ */ *background-image:expression(function(ele){ ele.style.backgroundImage = 'url(mhtml:' + document.getElementById('data-uri-css').getAttribute('href',4) + '!03114501408821761.gif)'; }(this));
兼容 IE6 & IE7
通过 CSS Hacks 结合 MHTML[3] 方案解决 IE6 和 IE7 不支持 DataURI 的情况。
/* Content-Type: multipart/related; boundary="_ANY_SEPARATOR" --_ANY_SEPARATOR Content-Location:somestring Content-Transfer-Encoding:base64 iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAA[...snip...]SuQmCC --_ANY_SEPARATOR-- */ #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); }
/*Content-Type: multipart/related; boundary="_"
--_ Content-Location:<identifier> Content-Transfer-Encoding:base64
<data> */ selector{*background:url(mhtml:<stylesheet>!<identifier>);}
其中: _: 指定分隔符 (任意字符串)
identifier: 指定内容位置标识符
stylesheet: 指定样式表绝对路径
完整代码示例
/* 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== --_ANY_STRING_WILL_DO_AS_A_SEPARATOR-- */ #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;}
在线生成base64编码的图片
http://dancewithnet.com/lab/2009/data-uri-mhtml/create.php
来自 Nicholas C. Zakas 的 DataURI 自动化工具,命令行格式:
java -jar datauri-x.y.z.jar -o <output filename> <input filename>