notes
notes copied to clipboard
如何美化图片缺失的默认样式
在谷歌浏览器中,当图片加载失败时呈现如下
<img class="img" src="head.jpg" alt="head">
很难看不是吗?
现有的解决方法
网上这类问题的解决方式大多都是直接监听onerror
方法
<img class="img" src="head.jpg" alt="head" onerror="this.src='xx.jpg'">
这种写法最为简单,但是风险也高,如果赋值的src
也失败的话,那就无限循环了
当然,可以设定this.onerror=null
只执行一次
<img class="img" src="head.jpg" alt="head" onerror="this.src='xx.jpg';this.onerror=null;">
虽然这样可以阻止无限循环,但是如果第二次加载失败,就回到了最初状态,还是很难看
稍微好一点的方法
在上面的基础上,如何更好的优化呢?首先我们必须保证onerror
里面的图片一定要加载成功。如果保证成功呢?线上的肯定不行,可以设置一张base64
的图片,这样就能保证一定加载成功了
<img class="img" src="head.jpg" alt="head" onerror="this.src='data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MTIgNTEyIj4gPHBhdGggZD0iTTQ2NCA2NEg0OEMyMS40OSA2NCAwIDg1LjQ5IDAgMTEydjI4OGMwIDI2LjUxIDIxLjQ5IDQ4IDQ4IDQ4aDQxNmMyNi41MSAwIDQ4LTIxLjQ5IDQ4LTQ4VjExMmMwLTI2LjUxLTIxLjQ5LTQ4LTQ4LTQ4em0tNiAzMzZINTRhNiA2IDAgMCAxLTYtNlYxMThhNiA2IDAgMCAxIDYtNmg0MDRhNiA2IDAgMCAxIDYgNnYyNzZhNiA2IDAgMCAxLTYgNnpNMTI4IDE1MmMtMjIuMDkxIDAtNDAgMTcuOTA5LTQwIDQwczE3LjkwOSA0MCA0MCA0MCA0MC0xNy45MDkgNDAtNDAtMTcuOTA5LTQwLTQwLTQwek05NiAzNTJoMzIwdi04MGwtODcuNTE1LTg3LjUxNWMtNC42ODYtNC42ODYtMTIuMjg0LTQuNjg2LTE2Ljk3MSAwTDE5MiAzMDRsLTM5LjUxNS0zOS41MTVjLTQuNjg2LTQuNjg2LTEyLjI4NC00LjY4Ni0xNi45NzEgMEw5NiAzMDR2NDh6Ij48L3BhdGg+IDwvc3ZnPg=='">
尽管能保证加载成功,但是这html
结构也太难看了吧,洋洋洒洒的一大片。
进一步,我们可以设置一张很小的图片,比如1像素的gif。其实只要图片存在,就不会出现文章头部的那张加载失败的图片。然后,再设置背景图片,就可以达到默认图的效果了
<img class="img" src="head.jpg" alt="head" onerror="this.src='data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';">
<!--是不是短了很多呢-->
img{
background:url('head.jpg') #eee
}
即使背景图加载失败,也不会留下那张丑陋的默认图,是不是好了很多呢?
如果你有代码洁癖,肯定忍受不了在html
添加内联脚本,那么,可以将脚本提取出来
<img class="img" src="head.jpg" alt="head" onerror="error">
function error(){
this.src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
}
你看能觉得onerror
写在html
上还是有点不雅,而且对这类全局函数的使用也不够放心,可以试试自定义标签
class XImg extends HTMLImageElement {
constructor() {
super();
}
connectedCallback() {
this.addEventListener('error',()=>{
this.src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
})
}
}
customElements.define('x-img', XImg, { extends: 'img' })
然后只需在html
添加一个is
属性就可以了,无论是页面上存在的元素,还是后来新添加的元素都起作用。
<img class="img" src="head.jpg" alt="head" is="x-img">
是不是有点悄无声息的感觉?
CSS解决方式
上面都是js的相关解决方式,可以说没有js解决不了的,只是看实现优不优雅。
对于img
标签来说,正常情况选是不能包含伪元素(::before
、::after
)的,但是,当图片加载失败的时候,又可以包含了。
img::after{
content:'-error'
}
有了伪元素,就可以搞很多事情了。
这里有以下思路:
- 把默认图覆盖
- 把默认图挤走
- ??
先看第一个,img
设置相对定位,伪元素设置绝对定位就可以了
img{
position:relative;
}
img::after{
content:attr(alt);/*可以添加一些提示*/
position:absolute;
left:0;
top:0;
width:100%;
height:100%;
background:#eee;/*用一个实色背景覆盖*/
/*其他美化样式*/
}
第二种思路,可以用::before
把img
内部的shadow-dom
挤下去(默认图就在shadow-dom
里面)
然后设置img
超出隐藏即可
img{
overflow:hidden;/*超出隐藏*/
}
img::before{
content:attr(alt);
height:100%;/*设置高度100%即可*/
/*其他美化样式*/
}
可以看出第二种方式无需背景色覆盖,代码量也更少,推荐。
其他解决方式
如果对语义没有严格要求的话,可用背景图片来代替
<div class="img"></div>
.img{
background:url(1.jpg) url(默认图.jpg)
}
多背景会叠加,可以把默认图放在最后,这样在页面上显示为最底层,而且就算加载失败,背景图也没有默认图标。
还有一种html
解决方式。object
标签也可以设置图片资源,而且,当资源加载失败时才会显示子节点内容,这点和img
有点类似。
<object class="img" data="pic.jpg" type="image/jpg">
<!--加载失败时才会显示这里的内容-->
</object>