” 将内嵌图像合并到您的(缓存的)样式表中是减少HTTP请求并避免增加页面大小的一种方法。您网站的每日访问者中有40-60%的人使用了空的缓存。 为这些初次访问的用户提供快速的页面是改善用户体验的关键 。”
数据URI格式指定为
data:[<mime type>][;charset=<charset>][;base64],<encoded data>
我们只对图像感兴趣,因此mime类型可以是例如image / gif,image / jpeg或image / png。 图片应省略字符集。 编码由; base64指示。 有效数据URI的一个示例:
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA
AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO
9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot">
像上面的示例一样,带有嵌入式图像HTML片段并不是很有趣,因为它们没有被缓存。 CSS文件(样式表)中的数据URI与CSS文件一起缓存,这带来了很多好处。 Wikipedia中描述的一些优点:
- 嵌入式数据不需要HTTP请求和标头流量,因此,每当将内联内容编码为数据URI的开销小于HTTP开销时,数据URI消耗的带宽就会减少。 例如,对于600字节长的图像,所需的base64编码将为800字节,因此,如果HTTP请求所需的开销超过200字节,则数据URI会更有效。
- 对于传输许多小文件(每个文件少于几千字节),这可能会更快。 TCP传输往往开始缓慢。 如果每个文件都需要一个新的TCP连接,则传输速度受往返时间而不是可用带宽的限制。 使用HTTP keep-alive可以改善这种情况,但可能无法完全缓解瓶颈。
- 当浏览安全的HTTPS网站时,网络浏览器通常要求通过安全连接下载网页的所有元素,否则由于安全元素和不安全元素的混合使用,会通知用户降低的安全性。 在配置错误的服务器上,HTTPS请求比普通的HTTP请求具有大量开销,因此在这种情况下将数据嵌入数据URI可能会提高速度。
- 通常将Web浏览器配置为仅与域建立一定数量(通常两个)的并发HTTP连接,因此,内联数据可以释放下载连接以用于其他内容。
此外,数据URI比精灵更好。 组织为CSS精灵的图像(许多小图像合并为一个大图像)很难维护。 维护费用高。 想象一下,您想更改子画面中的一些小图像,它们的位置,大小,颜色或其他任何内容。 好了,有一些工具可以生成精灵,但是以后的更改并不容易。 特别是大小的改变会引起所有位置的偏移,并且会导致很多CSS改变。 而且请不要忘记– Sprite仍然需要一个HTTP请求:-)。
哪些浏览器支持数据URI? 所有现代浏览器都支持数据URI:基于Gecko的浏览器(Firefox,SeaMonkey,Camino等),基于WebKit的浏览器(Safari,Google Chrome),Opera,Konqueror,Internet Explorer 8和更高版本。 对于Internet Explorer 8,数据URI必须小于32 KB。 Internet Explorer 9没有32 KB的限制。 IE 5-7版本缺乏对数据URI的支持,但是有MHTML –当您需要IE7及以下版本中的数据URI时。
有工具可以帮助自动嵌入数据URI吗? 是的,有一些工具。 最受欢迎的是命令行工具CSSEmbed 。 特别是如果您需要支持旧的IE版本,则可以使用此命令行工具来处理MHTML。 作为PrimeFaces Extensions项目一部分的用于Web资源优化的Maven插件现在也支持数据URI。 该插件允许在构建时在样式表中嵌入参考图像的数据URI。 此Maven插件不支持MHTML。 这是有问题的,因为您需要单独包含带有条件注释CSS文件-适用于IE7和更低版本以及所有其他浏览器。 如何转换为数据URI?
- 插件读取CSS文件的内容。 一个特殊的java.io.Reader实现在CSS文件中查找令牌#{resource […]}。 这是JSF 2中图像引用的语法。令牌应以#{resource [开头,并以]}结尾。 内部内容包含JSF语法中的图像路径。 从理论上讲,我们还可以支持其他令牌(它们是可配置的),但是我们对这种支持不感兴趣:-)示例:
.ui-icon-logosmall { background-image: url("#{resource['images/logosmall.gif']}") !important; } .ui-icon-aristo { background-image: url("#{resource['images:themeswitcher/aristo.png']}") !important; }
- 在下一步中,将定位每个背景图像的图像资源。 图像目录是根据JSF 2规范指定的,适用于WAR和JAR项目。 这些是$ {project.basedir} / src / main / webapp / resources和$ {project.basedir} / src / main / resources / META-INF / resources。 尝试在这些目录中找到每个图像。
- 如果在指定目录中找不到该图像,则不会对其进行转换。 否则,图像将编码为base64字符串。 仅当数据URI字符串小于32KB时才执行编码,以支持IE8浏览器。 大于该数量的图像不会被转换。 数据URI看起来像
.ui-icon-logosmall { background-image: url("data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgA ... ASUVORK5CYII=") !important; } .ui-icon-aristo { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgA ... BJRU5ErkJggg==") !important; }
pom.xml中的配置很简单。 要启用此功能,请将useDataUri标志设置为true。 例:
<plugin>
<groupId>org.primefaces.extensions</groupId>
<artifactId>resources-optimizer-maven-plugin</artifactId>
<configuration>
<useDataUri>true</useDataUri>
<resourcesSets>
<resourcesSet>
<inputDir>${project.build.directory}/webapp-resources</inputDir>
</resourcesSet>
</resourcesSets>
</configuration>
</plugin>
理论足够。 现在,我将描述一个练习部分。 我将展示一些测量结果,屏幕截图,并给出提示,其中应该显示多大的图像,应该放置CSS的位置,带有数据URICSS文件的大小以及GZIP过滤器是否可以帮助您。 继续阅读。
第一个问题是是否值得将数据URI放在样式表中? 是的,值得。 首先,我想为您指出这篇很棒的文章“ CSS图像的数据URI:更多测试,更多问题 ”,您可以在其中尝试针对您的位置测试所有这三种情况。 延迟时间因您所在的位置而异。 但是您会看到一种趋势,即包含数据URI的网页加载速度更快。 我们可以看到使用数据URI实现更好性能的主要技巧之一:
将CSS分为两个文件–一个文件包含主要数据,另一个文件仅包含数据URI,第二个文件放置在页脚中。 “在页脚中”表示靠近HTML正文标签。 由于采用渐进式渲染,因此页面渲染的感觉要快得多。 在第二篇文章中,您可以看到该技术确实可以加速页面渲染。 页脚中的样式表会产生很好的效果,即大型图像与数据URI样式表并行下载。 为什么? 好吧,浏览器认为放置在页脚中的内容不会对包含文件上方的页面结构产生任何影响,并且不会阻止资源加载。 我还读到,在这种情况下,所有浏览器(旧IE版本除外)都立即呈现页面,而无需等到带有数据URICSS加载完毕。 据我所知,同样适用于JavaScript文件。 将CSS文件放在页面页脚中是否完全有效? 嗯,在HTML规范中不建议这样做。 但这在实践中是有效的,在特殊情况下也不是一件坏事。 关于Stackoverflow有一个有趣的讨论:“ 将CSS include放在主体中间有多糟糕? ”
第二个技巧是将数据URI用于最大为1-2 KB的小图像。 对于大型图像,不应该使用数据URI。 大图像具有非常长的数据URI字符串(base64编码的字符串),这可能会增加CSS文件的大小。 较大的文件可能会阻止其他文件的加载。 请记住,浏览器有连接限制。 他们通常可以打开2-8个圆锥形连接到相同的域。 这意味着只能同时并行加载2-8个文件。 阅读了互联网上的一些评论后,我得到了关于1-2 KB图像的假设的认可。
我们可以通过使用GZIP过滤器来软化此行为。 GZIP筛选器可减少资源大小。 我已经读过,有时编码为数据URI的图像的大小甚至比原始图像的大小还要小。 GZIP过滤器被添加到CSS,JavaScript和(X)HTML文件之类的Web资源。 但是不建议将其应用于图像和PDF文件,例如,不是编码图像不会通过文件管理器,而是CSS文件正在处理。 在99%的情况下,如果gzip CSS文件,则生成的大小与常规图像URL参考大致相同! 这是第三个技巧–使用GZIP过滤器。
我想现在显示我的测试结果。 我的测试环境:Kubuntu Oneiric上的Firefox 11。 我准备了带有31张图像的PrimeFaces Extensions展示柜,这些图像已添加到起始页。 这些图像以PNG格式显示小主题图标。 每个图像的大小相同,均为30 x 27像素。 以千字节为单位的大小范围为1.0 – 4.6 KB。 不带数据URICSS文件为4.8 KB,带数据URICSS文件为91.6 KB。 顺便说一下,CSS文件通常包含在HTML标头部分中。 我在带有Jetty 8服务器的VPS上部署了带有和不带有数据URI的展示柜。 首先没有GZIP文件管理器。 我清除了浏览器缓存并为每个展示柜打开了Firebug。 结果如下:
没有数据URI:
65个请求。 页面加载时间3.84s(加载:4.14s)。
这意味着文档准备事件在3.84 sek之后发生。 并在4.14秒后打开窗口。 随后对同一页面的调用(资源是从浏览器缓存中获取的)耗时577毫秒,571毫秒,523毫秒,...
使用数据URI:
34个请求。 页面加载时间3.15秒(加载时间:3.33秒)。
这意味着,在3.15秒之后,发生了更少的请求(记住31张嵌入式图像),文档就绪事件。 并在3.33瑞典克朗之后加载窗口。 随后对同一页面的调用(资源是从浏览器缓存中获取的)花费了513 ms,529 ms,499 ms等...
后续调用(页面刷新)并没有太大的区别,但是第一次访问时有很大的区别。 特别是onload事件通过数据URI发生得更快。 难怪。 准备好文档后正在加载图像。 由于无法并行加载它们(打开的连接数受到限制),因此它们被阻塞。 我从Google Chrome Web Inspector拍摄了一些照片。 在下面,您可以看到没有数据URI的第一种(常规)情况下图像(vader.png)的计时。
第二种情况是将同一图像编码为数据URI。
您会在第二张图片中看到完全没有任何障碍。 在我的情况下,使用GZIP筛选器进行的测试没有太大影响(不知道为什么,也许我没有太多资源)。 在几次测试中使用空缓存后的平均时间:
没有数据URI:
65个请求。 页面加载时间3.18秒(加载时间:3.81秒)。
使用数据URI:
34个请求。 页面加载时间为3.03s(加载时间:3.19s)。
参考: 高性能Webapp。 使用数据URI。 实践 , 高性能Webapps。 使用数据URI。 理论来自我们JCG伙伴奥列格Varaksin在软件开发的思考博客。
翻译自: https://www.javacodegeeks.com/2012/04/high-performance-webapps-data-uris.html