惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
博客园 - 司徒正美
小众软件
小众软件
H
Help Net Security
博客园 - 聂微东
宝玉的分享
宝玉的分享
Jina AI
Jina AI
酷 壳 – CoolShell
酷 壳 – CoolShell
阮一峰的网络日志
阮一峰的网络日志
M
MIT News - Artificial intelligence
博客园 - 【当耐特】
U
Unit 42
大猫的无限游戏
大猫的无限游戏
Apple Machine Learning Research
Apple Machine Learning Research
S
SegmentFault 最新的问题
腾讯CDC
MongoDB | Blog
MongoDB | Blog
云风的 BLOG
云风的 BLOG
J
Java Code Geeks
I
InfoQ
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Martin Fowler
Martin Fowler
博客园 - 三生石上(FineUI控件)
Vercel News
Vercel News

豆沙工作室

Clean Slate: 一个 11ty 站点主题的实现 不想(二)十七岁 小点阵字 Get an Oscilloscope 杰理 WTS 格式音频转换和打包 [11ty] 增量式地刷新 CDN 缓存 站起来,为你的成果答辩吧 公理还是定理? [11ty] 处理资产文件的 CDN 缓存问题 [11ty] 无障碍设计:正确地标识图和表 停止 Mac 上的时间机器备份 从 Gitea 迁移到 Forgejo 评论里的私信消息 记得清理你的日志文件 招魂 Annihilation [11ty] 使用 Pagefind 实现静态站点的搜索 直面死亡 [11ty] 修复 RSS 里的数学公式 看到了一个神奇的 UA PreFound:10B - 四次击键 一点小小的 AI 震撼 PreFound:10A - 文本之外,还有(绘)文字 PreFound:09 - 色彩运算子 计算机不予申辩 Re-Game 2.0 Addendum C - Press START PreFound:08 - 动效与仿射 PreFound:07 - 图片拼贴报 PreFound:06 - 漫游雪花海 PreFound:05 - 写出到屏幕
[11ty] 无障碍设计:修复图片灯箱
dousha99 · 2026-09-19 · via 豆沙工作室

或者说,正确地实现一个模态对话框。

虽然标题里说的是 11ty, 其实更多的是在修 Adams 主题。不知不觉间这款主题现在已经快到要上学的年纪了。

Adams 主题在点击图片的时候会显示大图,通过 ViewImage 库实现。这个库本身功能上没什么问题,但是它会动态地插入灯箱 <div> 元素,而这会对屏幕阅读器带来不小的挑战:灯箱打开之后,它是没有任何屏幕阅读器可见的输入焦点的,因为它的所有看起来像是按钮的东西都是一个带着点击事件且没有 tabindex<div>。这就意味着如果你尝试用屏幕阅读器去关闭灯箱,那么不好意思,做不到——屏幕阅读器甚至不知道灯箱这个东西被打开了!它的焦点还停留在图片上面。

虽然 ViewImage 库实现了 Esc 键的输入捕获来通过键盘关闭灯箱,但我总觉得这么做有点不是滋味。

「幽灵窗口」

Accessibility Issues That Must Not Be Named 中,PaulMartz 指出这种无法被屏幕阅读器访问的窗口十分常见。更头疼的是:模态对话框内可能会包含真的需要用户交互的内容,而 VoiceOver 的高亮框就是进入不到这个对话框里。

它「看」起来像是一个模态对话框,「点」起来像是一个模态对话框,但是它并不会把自己标识为一个模态对话框,也不会提供对应的 ARIA 属性来告诉屏幕阅读器这是一个模态对话框。对于屏幕阅读器来说,它和一个没有任何交互的 <div> 幽灵没有任何区别。

即使对话框内部有可被识别的元素,许多对话框的实现也需要用户移动到页面最底部才能将扫描焦点移动到对话框内,因为对话框本身是被动态插入到 <body> 元素中,作为最后一个子元素出现的。

所以,如果要正确实现一个模态对话框,我们至少需要满足以下需求:

  • 屏幕阅读器可以感知到模态框被打开
  • 屏幕阅读器可以在模态框内探索其中的元素,尤其是关闭按钮必须可以被选中(笑)
  • 输入焦点需要跟随到模态框内,这样就不需要按一百多次 Tab 才能选中关闭按钮了——尤其是你的键盘焦点是在页面正中心所以 Shift+Tab 和 Tab 都得按几十次的时候

考虑到 ViewImage 库是 IE 时代的产物,它必然会需要照顾到各种老浏览器的怪行为。但现在我总算是摆脱了 IE 的桎梏,有了现代浏览器的功能加持,能否改善图片灯箱的可访问性呢?

现有技术

在着手写自己的实现之前,我先简单搜索了一下现有的灯箱库:

  • Lightbox2: 虽然这个无疑是最优实现,但是它依赖于我正在计划移除的 jQuery, 所以很遗憾
  • LiteBox: 同样有无障碍访问问题
  • fslightbox.js: 虽然确实正确使用了 <button> 作为灯箱控件,但是灯箱控件需要按无数次 Tab 才能得到焦点
  • Featherlight.js: 这玩意一下子干碎了我的 WAVE 插件,含金量太高了

那么,自己动手,丰衣足食!

<dialog> 元素

HTML 5 标准中添加了 <dialog> 元素。这个元素天然地可以作为模态对话框——它有完整的可访问性语义、焦点、自动抬升的 z-index, 用起来真是再好不过了!而且不需要担心兼容性问题:三大浏览器内核对这个元素都有足够的支持

HTML 5 的 data- 属性前缀

为了保持 HTML 5 标准合规,自定义的属性应该以 data- 开头。这个修起来很容易,重新指定一下属性名可以了。

我真的需要一个图片灯箱么?

思来想去,目前的用例中,图片灯箱似乎没有什么特别明显的作用:如果用户需要看大图的话,他们完全可以在新标签页中打开图片,这样他们甚至可以享受浏览器自带的缩放和保存功能。我的博客的图片大多托管在图床上,没有转码也没有压缩,所以也不需要灯箱来加载真·高清大图出来——大多数灯箱插件甚至也压根没有点开之后加载另一张图片的方法。

一个可能的用例是允许用户直接在页面中缩放一些比例比较奇特的图片,比如放大窄长的截图。不过这个功能在原版的 ViewImage 库里面貌似也没有实现——这件事还是交给浏览器缩放自己来吧!

另一个可能的方案是:在灯箱中提供关于图片的更多信息,比如拍摄位置、镜头参数等图片元信息、版权信息,以及展示该图片的描述文字等等。不过这么搞,可能带来的坑会更多——是否需要专门的页面来展示这些信息?这些信息的无障碍访问又要怎样处理?

还是先不搞这些花里胡哨的东西了。它现在可以满足需求,这是最重要的。