无障碍
Web 无障碍 (简称 a11y),是指确保没有任何障碍阻碍残疾人与万维网上的网站进行互动或访问的包容性做法。Vuetify 组件是为所有基于鼠标的操作提供键盘交互,并在适当的情况下利用 HTML5 语义元素。
Material Design 无障碍
Google 详细介绍了如何创建其组件。它们还提供了一些示例,说明如何在创建应用程序时确保使用最佳实践(超出了 Vuetify 默认支持的范围)。你可以在规范网站上找到有关 implementing accessibility 的更多信息。
激活槽位
Vuetify 对许多组件使用激活插槽,如 v-menu
,v-dialog
等等。 在某些情况下,这些 activator 元素应该具有特定的 a11y 属性,将它们与它们的相应内容联系起来。 为了做到这一点,我们通过插槽范围传递必要的 a11y 选项。
<!-- Vue HTML Markup -->
<template>
<v-menu>
<template v-slot:activator="{ on, attrs }">
<v-btn
v-bind="attrs"
v-on="on"
>
Click me
</v-btn>
</template>
<v-list>
<v-list-item @click="method">
<v-list-item-title>Option 1</v-list-item-title>
</v-list-item>
<v-list-item disabled>
<v-list-item-title>Option 2</v-list-item-title>
</v-list-item>
<v-list-item @click="method">
<v-list-item-title>Option 3</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</template>
当 activator 元素被呈现时,它现在将包含绑定的 a11y 属性
<!-- Rendered Activator HTML Output -->
<button
type="button"
role="button"
aria-haspopup="true"
aria-expanded="false"
>
Click me
</button>
Item slots
在某些情况下,你将插槽用于组件,并且需要正确的 aria 属性才能绑定到元素。当使用 (v-slot) 时,这在插槽范围内传递给你,正如上面的 v-menu
示例所示。然而,还有其他更复杂的组件,你需要将属性绑定到正确的组件以确保获得适当的支持。
v-select
组件将自动配置所有需要 a11y 的属性。每个项目将生成对应的 id, aria-labelledby, aria-selected 和 roles
<!-- Vue HTML Markup -->
<template>
<v-select
:items="['Foo', 'Bar']"
label="Items"
></v-select>
</template>
渲染时,v-select
组件的内容将类似于:
<!-- Rendered `v-select` content HTML Output -->
<div
role="listbox"
tabindex="-1"
>
<div
aria-labelledby="foo-list-item-12"
aria-selected="true"
class="v-list-item"
role="option"
tabindex="0"
>
<div
class="v-list-item__title"
id="foo-list-item-12"
>
Foo
</div>
<div
aria-labelledby="bar-list-item-13"
aria-selected="false"
class="v-list-item"
role="option"
tabindex="0"
>
<div
class="v-list-item__title"
id="bar-list-item-13"
>
Bar
</div>
</div>
</div>
但是,在某些情况下使用插槽时,你将需要利用传递的属性来获得正确的 aria 设置。这个信息同样也适用于 v-autocomplete
, v-combobox
and v-overflow-btn
,因为它们都是 v-select
扩展而来。
template
<template>
<v-select
:items="['Foo', 'Bar', 'Fizz', 'Buzz']"
label="Fizzbuzz"
>
<template v-slot:item="{ item, attrs, on }">
<v-list-item
v-bind="attrs"
v-on="on"
>
<v-list-item-title
:id="attrs['aria-labelledby']"
v-text="item"
></v-list-item-title>
</v-list-item>
</template>
</v-select>
</template>
当在插槽中提供 v-list-item
组件时,aria 属性会通过 attrs 数据属性,并且可以与 v-bind
绑定。
<!-- Vue HTML Markup -->
<template>
<v-select
:items="['Fizz', 'Buzz']"
label="Items"
>
<template v-slot:item="{ item, attrs, on }">
<v-list-item
v-bind="attrs"
v-on="on"
>
<v-list-item-content>
<v-list-item-title
:id="attrs['aria-labelledby']"
v-text="item.title"
></v-list-item-title>
<v-list-item-subtitle v-text="item.sub"></v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
</template>
</v-select>
</template>
为了正确地将标签与正确的 option 关联,你休要绑定 attrs.id
到 v-list-item-title
上的 aria-labelled-by
。这将去报文本被正确关联。请记住,如果你没有使用插槽,这些都会自动完成。
焦点管理和键盘交互
除了属性之外,诸如 v-menu
之类的组件还通过按 ↑ 和 ↓ 在选项之间导航来支持交互。
v-menu
在 v-menu
中,v-list-item
将自动配置为 menuitem 的作用。浏览 Menu 以获得有关组件功能的更多信息。
template script
<template>
<div class="text-center">
<v-menu>
<template v-slot:activator="{ on, attrs }">
<v-btn
v-bind="attrs"
v-on="on"
>
Click me
</v-btn>
</template>
<v-list>
<v-list-item @click="method">
<v-list-item-title>Option 1</v-list-item-title>
</v-list-item>
<v-list-item disabled>
<v-list-item-title>Option 2</v-list-item-title>
</v-list-item>
<v-list-item @click="method">
<v-list-item-title>Option 3</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</div>
</template>
<script>
export default {
methods: {
method () {
// Perform an action
},
},
}
</script>
<!-- Rendered `v-menu` content HTML Output -->
<div
class="v-menu__content"
role="menu"
>
<div class="v-list">
<div
class="v-list-item"
role="menuitem"
tabindex="0"
>
...
</div>
<div
aria-disabled="true"
class="v-list-item"
role="menuitem"
tabindex="-1"
>
...
</div>
</div>
</div>
v-list-item-group
v-list-item-group
组件在按 tab 键时,v-list-item
变得可以互动和导航。 它还将 v-list-item
配置为具有 listitem 的功能。参阅 List-item group 以获取更多关于组件特性的信息。
template script
<template>
<v-card
class="mx-auto"
max-width="500"
>
<v-list>
<v-list-item-group v-model="model">
<v-list-item
v-for="(item, i) in items"
:key="i"
:disabled="item.disabled"
>
<v-list-item-content>
<v-list-item-title v-text="item.text"></v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list-item-group>
</v-list>
</v-card>
</template>
<script>
export default {
data: () => ({
items: [
{
text: 'Item 1',
},
{
text: 'Item 2',
disabled: true,
},
{
text: 'Item 3',
},
],
model: 0,
}),
}
</script>
<!-- Rendered `v-list-group` content HTML Output -->
<div
class="v-list-item-group"
role="listbox"
>
<div
aria-selected="true"
class="v-list-item"
role="listitem"
tabindex="0"
>
...
</div>
<div
aria-disabled="true"
aria-selected="true"
class="v-list-item"
role="listitem"
tabindex="-1"
>
...
</div>
<div
aria-selected="false"
class="v-list-item"
role="listitem"
tabindex="0"
>
...
</div>
</div>
额外资源
虽然 Vuetify 尽可能保证你在开发应用程序中轻松地使用 a11y,但有时候仍然需要额外的信息。 下面可以找到有用的资源列表。