Data URI 科普
笔者对本文的定位是实践操作型,所以一些理论基础只点到为止。首先 Data URI 是什么? 引用 Wikipedia 上对其的解释:
Data URI 是一种提供让外置资源的直接内嵌在页面中的方案。这种技术允许我们只需单次 HTTP 请求即可获取所有需要引用的图片与样式资源,
并因无需多次请求资源而变的高效。
在 RFC2397(http://tools.ietf.org/html/rfc2397)中定义了它格式规范:
data:[<mime type>][;charset=<charset>][;base64],<encoded data>
Data URI 初探
看格式规范貌似不是很友好,我们以内嵌图片为例:
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA
AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO
9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot">
data:image/png;base64, 是固定的格式, image/png 是图片的MIME类型,base64是数据编码方式。这里还有必要指出下Base64 编码后的数据会比原始数据大 4/3 左右,这与Base64 编码算法有关。 如需使用在电子邮件中,根据 RFC 822 规定,每 76 个字符,还需要加上一个回车换行,此时编码后数据长度大约为原长的135.1%。
为验证理论的我们做如下的测试,分别对不同尺寸的图片进行Base64编码,与我们的预期一致,比原始数据增长了 1/3 :
图片尺寸 | 原始大小 | Base64大小 | 增长率 |
:-----------|:------------|:-------------|:-------------|
16*16 | 618 | 824 | 34.2%
24*24 | 1,063 | 1,420 | 33.6%
32*32 | 1,615 | 2,156 | 33.5%
42*42 | 2,510 | 3,348 | 33.4%
48*48 | 2,892 | 3,856 | 33.3%
96*96 | 8,217 | 10,956 | 33.3%
350*350 | 49,899 | 66,532 | 33.3%
图片是使用 Data URI 最常用的情景,但 Data URI 是与资源类型无关的规范,您也可以使用 Data URI 内嵌其他资源:
var cvs = ‘data:text/csv;charset=utf-8,‘ + encodeURIComponent(csv);
var html = ‘data:text/html;charset=utf-8,‘ + encodeURIComponent(html);
Data URI 兼容性
在前端,浏览器兼容性几乎每个技术都逃不过的话题,检阅 Data URI 的兼容性:
- Firefox 2+
- Opera 7.2+
- Chrome++
- Safari++
- Internet Explorer 8+
大部分主流浏览器都早已支持 Data URI,IE8 虽支持但其最大长度不能超过32K的数据,在 IE9 下已解除此限制,IE 详细的文档可细读微软官方文档。 剩下的依旧是面对在国内还是 A 类浏览量的 IE 6/7, 我们可以采用与 Data URI 类似的 MHTML(笔者认为其设计上比 Data URI 是更优秀的,考虑到了内嵌数据的重用). MHTML 详细的介绍不在本文的讨论范围,但需要指出的是微软在 2011 年发布了 MHTML 中的漏洞可能允许信息泄露 的补丁, 将造成 MHTML 无法被引用的问题,所以在 IE 中使用 MHTML 的方案会有极大的风险,权且当扩展知识面不推荐采用。
- http://technet.microsoft.com/zh-CN/security/advisory/2501696
- http://www.microsoft.com/china/security/bulletins/ms03-014.mspx
Data URI 最佳实践
在 Data URI 转换之前我们不进行图片合并,而是直接使用小图片,如此省去了合图定位的麻烦,
background-image:url("data:image/png;base64,iVBORw0KGgoAAA...ElFTkSuQmCC");
*background-image:url(http://cdn.example.com/foo.gif);
比较数据:
图片尺寸 | 原始大小 | Base64大小 | Gzip大小 | Gzip压缩率 | 增长率 |
:-----------|:------------|:-------------|:-------------|:-------------|:-------------|
16*16 | 618 | 824 | 668 | 81.1% | 108.8%
24*24 | 1,063 | 1,420 | 1,119 | 78.8% | 5.3%
32*32 | 1,615 | 2,156 | 1,670 | 77.5% | 3.9%
42*42 | 2,510 | 3,348 | 2,568 | 76.7% | 2.3%
48*48 | 2,892 | 3,856 | 2940 | 76.2% | 1.7%
96*96 | 8,217 | 10,956 | 8304 | 75.8% | 1.1%
350*350 | 49,899 | 66,532 | 50,095 | 75.3% | 0.4%
DIY 生成工具
Node 是名副其实的前端开发得力助手,只用3行代码就能让一张图片转换成Base64编码:
var body = fs.readFileSync(‘./foo.png‘, ‘binary‘); // 输入
var image = new Buffer(body, ‘binary‘).toString(‘base64‘); // base64编码
var base64 = ‘data:image/png;base64,‘ + image; // 输出
Datauri 格式数据需要更多CPU计算来呈现图片,也许在性能稍弱的PC上,额外请求图片的方案可能更早的渲染出图片,尤其在移动端有限CPU的情景下,一定要慎用。
这里折中方案是限定转换的条件,只有小于 2K 的小图才被转换成Base64编码, 2K 是比较推荐的阀值