网站分享插件Share.js微信分享图片缺少alt属性完美修复方法

技术教程 fuwa
35

事情是这样的。

前阵子在搞一个网站,接入了 Share.js 这个分享插件,微博、QQ、微信、豆瓣这些渠道都挺顺畅的,分享出去链接也都能正常跳转。

结果那天无聊,跑了一下 Google Lighthouse 做无障碍检测,好家伙,给我弹出来一个警告。

图片缺少 alt 属性。

点进去一看,是微信分享弹窗里那张二维码图片,一张 base64 生成的二维码,src 长得要命,但 alt 属性。空的。啥也没有。

我当时就愣住了。

不是,这玩意怎么会没 alt 呢?无障碍访问是最基本的 web 标准啊,视障用户靠屏幕阅读器读网页的时候,读到一张没 alt 的图片,它只能说「图片」,用户压根不知道这是啥。

这不行。

于是就钻进去看了一下 Share.js 的源码,搞清楚了这个问题的根因,顺便给修了。如果你也在用这个插件,大概率也会遇到同样的问题,这篇文章就把排查过程和修复方法完整走一遍。

网站分享插件Share.js微信分享图片缺少alt属性完美修复方法

Share.js 是怎么生成微信二维码的

先简单说一下 Share.js 的微信分享机制。

其他渠道(微博、QQ、豆瓣这些)都是直接拼一个分享链接,打开新窗口完事。但微信比较特殊,它没有开放网页端的分享 API,所以 Share.js 的做法是。

在页面上弹一个浮层,里面放一张二维码图片,用户拿微信扫这个码就能把链接分享出去。

这套逻辑在 jquery.share.min.js 里,核心代码大概是这样的,

e.append(
  '<div class="wechat-qrcode">' +
  '<h4>' + t.wechatQrcodeTitle + '</h4>' +
  '<div class="qrcode"></div>' +
  '<div class="help">' + t.wechatQrcodeHelper + "</div>" +
  "</div>"
),
e.find(".qrcode").qrcode({
  render: "image",
  size: t.wechatQrcodeSize,
  text: t.url
})

它先拼了一个 HTML 结构出来,然后调用 qrcode() 方法在 .qrcode 这个 div 里生成一张二维码图片。render 设成 "image",意思是不要用 canvas 画,也不要拼 div 像素矩阵,直接输出一个 <img> 标签。

问题就出在这个 <img> 标签的生成逻辑上。

根因在哪里

追到 qrcode() 的 image 渲染分支,代码是这样的,

function(r) {
  return d("<img/>").attr("src", t(r)[0].toDataURL("image/png"))
}(r)

看到了吧。

用 canvas 把二维码画出来,转成 dataURL,然后直接 d("<img/>").attr("src", ...),只设了 src,完全没有管 alt

你肯定会想,那是不是 createImgTag 那个方法有 alt 参数但没传?

确实。Share.js 内置的 QR 码库还有一个 createImgTag 方法,是走 GIF base64 路线的,

A = function(r, t, e, n) {
  // ...生成 base64...
  n && (l += ' alt="', l += n, l += '"')
  // ...
}

第四个参数 n 就是 alt 文本。但问题是,调用它的地方只传了两个参数,

f.createImgTag = function(o, r) {
  o = o || 2, r = void 0 === r ? 4 * o : r;
  return A(t, t, function(r, t) { ... }) // 没传 alt
}

alt 参数永远是 undefined,分支永远不走。

而且微信分享走的是 render: "image" 路径,根本就不会调 createImgTag。所以不管哪个分支,最终生成的这张微信二维码图片,alt 属性就是空的。

这就是完整的根因。两个生成路径,都没有处理 alt。

网站分享插件Share.js微信分享图片缺少alt属性完美修复方法

修复步骤

搞清楚问题之后,修起来其实非常简单。总共就一步。

找到 jquery.share.min.js 里微信二维码生成的那段代码,在 .qrcode() 调用后面,链式追加上 alt 属性。

修改前,

e.find(".qrcode").qrcode({
  render: "image",
  size: t.wechatQrcodeSize,
  text: t.url
}), e.offset().top < 100 && e.find(".wechat-qrcode").addClass("bottom")

修改后,

e.find(".qrcode").qrcode({
  render: "image",
  size: t.wechatQrcodeSize,
  text: t.url
}).find("img").attr("alt", "微信分享二维码"), e.offset().top < 100 && e.find(".wechat-qrcode").addClass("bottom")

就多了一行 .find("img").attr("alt", "微信分享二维码")

原理很简单,.qrcode() 执行完之后,.qrcode 这个 div 里面就已经有了一张 <img> 标签,直接 find("img") 找到它,用 attr() 把 alt 补上就行了。

alt 的内容我写死了「微信分享二维码」,如果你想让用户自定义文字,也可以读插件的配置项,比如之前已经有 wechatQrcodeTitle 这个参数,默认值是「微信扫一扫:分享」,

.find("img").attr("alt", t.wechatQrcodeTitle || "微信分享二维码")

这样如果你在初始化 .share() 的时候传了自定义的 wechatQrcodeTitle,alt 也会跟着变。想灵活一点就这么写,想简单一点直接写死也完全没问题。

验证

改完之后刷新页面,打开微信分享的二维码弹窗,右键检查元素,你应该能看到 img 标签上多了一个 alt="微信分享二维码"

再跑一下 Lighthouse 的无障碍检测,alt 缺失的警告就消失了。

屏幕阅读器读到这张图片的时候,会播报「微信分享二维码」,用户立刻知道这是什么。

结尾

说实话,这是个特别小的问题。

就一行代码的事儿。

但它背后反映的是,很多前端插件在开发的时候,无障碍访问几乎是被遗忘的角落。alt 属性、ARIA 标签、键盘导航、焦点管理,这些对普通用户可能感知不到,但对视障用户来说就是能不能正常使用一个网站的分界线。

web 标准写了这么多年,WAI-ARIA 规范也推了这么多年,但实际落地的时候,连一个几万 star 的分享插件都能漏掉 alt。

以前我也没注意过这个问题,也是那次跑 Lighthouse 才发现的。修完之后就顺手记录下来了。

如果你也在用 Share.js 或者类似的前端分享插件,有空跑一下无障碍检测,大概率能发现一些类似的小细节。修起来都不难,但修完之后的用户体验提升,对那一部分用户来说是实打实的。

以上。

打赏
THE END
作者头像
fuwa
我爱我的参差不齐 我即是自己的反义词