这篇博客算是完全的笔记了,记录一下平常中不怎么注意的img标签的一些事。
昨天看到这篇Handling broken images with the service worker文章,这文章中有另外提到用伪元素处理加载图片失败的样式问题。当图片加载失败的时候,并不是手足无绰的对着丑陋的发呆,尽管有alt属性可以做个解释,但我更觉得是丑上加丑。因为img是个可替换元素,先来回顾一下什么是可替换元素:替换元素是浏览器根据其标签的元素与属性来判断显示具体的内容。
那这时候当img加载图片失败的时候,它就可以被它的伪元素样式所覆盖(img:兄弟我这出了点事情,你帮我顶一下)。引用上边文章中的例子:
img { /* Same as first example */ }
img:after {
content: "\f1c5" " " attr(alt);
font-size: 16px;
font-family: FontAwesome;
color: rgb(100, 100, 100);
display: block;
position: absolute;
z-index: 2;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #fff;
}
显示出的效果:
这样一来确实是比之前丑陋的失败图片好看一点,在这基础上大家可以自由发挥,可以让图片变的更加优美点。用伪元素替换img加载失败的方案基本上是可行的,也不会特别 复杂和难以理解。好的东西都是会有那么一点的瑕疵:兼容性并不是完美的,在Safari 浏览器以及ios系统上不太理想。
于是上边提到的那篇博客利用了service worker fetch事件(关于service worker可以看这里),具体代码:
self.addEventListener('fetch', (e) => {
e.respondWith(
fetch(e.request)
.then((response) => {
if (response.ok) return response;
// User is online, but response was not ok
if (isImage(e.request)) {
// Fetch the broken image placeholder instead
return fetch("/broken.png");
}
})
.catch((err) => {
// User is probably offline
if (isImage(e.request)) {
// do something
}
}) // end fetch
)
});
这个方法只适用于在线,当用户离线时候,就无法保存下broken图片,于是就有了下面的方法:
self.addEventListener('install', (e) => {
self.skipWaiting();
e.waitUntil(
caches.open("precache").then((cache) => {
// Add /broken.png to "precache"
cache.add("/broken.png");
})
);
});
self.addEventListener('fetch', (e) => {
e.respondWith(
fetch(e.request)
.then((response) => {
if (response.ok) return response;
// User is online, but response was not ok
if (isImage(e.request)) {
// Get broken image placeholder from cache
return caches.match("/broken.png");
}
})
.catch((err) => {
// User is probably offline
if (isImage(e.request)) {
// Get broken image placeholder from cache
return caches.match("/broken.png");
}
})
)
});
介绍完了对于加载图片失败的优化,接下来就聊聊关于图片懒加载。大家或多或少都对图片懒加载有点了解,无非就是当浏览器可视区域滚动到图片所在的区域时,一般选择把img标签中的src中的URL替换成data-src中的URL。也就是说,本来这图片的src可能根本不存在,于是就会产生一个上面提到的原始的丑陋图片(当然你可以用上面提到的方案优化你的图片)。当img标签的URL被替换成正确的路径时,图片就会开始渲染,这是图片所呈现的高度以及宽度会和之前加载失败时候的高度宽度不一致(如果你没强制去设置的话),那么就会带来浏览器最不想发生的重排重绘。
Preventing Content Reflow From Lazy-Loaded Images这篇文章讲述了四种防止图片懒加载导致的重拍重绘的解决办法。
利用伪元素去支撑宽高:这方法和之前优化加载失败图片的方式如出一辙,两个的原理也是相同的,都是因为img无法加载到正确的图片时候伪元素就有了发挥的空间。
利用BASE64位编码数据放在src上支撑宽高:先举个例子:
相信很多人对这写法不会陌生吧,webpack打包image的时候,在给png这类图片用url-loader解析的时候需要有limit属性来限制打包进webpack中图片的大小。使用png-pixel网站生成具有相同宽高的透明背景。这种方案兼容性会比使用伪元素的兼容性好一点,也不需要在css中写一堆烦人的样式。但是每次都要根据图片去生成一个BASE64的透明背景也是挺烦人的。
使用BASE64转换svg图片:这个方案只能说是上一个方案的优化,因为还是要转换BASE64。两者的不同点在于:svg图片占用空间会小于上述的png图片。
而且随着比例的增加,所省的空间也就越多。 should not use base64 encoding with SVG这篇文章大概意思是说,使用BASE64位编码后,字符变大导致存储空间变多。最大的没必要的就是用BASE64来编码svg,因为svg语法中并没有一些奇形怪状的字符在里面。
使用URL编码:既然svg空间小于png,而且svg没有必要使用BASE64编码。那就直接放上去好了吧,但是URL还是会自动去编码,有可能会去BASE64编码还长。
可能有人就纳闷了,那我难不成在选择URL编码或者BASE64编码的时候还得去比较一下?那这真的是很白痴的行为,大神们总会在你之前就想到了这个办法,Optimizing SVGs in data URIs,这篇文章深入的讲解了如何在URL编码的时候进行优化,一个核心就是将属性节点中的双引号全部改成单引号,因为只有单引号是允许出现在URL当中不会被编码。
结束语:用行动去打破平衡,用努力去充实自我