无障碍基础:让更多人能正常使用你的站点
无障碍(a11y)不是「加分项」,而是「做对了才叫完成」。而且大部分改动成本极低——改几行 CSS 就能覆盖一大半问题。
一、先做三件最划算的事
1. 保留焦点样式
很多人为了「好看」写了 outline: none,这对只用键盘的用户是灾难——他们完全不知道焦点在哪。
/* 不要这样 */
*:focus { outline: none; }
/* 应该这样:只在鼠标点击时隐藏,键盘操作时显示 */
:focus { outline: none; }
:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
border-radius: 4px;
}:focus-visible 是浏览器自动判断的:键盘聚焦显示,鼠标点击不显示。完美解决「好看」与「可用」的矛盾。
2. 确保键盘能操作
自查方法:拔掉鼠标,只用 Tab 键走一遍。
<!-- 用真正的按钮,可聚焦、可回车触发 -->
<button type="button" id="theme-btn">切换主题</button>
<!-- 不要这样:div 默认不可聚焦、不响应键盘 -->
<div onclick="toggle()">切换主题</div>如果非要用 div(比如为了实现特殊样式),必须补齐三样:
<div role="button" tabindex="0" onclick="toggle()" onkeydown="handleKey(event)">
切换主题
</div>3. 点击区域够大
.icon-btn {
min-width: 44px; /* 建议最小 44×44 */
min-height: 44px;
}二、对比度
文字与背景要有足够对比度:
| 级别 | 普通文字 | 大字(≥18px 或粗体 14px) |
|---|---|---|
| AA(最低) | 4.5:1 | 3:1 |
| AAA | 7:1 | 4.5:1 |
常见踩坑:浅灰色小字(#999 配白底只有 2.8:1,不达标)。
/* 本站的 muted 色在浅色下是 #737b85(4.6:1,刚过 AA) */
--muted: #737b85;
/* 深色下 #8b949e(5.9:1) */
[data-theme="dark"] { --muted: #8b949e; }检查方法:Chrome DevTools 里选中文字,颜色选择器会直接显示对比度数值和 AA/AAA 判定。
三、语义标签就是无障碍
用对标签,屏幕阅读器能自动理解结构,不需要额外写 aria:
<button>提交</button> <!-- 自动朗读为「按钮」 -->
<nav>...</nav> <!-- 朗读为「导航」 -->
<main>...</main> <!-- 朗读为「主要内容」 -->
<h2>小节</h2> <!-- 可跳转的标题 -->相反,用 <div class="button"> 的话,屏幕阅读器只会读成一段文字。
四、aria 的正确用法
第一条原则:能用原生标签就别用 aria。
只在原生标签表达不了时才补:
<!-- 图标按钮没有文字,需要 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 | 当前项(如导航高亮) |
五、图片与替代文本
<img src="chart.webp" alt="2026 年各月访问量折线图,整体呈上升趋势">
<!-- 纯装饰 -->
<img src="deco.svg" alt="">
<!-- 背景图不用 alt,用 CSS -->alt 要写「图片传达的信息」,不是「这是一张图」。
六、表单
<!-- 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>七、让跳转链接有意义
<a href="/post/1">阅读全文</a> <!-- 多个都一样,无法区分 -->
<a href="/post/1">阅读全文:域名注册与 DNS</a>
<!-- 或用 aria-label -->
<a href="/post/1" aria-label="阅读全文:域名注册与 DNS 解析">阅读全文</a>八、跳转主内容的链接
键盘用户每次都要 Tab 过整个导航栏才能到正文。加一个「跳到主内容」:
<a href="#main" class="skip-link">跳到主要内容</a>
<main id="main">...</main>.skip-link {
position: absolute;
left: -9999px;
}
.skip-link:focus {
left: 8px;
top: 8px;
z-index: 100;
padding: 8px 16px;
background: var(--accent);
color: #fff;
}九、动效与减少动效偏好
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: .01ms !important;
transition-duration: .01ms !important;
scroll-behavior: auto !important;
}
}有些人会因动画感到不适(前庭功能障碍),系统里开了「减少动效」就应当尊重。
十、自查清单
手动检查(5 分钟):
- 只用键盘能走完整个站点吗?
- 焦点看得见吗?
- 每个图片都有合适的 alt 吗?
- 关掉 CSS,内容顺序还合理吗?(装个禁用 CSS 的插件看)
工具检查:
# 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、更完整的键盘导航。
无障碍不是给「少数人」做的:键盘用户、老年人、临时受伤的人、在强光下看手机的人——每个人都可能在某些时刻需要它。
