可访问性
Web 可访问性(也称为 a11y)指的是创建任何人都能使用的网站的实践——无论是有残障的人、网络连接较慢的人、使用过时或损坏硬件的人,还是仅仅身处不利环境中的人。例如,为视频添加字幕既能帮助失聪和听力障碍用户,也能帮助身处嘈杂环境、听不到手机声音的用户。同样,确保文本对比度不过低,既能帮助低视力用户,也能帮助在强烈阳光下尝试使用手机的用户。
准备开始了,但不确定从哪里入手?
请查看由 World Wide Web Consortium (W3C) 提供的 规划和管理 Web 可访问性指南
跳过链接
你应该在每个页面顶部添加一个链接,直接跳转到主要内容区域,这样用户就可以跳过多个网页中重复出现的内容。
通常这会放在 App.vue 的顶部,因为它会是你所有页面中第一个可聚焦元素:
template
<span ref="backToTop" tabindex="-1" />
<ul class="skip-links">
<li>
<a href="#main" ref="skipLink" class="skip-link">跳转到主要内容</a>
</li>
</ul>要在链接未获得焦点时将其隐藏,可以添加以下样式:
css
.skip-links {
list-style: none;
}
.skip-link {
white-space: nowrap;
margin: 1em auto;
top: 0;
position: fixed;
left: 50%;
margin-left: -72px;
opacity: 0;
}
.skip-link:focus {
opacity: 1;
background-color: white;
padding: 0.5em;
border: 1px solid black;
}当用户切换路由后,将焦点带回页面最开始的位置,也就是跳过链接之前。这可以通过调用 backToTop 模板 ref 的 focus 来实现(假设使用的是 vue-router):
vue
<script setup>
import { ref, watch } from 'vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const backToTop = ref()
watch(
() => route.path,
() => {
backToTop.value.focus()
}
)
</script>内容结构
可访问性中最重要的一部分之一,是确保设计能够支持可访问的实现。设计不仅应考虑颜色对比度、字体选择、文本大小和语言,还应考虑应用中的内容是如何组织的。
标题
用户可以通过标题在应用中导航。为应用的每个部分提供描述性的标题,会让用户更容易预测每个部分的内容。关于标题,有几条推荐的可访问性实践:
- 按层级顺序嵌套标题:
<h1>-<h6> - 不要在同一部分中跳过标题层级
- 使用真正的标题标签,而不是通过样式把文本做成标题外观
template
<main role="main" aria-labelledby="main-title">
<h1 id="main-title">主标题</h1>
<section aria-labelledby="section-title-1">
<h2 id="section-title-1">章节标题</h2>
<h3>章节副标题</h3>
<!-- 内容 -->
</section>
<section aria-labelledby="section-title-2">
<h2 id="section-title-2">章节标题</h2>
<h3>章节副标题</h3>
<!-- 内容 -->
<h3>章节副标题</h3>
<!-- 内容 -->
</section>
</main>地标区域
地标区域 为应用中的各个部分提供程序化访问。依赖辅助技术的用户可以导航到应用的每个部分并跳过内容。你可以使用 ARIA 角色 来帮助实现这一点。
| HTML | ARIA 角色 | 地标用途 |
|---|---|---|
| header | role="banner" | 主要标题:页面标题 |
| nav | role="navigation" | 链接集合,适用于浏览文档或相关文档时使用 |
| main | role="main" | 文档的主要或中心内容。 |
| footer | role="contentinfo" | 关于父文档的信息:脚注/版权/隐私声明链接 |
| aside | role="complementary" | 支持主要内容,但又相互独立且本身具有意义的内容 |
| search | role="search" | 这一部分包含应用的搜索功能 |
| form | role="form" | 表单相关元素的集合 |
| section | role="region" | 与内容相关且用户很可能希望导航到的内容。该元素必须提供标签 |
语义化表单
创建表单时,你可以使用以下元素:<form>、<label>、<input>、<textarea> 和 <button>
标签通常放在表单字段的上方或左侧:
template
<form action="/dataCollectionLocation" method="post" autocomplete="on">
<div v-for="item in formItems" :key="item.id" class="form-item">
<label :for="item.id">{{ item.label }}: </label>
<input
:type="item.type"
:id="item.id"
:name="item.id"
v-model="item.value"
/>
</div>
<button type="submit">提交</button>
</form>注意,你可以在 form 元素上添加 autocomplete='on',它会应用到表单中的所有输入框。你也可以为每个输入框设置不同的 autocomplete 属性值。
标签
提供标签来描述所有表单控件的用途;通过 for 和 id 进行关联:
template
<label for="name">姓名: </label>
<input type="text" name="name" id="name" v-model="name" />如果你在 Chrome 开发者工具中检查这个元素,并在 Elements 标签页中打开 Accessibility 面板,你会看到输入框是如何从标签中获取名称的:

警告:
虽然你可能见过像这样包裹输入框的标签:
template
<label>
姓名:
<input type="text" name="name" id="name" v-model="name" />
</label>显式地使用匹配的 id 来设置标签,能获得更好的辅助技术支持。
aria-label
你也可以使用 aria-label 为输入框提供可访问名称。
template
<label for="name">姓名: </label>
<input
type="text"
name="name"
id="name"
v-model="name"
:aria-label="nameLabel"
/>你可以随意在 Chrome 开发者工具中检查这个元素,看看可访问名称是如何变化的:

aria-labelledby
使用 aria-labelledby 与 aria-label 类似,只不过它用于屏幕上可见标签文本的情况。它通过各元素的 id 进行关联,并且可以链接多个 id:
template
<form
class="demo"
action="/dataCollectionLocation"
method="post"
autocomplete="on"
>
<h1 id="billing">账单</h1>
<div class="form-item">
<label for="name">姓名: </label>
<input
type="text"
name="name"
id="name"
v-model="name"
aria-labelledby="billing name"
/>
</div>
<button type="submit">提交</button>
</form>
aria-describedby
aria-describedby 的使用方式与 aria-labelledby 类似,但它提供的是带有额外信息的描述,供用户需要时查看。这可以用于描述任何输入框的填写要求:
template
<form
class="demo"
action="/dataCollectionLocation"
method="post"
autocomplete="on"
>
<h1 id="billing">账单</h1>
<div class="form-item">
<label for="name">全名: </label>
<input
type="text"
name="name"
id="name"
v-model="name"
aria-labelledby="billing name"
aria-describedby="nameDescription"
/>
<p id="nameDescription">请提供名和姓。</p>
</div>
<button type="submit">提交</button>
</form>你可以通过检查 Chrome 开发者工具来查看该描述:

占位符
应避免使用占位符,因为它们会让很多用户感到困惑。
占位符的一个问题是它们默认不满足 颜色对比度标准;修复颜色对比度后,占位符会看起来像输入框中的预填数据。看下面的例子,你可以看到满足颜色对比度标准的姓氏占位符看起来像预填数据:

template
<form
class="demo"
action="/dataCollectionLocation"
method="post"
autocomplete="on"
>
<div v-for="item in formItems" :key="item.id" class="form-item">
<label :for="item.id">{{ item.label }}: </label>
<input
type="text"
:id="item.id"
:name="item.id"
v-model="item.value"
:placeholder="item.placeholder"
/>
</div>
<button type="submit">提交</button>
</form>css
/* https://www.w3schools.com/howto/howto_css_placeholder.asp */
#lastName::placeholder {
/* Chrome, Firefox, Opera, Safari 10.1+ */
color: black;
opacity: 1; /* Firefox */
}
#lastName:-ms-input-placeholder {
/* Internet Explorer 10-11 */
color: black;
}
#lastName::-ms-input-placeholder {
/* Microsoft Edge */
color: black;
}最好把用户填写表单所需的所有信息都放在输入框之外。
说明
在为输入字段添加说明时,请确保将其正确关联到输入框。 你可以在 aria-labelledby 中提供额外说明并绑定多个 id。这能带来更灵活的设计。
template
<fieldset>
<legend>使用 aria-labelledby</legend>
<label id="date-label" for="date">当前日期: </label>
<input
type="date"
name="date"
id="date"
aria-labelledby="date-label date-instructions"
/>
<p id="date-instructions">MM/DD/YYYY</p>
</fieldset>或者,你可以使用 aria-describedby 将说明附加到输入框上:
template
<fieldset>
<legend>使用 aria-describedby</legend>
<label id="dob" for="dob">出生日期: </label>
<input type="date" name="dob" id="dob" aria-describedby="dob-instructions" />
<p id="dob-instructions">MM/DD/YYYY</p>
</fieldset>隐藏内容
通常不建议在视觉上隐藏标签,即使输入框已经有可访问名称。不过,如果输入框的功能可以通过周围内容理解,那么我们可以隐藏视觉标签。
来看这个搜索字段:
template
<form role="search">
<label for="search" class="hidden-visually">搜索: </label>
<input type="text" name="search" id="search" v-model="search" />
<button type="submit">搜索</button>
</form>我们之所以可以这样做,是因为搜索按钮会帮助视觉用户识别输入字段的用途。
我们可以使用 CSS 在视觉上隐藏元素,但仍让辅助技术可以访问它们:
css
.hidden-visually {
position: absolute;
overflow: hidden;
white-space: nowrap;
margin: 0;
padding: 0;
height: 1px;
width: 1px;
clip: rect(0 0 0 0);
clip-path: inset(100%);
}aria-hidden="true"
添加 aria-hidden="true" 会让辅助技术看不到该元素,但仍对其他用户可见。不要把它用于可聚焦元素,只用于纯装饰性、重复或屏幕外内容。
template
<p>这段内容不会被屏幕阅读器隐藏。</p>
<p aria-hidden="true">这段内容会对屏幕阅读器隐藏。</p>按钮
在表单中使用按钮时,你必须设置 type,以避免提交表单。 你也可以使用 input 来创建按钮:
template
<form action="/dataCollectionLocation" method="post" autocomplete="on">
<!-- 按钮 -->
<button type="button">取消</button>
<button type="submit">提交</button>
<!-- 输入按钮 -->
<input type="button" value="取消" />
<input type="submit" value="提交" />
</form>功能性图片
你可以使用这种技术来创建功能性图片。
输入字段
- 这些图片会在表单中充当提交类型按钮
template<form role="search"> <label for="search" class="hidden-visually">搜索: </label> <input type="text" name="search" id="search" v-model="search" /> <input type="image" class="btnImg" src="https://img.icons8.com/search" alt="搜索" /> </form>图标
template
<form role="search">
<label for="searchIcon" class="hidden-visually">搜索: </label>
<input type="text" name="searchIcon" id="searchIcon" v-model="searchIcon" />
<button type="submit">
<i class="fas fa-search" aria-hidden="true"></i>
<span class="hidden-visually">搜索</span>
</button>
</form>标准
万维网联盟(W3C)网页无障碍倡议(WAI)为不同组件制定网页无障碍标准:
- 用户代理无障碍指南(UAAG)
- 网页浏览器和媒体播放器,包括辅助技术的某些方面
- 创作工具无障碍指南(ATAG)
- 创作工具
- 网页内容无障碍指南(WCAG)
- 网页内容——供开发人员、创作工具和无障碍评估工具使用
网页内容无障碍指南(WCAG)
WCAG 2.1 是对 WCAG 2.0 的扩展,并通过应对网页变化来支持新技术的实现。在开发或更新网页无障碍政策时,W3C 鼓励使用最新版本的 WCAG。
WCAG 2.1 四个主要指导原则(简称 POUR):
网页无障碍倡议 – 可访问的富互联网应用(WAI-ARIA)
W3C 的 WAI-ARIA 提供了有关如何构建动态内容和高级用户界面控件的指导。
资源
文档
辅助技术
测试
- 自动化工具
- 颜色工具
- 其他有用工具
用户
世界卫生组织估计,全球有 15% 的人口存在某种形式的残障,其中 2-4% 为严重残障。也就是说,全球约有 10 亿人;这使得残障人士成为世界上最大的少数群体。
残障类型非常多,大致可分为四类:
- 视觉 - 这些用户可受益于使用屏幕阅读器、屏幕放大、控制屏幕对比度或盲文显示器。
- 听觉 - 这些用户可受益于字幕、文字稿或手语视频。
- 运动 - 这些用户可受益于多种 运动障碍辅助技术:语音识别软件、眼动追踪、单键开关访问、头部指示棒、吸吹开关、大号轨迹球鼠标、自适应键盘或其他辅助技术。
- 认知 - 这些用户可受益于补充媒体、内容的结构化组织、清晰简洁的写作。
查看以下来自 WebAim 的链接,以从用户角度加深理解: