合者离之始
Record:008

零 JavaScript 的可访问性清单

一份可以逐条勾选的清单:不依赖 JS 时,网站还剩多少可用性?

Posted2026-03-15Words853Reading2 min

关掉 JavaScript,刷新页面,然后逐条检查:

内容

  • 所有文字都可见(没有靠 opacity: 0 做入场动画)
  • 图片有 alt
  • 代码块可以选中、复制、页内查找
  • 表格不靠 JS 横向滚动

导航

  • 链接是真 <a href>,不是 onclick
  • 表单(搜索框)能直接提交
  • 分页链接可用
  • 页面标题(<title>)能区分不同页面

语义

  • 每页只有一个 <h1>
  • 标题层级不跳级(h1 → h2 → h3)
  • 有一个「跳到正文」的 skip link
  • 当前页导航项带 aria-current="page"

交互

  • 焦点可见(不要 outline: none)
  • 点击区域 ≥ 44×44px
  • 悬停信息在触摸设备上也能看到(不要只靠 :hover)

媒体

  • 视频有字幕
  • 动画遵守 prefers-reduced-motion
  • 没有自动播放的声音

为什么在意

不是因为「无障碍」是个道德高地,而是因为依赖 JS 的东西都很脆。

网络慢的时候、脚本报错的时候、用户开了阅读模式的时候、搜索引擎爬虫来的时候——你的页面都在被降级使用。

一个零 JS 也能读的页面,在这些情况下依然是个页面;一个必须等 JS 的页面,在这些情况下就是一片空白。

实现上的一点技巧

渐进增强的顺序是:先让内容可用,再让它更好用。

<!-- 基础:浏览器原生就能滚动的代码块 -->
<pre tabindex="0"><code>…</code></pre>
 
<!-- 增强:JS 注入复制按钮 -->
<button class="copy-btn" type="button">Copy</button>

复制按钮是 JS 注入的,所以完全不用在 HTML 里写「如果 JS 不可用就隐藏」的逻辑——它压根不会出现。

同理,入场动画的初始状态不要写在 CSS 里,而是由 JS 添加一个类再触发。这样无 JS 时元素就是正常可见的。

原则只有一条:默认状态必须是可用的,增强状态由 JS 添加。