Web 可访问性最佳实践:构建人人可用的前端界面
什么是 Web 可访问性?
Web 可访问性(Web Accessibility)是指网站、工具和技术能够被所有人使用,包括那些有残障人士。这意味着无论用户的能力如何,他们都应该能够感知、理解、导航和与 Web 内容交互。
为什么 Web 可访问性很重要?
- 法律要求:许多国家和地区都有法律法规要求网站必须具有可访问性。
- 扩大用户群体:约 15% 的世界人口生活有某种形式的残障,可访问性可以让更多人使用你的网站。
Web 可访问性确保网站能被所有人(包括残障人士)使用。基于 WCAG 四大原则(可感知、可操作、可理解、健壮),核心实践,包括语义化 HTML、替代文本、键盘支持、颜色对比度、表单优化及 ARIA 属性。提供了登录表单完整示例,并推荐了 axe-core、Lighthouse 等测试工具。遵循这些规范不仅符合法律要求,还能提升 SEO 和整体用户体验,构建包容的数字环境。
Web 可访问性(Web Accessibility)是指网站、工具和技术能够被所有人使用,包括那些有残障人士。这意味着无论用户的能力如何,他们都应该能够感知、理解、导航和与 Web 内容交互。
根据 WCAG(Web Content Accessibility Guidelines)2.1,Web 可访问性基于以下四个核心原则:
信息和用户界面组件必须以用户可以感知的方式呈现。
用户界面组件和导航必须是可操作的。
信息和用户界面操作必须是可理解的。
内容必须足够健壮,能够被各种用户代理(包括辅助技术)可靠地解释。
使用正确的 HTML 元素来表示内容的结构和含义。
<!-- 不好的做法 -->
<div>标题</div>
<div>导航链接</div>
<div>文章内容</div>
<!-- 好的做法 -->
<header>标题</header>
<nav>导航链接</nav>
<article>文章内容</article>
为所有非文本内容(如图像、音频、视频)提供替代文本。
<!-- 图片的替代文本 -->
<img src="logo.png" alt="公司标志">
<!-- 装饰性图片的替代文本(空字符串) -->
<img src="decorative.png" alt="">
<!-- 复杂图像的详细描述 -->
<figure aria-describedby="chart-description">
<img src="chart.png" alt="2024 年销售数据图表">
<figcaption>2024 年销售数据图表,显示第一季度销售额为 100 万,第二季度为 120 万,第三季度为 150 万,第四季度为 180 万,全年增长 20%。</figcaption>
</figure>
确保所有功能都可以通过键盘访问。
/* 为键盘焦点添加可见的样式 */
:focus {
outline: 2px solid #667eea;
outline-offset: 2px;
}
/* 移除默认的 outline 但保持可访问性 */
button {
outline: none;
}
button:focus {
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.5);
}
确保文本和背景之间有足够的对比度。
| 文本大小 | 正常文本 | 大文本(18pt 或 14pt 粗体) |
|---|---|---|
| 最小对比度 | 4.5:1 | 3:1 |
| 增强对比度 | 7:1 | 4.5:1 |
/* 好的对比度示例 */
body {
background-color: #ffffff;
color: #333333; /* 对比度约为 12:1 */
}
/* 不好的对比度示例 */
body {
background-color: #f0f0f0;
color: #666666; /* 对比度约为 3:1,对于正常文本不足 */
}
确保表单元素有明确的标签和错误提示。
<form>
<div>
<label for="name">姓名</label>
<input type="text" name="name" required>
<span aria-live="polite"></span>
</div>
<div>
<label for="email">邮箱</label>
<input type="email" name="email" required>
<span aria-live="polite"></span>
</div>
<button type="submit">提交</button>
</form>
使用 ARIA(Accessible Rich Internet Applications)属性来增强可访问性。
<!-- 导航菜单 -->
<nav aria-label="主导航">
<ul>
<li><a href="#">首页</a></li>
<li><a href="#">关于</a></li>
<li><a href="#">服务</a></li>
<li><a href="#">联系</a></li>
</ul>
</nav>
<!-- 模态框 -->
<div aria-labelledby="modal-title" aria-hidden="true">
<h2>模态框标题</h2>
<p>模态框内容</p>
<button aria-label="关闭">×</button>
</div>
<!-- 状态提示 -->
<div aria-live="assertive"></div>
确保网站在不同设备和屏幕尺寸上都能正常工作。
/* 响应式布局 */
.container {
width: 100%;
max-width: 1200px;
margin: 0 auto;
padding: 0 1rem;
}
/* 响应式字体大小 */
body {
font-size: clamp(16px, 1rem + 0.5vw, 20px);
}
/* 触摸目标大小 */
button, a {
min-width: 44px;
min-height: 44px;
padding: 0.5rem;
}
为键盘用户提供跳过导航链接,直接跳转到主要内容。
<body>
<a href="#main-content">跳转到主要内容</a>
<header><!-- 导航菜单 --></header>
<main><!-- 主要内容 --></main>
</body>
.skip-link {
position: absolute;
top: -40px;
left: 0;
background-color: #667eea;
color: white;
padding: 0.5rem;
text-decoration: none;
z-index: 1000;
transition: top 0.3s ease;
}
.skip-link:focus {
top: 0;
}
为用户提供足够的时间来阅读和使用内容,避免使用不必要的时间限制。
<!-- 提供延长时间的选项 -->
<div>
<p>您还有 <span>60</span> 秒来完成此操作。</p>
<button>延长时间</button>
</div>
为音频和视频内容提供字幕和转录。
<!-- 视频 -->
<video controls>
<source src="video.mp4" type="video/mp4">
<track kind="captions" src="captions.vtt" srclang="zh" label="中文">
您的浏览器不支持视频标签。
</video>
<!-- 音频 -->
<audio controls>
<source src="audio.mp3" type="audio/mpeg">
您的浏览器不支持音频标签。
</audio>
<p><a href="transcript.txt">查看音频转录</a></p>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>登录</title>
<style>
/* 基础样式 */
body {
font-family: 'Inter', system-ui, sans-serif;
line-height: 1.6;
color: #333333;
background-color: #f8f9fa;
margin: 0;
padding: 2rem;
}
/* 容器 */
.container {
max-width: 400px;
margin: 0 auto;
background-color: #ffffff;
padding: 2rem;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
/* 标题 */
h1 {
margin-top: 0;
margin-bottom: 1.5rem;
font-size: 1.5rem;
font-weight: 600;
color: #212529;
text-align: center;
}
/* 表单组 */
.form-group {
margin-bottom: 1.25rem;
}
/* 标签 */
label {
display: block;
margin-bottom: 0.5rem;
font-weight: 500;
color: #495057;
}
/* 输入框 */
input {
width: 100%;
padding: 0.75rem;
border: 1px solid #ced4da;
border-radius: 4px;
font-size: 1rem;
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}
input:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 0.2rem rgba(102, 126, 234, 0.25);
}
/* 错误信息 */
.error {
color: #dc3545;
font-size: 0.875rem;
margin-top: 0.25rem;
}
/* 按钮 */
button {
width: 100%;
padding: 0.75rem;
background-color: #667eea;
color: #ffffff;
border: none;
border-radius: 4px;
font-size: 1rem;
font-weight: 500;
cursor: pointer;
transition: background-color 0.15s ease-in-out;
}
button:hover {
background-color: #5a6fd8;
}
button:focus {
outline: none;
box-shadow: 0 0 0 0.2rem rgba(102, 126, 234, 0.5);
}
/* 跳过链接 */
.skip-link {
position: absolute;
top: -40px;
left: 0;
background-color: #667eea;
color: white;
padding: 0.5rem;
text-decoration: none;
z-index: 1000;
}
.skip-link:focus {
top: 0;
}
</style>
</head>
<body>
<a href="#main-content">跳转到主要内容</a>
<div class="container">
<h1>用户登录</h1>
<form id="login-form">
<div class="form-group">
<label for="email">邮箱</label>
<input type="email" name="email" required aria-describedby="email-error">
<span id="email-error" class="error" aria-live="polite"></span>
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" name="password" required aria-describedby="password-error">
<span id="password-error" class="error" aria-live="polite"></span>
</div>
<button type="submit">登录</button>
</form>
</div>
<script>
// 表单验证
document.getElementById('login-form').addEventListener('submit', function(e) {
e.preventDefault();
const email = document.getElementById('email');
const password = document.getElementById('password');
const emailError = document.getElementById('email-error');
const passwordError = document.getElementById('password-error');
let isValid = true;
// 验证邮箱
if (!email.value) {
emailError.textContent = '请输入邮箱';
email.focus();
isValid = false;
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email.value)) {
emailError.textContent = '请输入有效的邮箱地址';
email.focus();
isValid = false;
} else {
emailError.textContent = '';
}
// 验证密码
if (!password.value) {
passwordError.textContent = ;
(isValid) { password.(); }
isValid = ;
} (password.. < ) {
passwordError. = ;
(isValid) { password.(); }
isValid = ;
} {
passwordError. = ;
}
(isValid) {
();
}
});
</script>
</body>
</html>
Web 可访问性是前端开发的重要组成部分,它不仅是法律要求,也是一种社会责任。通过遵循这些最佳实践,我们可以构建出人人都能使用的前端界面,为所有用户提供良好的用户体验。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML 转 Markdown 互为补充。 在线工具,Markdown 转 HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML 转 Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online