Ilence Ye

提供 fallback image

在获取 favicon 时,存在一种情况是,对于有些域名,favicon service 爬取 favicon 失败,比如下面这个例子:

html
<img
	src="https://www.google.com/s2/favicons?domain=【】&sz=【】"
	alt="favicon"
/>

这时 favicon service 通常会给你返回一个 fallback image,但我的需求是,当获取 favicon 失败时,显示大写的域名首字母。那么这个需求要如何实现呢?

一、

首先,我们需要监听 imgerror 事件error 事件会在一个 resource 加载失败或无法使用时出发,比如,图片无法找到或无效时。

html
<img
	data-favicon
/>
js
document.querySelectorAll("img[data-favicon]").forEach((img) => {
	img.addEventListener("error", () => {
		// Fired when the image can't be found or is invalid.
	});
});

这里我们先给 img 添加了一个 data-favicon 属性,方便我们在脚本里选中该元素。然后遍历所有找到的目标元素,给它们分别绑定 error 事件。

二、

然后,我们先给 img 元素添加 data-fallback 属性。为了演示作用,下面这里的值是硬编码的。实际项目中,如果是用 React 的话,你可能是这样来设定的 -- data-fallback={new URL(url).hostname.charAt(0)}

html
<div class="favicon-wrapper">
	<img
		data-fallback="F"
	/>
</div>

然后,在 error 事件的处理程序里,我们通过 dataset.fallback 来读取 fallback value,并给父元素添加一个 data-fallback 属性,值设定为刚才读取到的 fallback value。

js
img.parentElement.dataset.fallback = img.dataset.fallback;

三、

最后一步就要靠 CSS 来实现了。当父元素带有 data-fallback 属性时,我们先将 img 元素给隐藏掉,然后我们就可以绘制自己想要的 fallback shape 了。这里是通过伪元素来实现的。

css
.favicon-wrapper[data-fallback] {
  & img {
    display: none;
  }

  &::before {
    content: attr(data-fallback);
    color: gray;
    font-size: 64px;
    font-weight: 800;
    text-transform: uppercase;
    transform: rotate(-10deg);
  }
}