ARIA 支持
本章节主要包含如何快速运用 UIExtension 框架的内置功能实现可访问性,以及相关工具的介绍。如果你想详细了解 ARIA 的技术规范以及最佳实践,可以查阅以下的网址:
- https://www.w3.org/WAI/standards-guidelines/aria/
- https://www.w3.org/TR/wai-aria-practices-1.1/
- https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA
如何使用 UIExtension 启用可访问性
初始化 PDFUI 时,我们需要加载 aria
附加组件:
javascript
new UIExtension.PDFUI({
addons: [
// .... other Add-on
'path/to/lib/uix-addons/aria/addon.info.json' // Make sure that aria is loaded last.
]
// ... other options
})
如果你的应用程序是通过 allInOne.js 来加载插件,因为它已经包含 aria
,所以不需要额外单独加载:
javascript
new UIExtension.PDFUI({
addons: 'path/to/lib/uix-addons/allInOne.js'
// ... other options
})
关于如何加载 add-on 的更详细信息,请参阅 Addons。
UIExtension 内置组件
aria-label
属性
这些内置组件在指定 text
或 label
参数后会自动向生成的 DOM 节点上添加 aria-label
属性,可点击 run
按钮运行示例, 然后使用屏幕阅读器查看效果:
html
<html>
<template id="layout-template">
<webpdf>
<div>
<div>
<gtab text="XButton" group="aria-tab" body="tab1-body" active></gtab>
<gtab text="Dropdown" group="aria-tab" body="tab2-body"></gtab>
<gtab text="Slider" group="aria-tab" body="tab3-body"></gtab>
<gtab text="Ribbon button" group="aria-tab" body="tab4-body"></gtab>
</div>
<div name="tab1-body">
<xbutton text="button"></xbutton>
</div>
<div name="tab2-body">
<dropdown text="Dropdown" style="width: 8em" separate="false">
<xbutton text="Dropdown item 1"></xbutton>
<xbutton text="Dropdown item 2"></xbutton>
</dropdown>
</div>
<div name="tab3-body">
<slider min="0" max="100" step="1" label="Slider label"></slider>
</div>
<div name="tab4-body">
<ribbon-button text="Ribbon button"></ribbon-button>
</div>
</div>
<div class="fv__ui-body">
<viewer></viewer>
</div>
</webpdf>
</template>
</html>
<script>
var CustomAppearance = UIExtension.appearances.Appearance.extend({
getLayoutTemplate: function () {
return document.getElementById('layout-template');
},
disableAll: function () {
}
});
var libPath = window.top.location.origin + '/lib';
var pdfui = new UIExtension.PDFUI({
viewerOptions: {
libPath: libPath,
jr: {
licenseSN: licenseSN,
licenseKey: licenseKey
}
},
renderTo: document.body,
appearance: CustomAppearance,
addons: libPath + '/uix-addons/allInOne.js'
});
</script>
json
{
"iframeOptions": {
"style": "height: 300px"
}
}
视觉隐藏的内容
在有些场景下,我们需要提供一些可供屏幕阅读器等辅助技术访问但视觉上隐藏的内容,并且通过使用 .fv__ui-aria-sr-only
类进行样式设置。这样可以为视觉障碍用户提供有用的信息或提示,比如使用不同的颜色表示危险、警告等不同类型的信息,这种情况下就需要添加额外文本内容告知视觉障碍用户这条信息的类型。
html
<p class="text-danger">
<span class="fv__ui-aria-sr-only">Danger:</span>
This action is not reversible.
</p>
aria 指令
@aria:attr
指令
该指令用于设置以 aria-
开头的属性,指令的写法是 @aria:attr.${aria-property-name}
,aria-property-name
可以参考 该网页,其参数值是一个可执行的表达式:
html
<html>
<template id="layout-template">
<webpdf>
<div @var.value="50">
<input @aria:attr.valuemax="1" @aria:attr.valuemin="0" @aria:attr.valuenow="value + '%'">
<!--Result:
<input aria-valuemax="1" aria-valuemin="0" aria-valuenow="50%" ...>
-->
<!-- source text -->
<input @aria:attr.label="'source text'">
<!--Result:
<input aria-label="source text" ...>
-->
<!-- I18n key -->
<input @aria:attr.label="'aria:labels.gotopage'|i18n">
<!--Result:
<input aria-label="Set page" ...>
-->
</div>
<div class="fv__ui-body">
<viewer></viewer>
</div>
</webpdf>
</template>
</html>
<script>
var CustomAppearance = UIExtension.appearances.Appearance.extend({
getLayoutTemplate: function () {
return document.getElementById('layout-template');
},
disableAll: function () {
}
});
var libPath = window.top.location.origin + '/lib';
var pdfui = new UIExtension.PDFUI({
viewerOptions: {
libPath: libPath,
jr: {
licenseSN: licenseSN,
licenseKey: licenseKey
}
},
renderTo: document.body,
appearance: CustomAppearance,
addons: libPath + '/uix-addons/allInOne.js'
});
</script>
json
{
"iframeOptions": {
"style": "height: 300px"
}
}
@aria:label
指令
该指令用于设置 aria-label
属性, 指令值为 i18n 词条。
html
<html>
<template id="layout-template">
<webpdf>
<div>
<group-list>
<group>
<input @aria:label="aria:labels.gotopage"
placeholder="@aria:label="aria:labels.gotopage"">
<!--Result:
<input aria-label="Set page" ...>
-->
<!-- It is equivalent to: -->
<input @aria:attr.label="'aria:labels.gotopage'|i18n"
placeholder="@aria:attr.label="'aria:labels.gotopage'|i18n"">
<!--Result:
<input aria-label="Set page" ...>
-->
<!-- source text -->
<input @aria:label="source text" placeholder="@aria:label="source text"">
<!--Result:
<input aria-label="source text" ...>
-->
<!-- It is equivalent to: -->
<input @aria:attr.label="'source text'" placeholder="@aria:attr.label="'source text'"">
<!--Result:
<input aria-label="source text" ...>
-->
</group>
</group-list>
<group-list>
<group>
<!-- It can set attributes at a location specified by the dropdown component -->
<!-- Set aria-label on the drop-down arrow -->
<dropdown @aria:label.caret="Toggle Dropdown" text="@aria:label.caret"></dropdown>
</group>
<group>
<!-- Set aria-label on icons -->
<dropdown icon-class="fv__icon-toolbar-hand" @aria:label.icon="Click dropdown icon"
text="@aria:label.icon"></dropdown>
</group>
<group>
<!-- Set aria-label on the input box -->
<dropdown
editable
@aria:label.editor="Click dropdown icon"
selected="1"
text="@aria:label.editor"
>
<dropdown-item>Item 2</dropdown-item>
<dropdown-item>Item 3</dropdown-item>
<dropdown-item>Item 1</dropdown-item>
</dropdown>
</group>
<group>
<!-- Set the aria-label of the list -->
<dropdown @aria:label.list="Items" text="@aria:label.list" separate="false">
<dropdown-item>Item 1</dropdown-item>
<dropdown-item>Item 2</dropdown-item>
<dropdown-item>Item 3</dropdown-item>
</dropdown>
</group>
</group-list>
</div>
<div class="fv__ui-body">
<viewer></viewer>
</div>
</webpdf>
</template>
</html>
<script>
var CustomAppearance = UIExtension.appearances.Appearance.extend({
getLayoutTemplate: function () {
return document.getElementById('layout-template');
},
disableAll: function () {
}
});
var libPath = window.top.location.origin + '/lib';
var pdfui = new UIExtension.PDFUI({
viewerOptions: {
libPath: libPath,
jr: {
licenseSN: licenseSN,
licenseKey: licenseKey
}
},
renderTo: document.body,
appearance: CustomAppearance,
addons: libPath + '/uix-addons/allInOne.js'
});
</script>
<style>
input {
width: 20em;
}
.fv__ui-dropdown {
width: auto;
}
</style>
json
{
"iframeOptions": {
"style": "height: 300px"
}
}
@aria:labelledby
指令
@aria:labelledby
指令用于生成 aria-labelledby
属性。指令值使用的是 UIExtension 的选择器语法,而不是元素的 id。这是因为 aria-labelledby
属性需要通过 id 关联到另外一个元素,而 id 可能引发全局冲突问题,因此我们不建议手写 id 来索引元素。该指令的选择器语法可以避免这一问题。
有关 aria-labelledby
属性的更详细信息,请查阅 该网址。
html
<html>
<template id="layout-template">
<webpdf>
<div>
<span>Field</span>
<!-- This is just for demonstration -->
<span name="a-colon">:</span>
<input type="text" @aria:labelledby="::parent()::childAt(0),a-colon">
</div>
<div class="fv__ui-body">
<viewer></viewer>
</div>
</webpdf>
</template>
</html>
<script>
var CustomAppearance = UIExtension.appearances.Appearance.extend({
getLayoutTemplate: function () {
return document.getElementById('layout-template');
},
disableAll: function () {
}
});
var libPath = window.top.location.origin + '/lib';
var pdfui = new UIExtension.PDFUI({
viewerOptions: {
libPath: libPath,
jr: {
licenseSN: licenseSN,
licenseKey: licenseKey
}
},
renderTo: document.body,
appearance: CustomAppearance,
addons: libPath + '/uix-addons/allInOne.js'
});
</script>
<style>
input {
width: 20em;
}
.fv__ui-dropdown {
width: auto;
}
</style>
json
{
"iframeOptions": {
"style": "height: 300px"
}
}
上述示例中,@aria:labelledby="::parent()::childAt(0),,a-colon"
指定了 <input>
前面两个 span 组件的 id 为标签。有关选择器语法更详细的信息,可以参阅 组件选择器。
@aria:describedby
指令
@aria:describedby
指令的用法和原理和 @aria:labelledby
基本相同,此处不做过多说明。
有关 aria-describedby
更详细的信息,请查阅 该网址。
html
<html>
<template id="layout-template">
<webpdf>
<div>
<span>Field:</span>
<input type="text" @aria:labelledby="::parent()::childAt(0)"
@aria:describedby="::nextSiblings(),more-description">
<span class="fv__ui-aria-sr-only">
Description of text input.
</span>
<span class="fv__ui-aria-sr-only" name="more-description">
More description of text input.
</span>
</div>
<div class="fv__ui-body">
<viewer></viewer>
</div>
</webpdf>
</template>
</html>
<script>
var CustomAppearance = UIExtension.appearances.Appearance.extend({
getLayoutTemplate: function () {
return document.getElementById('layout-template');
},
disableAll: function () {
}
});
var libPath = window.top.location.origin + '/lib';
var pdfui = new UIExtension.PDFUI({
viewerOptions: {
libPath: libPath,
jr: {
licenseSN: licenseSN,
licenseKey: licenseKey
}
},
renderTo: document.body,
appearance: CustomAppearance,
addons: libPath + '/uix-addons/allInOne.js'
});
</script>
<style>
input {
width: 20em;
}
.fv__ui-dropdown {
width: auto;
}
</style>
json
{
"iframeOptions": {
"style": "height: 300px"
}
}
@aria:rel
指令
ARIA 规范中,除了 aria-labelledby
和 aria-describedby
以外,还有很多需要关联其它元素的属性。@aria:rel
指令封装了这些常用的属性:
aria-activedescendant
,指令写法:aria:rel.activedescendant="selecor,..."
aria-flowto
,指令写法:aria:rel.flowto="selecor,..."
aria-owns
,指令写法:aria:rel.owns="selecor,..."
aria-controls
,指令写法:aria:rel.controls="selecor,..."
@aria:circular-focus
指令
该指令用来控制组件内元素的焦点,实现循环跳转功能。通常用于弹窗或者一个独立的 UI 区域。
可参照下面的示例,点击 run
按钮运行。
html
<html>
<template id="layout-template">
<webpdf>
<div>
<group-list>
<group>
<xbutton>button 1</xbutton>
<xbutton>button 2</xbutton>
<xbutton>button 3</xbutton>
</group>
<group @aria:circular-focus>
<xbutton @tooltip
tooltip-title="Press 'Shift + Tab' will switch focus to 'button 6' instead of 'button 3'">
button 4
</xbutton>
<xbutton>button 5</xbutton>
<xbutton @tooltip tooltip-title="Press 'Tab' will switch focus to 'button 4' instead of 'button 7'">
button 6
</xbutton>
</group>
<group>
<xbutton>button 7</xbutton>
</group>
</group-list>
</div>
<div class="fv__ui-body">
<viewer></viewer>
</div>
</webpdf>
</template>
</html>
<script>
var CustomAppearance = UIExtension.appearances.Appearance.extend({
getLayoutTemplate: function () {
return document.getElementById('layout-template');
},
disableAll: function () {
}
});
var libPath = window.top.location.origin + '/lib';
var pdfui = new UIExtension.PDFUI({
viewerOptions: {
libPath: libPath,
jr: {
licenseSN: licenseSN,
licenseKey: licenseKey
}
},
renderTo: document.body,
appearance: CustomAppearance,
addons: libPath + '/uix-addons/allInOne.js'
});
</script>
<style>
input {
width: 20em;
}
.fv__ui-dropdown {
width: auto;
}
</style>
json
{
"iframeOptions": {
"style": "height: 300px"
}
}