无障碍基础:让更多人能正常使用你的站点

无障碍(a11y)不是「加分项」,而是「做对了才叫完成」。而且大部分改动成本极低——改几行 CSS 就能覆盖一大半问题。

一、先做三件最划算的事

1. 保留焦点样式

很多人为了「好看」写了 outline: none,这对只用键盘的用户是灾难——他们完全不知道焦点在哪。

css
/* 不要这样 */
*:focus { outline: none; }

/* 应该这样:只在鼠标点击时隐藏,键盘操作时显示 */
:focus { outline: none; }
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}

:focus-visible 是浏览器自动判断的:键盘聚焦显示,鼠标点击不显示。完美解决「好看」与「可用」的矛盾。

2. 确保键盘能操作

自查方法:拔掉鼠标,只用 Tab 键走一遍。

html
<!-- 用真正的按钮,可聚焦、可回车触发 -->
<button type="button" id="theme-btn">切换主题</button>

<!-- 不要这样:div 默认不可聚焦、不响应键盘 -->
<div onclick="toggle()">切换主题</div>

如果非要用 div(比如为了实现特殊样式),必须补齐三样:

html
<div role="button" tabindex="0" onclick="toggle()" onkeydown="handleKey(event)">
  切换主题
</div>

3. 点击区域够大

css
.icon-btn {
  min-width: 44px;      /* 建议最小 44×44 */
  min-height: 44px;
}

二、对比度

文字与背景要有足够对比度:

级别普通文字大字(≥18px 或粗体 14px)
AA(最低)4.5:13:1
AAA7:14.5:1

常见踩坑:浅灰色小字(#999 配白底只有 2.8:1,不达标)。

css
/* 本站的 muted 色在浅色下是 #737b85(4.6:1,刚过 AA) */
--muted: #737b85;

/* 深色下 #8b949e(5.9:1) */
[data-theme="dark"] { --muted: #8b949e; }

检查方法:Chrome DevTools 里选中文字,颜色选择器会直接显示对比度数值和 AA/AAA 判定。

三、语义标签就是无障碍

用对标签,屏幕阅读器能自动理解结构,不需要额外写 aria

html
<button>提交</button>          <!-- 自动朗读为「按钮」 -->
<nav>...</nav>                 <!-- 朗读为「导航」 -->
<main>...</main>               <!-- 朗读为「主要内容」 -->
<h2>小节</h2>                  <!-- 可跳转的标题 -->

相反,用 <div class="button"> 的话,屏幕阅读器只会读成一段文字。

四、aria 的正确用法

第一条原则:能用原生标签就别用 aria。

只在原生标签表达不了时才补:

html
<!-- 图标按钮没有文字,需要 aria-label -->
<button aria-label="切换深浅色主题">
  <svg>...</svg>
</button>

<!-- 装饰性图标对辅助技术隐藏 -->
<svg aria-hidden="true">...</svg>

<!-- 动态内容变化要通知 -->
<div role="status" aria-live="polite">已复制</div>

<!-- 展开/收起状态 -->
<button aria-expanded="false" aria-controls="menu">菜单</button>

常用属性:

属性用途
aria-label给无文字元素加名字
aria-hidden="true"对辅助技术隐藏(装饰元素)
aria-live动态更新的区域
aria-expanded展开状态
aria-current当前项(如导航高亮)

五、图片与替代文本

html
<img src="chart.webp" alt="2026 年各月访问量折线图,整体呈上升趋势">

<!-- 纯装饰 -->
<img src="deco.svg" alt="">

<!-- 背景图不用 alt,用 CSS -->

alt 要写「图片传达的信息」,不是「这是一张图」。

六、表单

html
<!-- label 与 input 关联,点击文字也能聚焦 -->
<label for="q">搜索</label>
<input id="q" type="search" placeholder="搜索笔记">

<!-- 或用 aria-label(视觉上不需要标签时) -->
<input type="search" aria-label="搜索文章">

<!-- 错误提示要关联 -->
<input aria-describedby="err" aria-invalid="true">
<span id="err">请输入关键词</span>

七、让跳转链接有意义

html
<a href="/post/1">阅读全文</a>            <!-- 多个都一样,无法区分 -->
<a href="/post/1">阅读全文:域名注册与 DNS</a>

<!-- 或用 aria-label -->
<a href="/post/1" aria-label="阅读全文:域名注册与 DNS 解析">阅读全文</a>

八、跳转主内容的链接

键盘用户每次都要 Tab 过整个导航栏才能到正文。加一个「跳到主内容」:

html
<a href="#main" class="skip-link">跳到主要内容</a>
<main id="main">...</main>
css
.skip-link {
  position: absolute;
  left: -9999px;
}
.skip-link:focus {
  left: 8px;
  top: 8px;
  z-index: 100;
  padding: 8px 16px;
  background: var(--accent);
  color: #fff;
}

九、动效与减少动效偏好

css
@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: .01ms !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

有些人会因动画感到不适(前庭功能障碍),系统里开了「减少动效」就应当尊重。

十、自查清单

手动检查(5 分钟)

  • 只用键盘能走完整个站点吗?
  • 焦点看得见吗?
  • 每个图片都有合适的 alt 吗?
  • 关掉 CSS,内容顺序还合理吗?(装个禁用 CSS 的插件看)

工具检查

bash
# Lighthouse(DevTools → Lighthouse → Accessibility)
# 会给出具体问题,比如「按钮没有可访问的名称」
工具用途
Lighthouse自动检测,给出清单
axe DevTools浏览器插件,更详细
屏幕阅读器真机体验(macOS 的 VoiceOver 按 Cmd+F5)

十一、本站做了哪些

  • 所有交互元素都是 <button><a>
  • 图标按钮有 aria-label
  • 装饰性 SVG 标了 aria-hidden
  • 搜索框有 aria-label
  • 焦点样式用 :focus-visible
  • 深浅色主题的对比度都过 AA;
  • 支持 prefers-reduced-motion

还没做的:跳转主内容的 skip-link、更完整的键盘导航。


无障碍不是给「少数人」做的:键盘用户、老年人、临时受伤的人、在强光下看手机的人——每个人都可能在某些时刻需要它。