Web 無障礙訪問 (也(yě)稱爲 a11y) 是指創建可供任何人使用(yòng)的網站(zhàn)的做法——無論是身患某種障礙、通過慢速的網絡連接訪問、使用(yòng)老(lǎo)舊或損壞的硬件,還是僅處于某種不方便的環境。例如,在視(shì)頻中添加字幕可以幫助失聰、有聽力障礙或身處嘈雜(zá)環境而聽不到(dào)手機的用(yòng)戶。同樣地,确保文(wén)字樣式沒有處于太低(dī)的對(duì)比度,可以對(duì)低(dī)視(shì)力用(yòng)戶和(hé)在明(míng)亮(liàng)的強光下(xià)使用(yòng)手機的用(yòng)戶都有所幫助。
你(nǐ)是否已經準備開(kāi)始卻又無從(cóng)下(xià)手?
請(qǐng)先閱讀由萬維網聯盟 (W3C) 提供的 Web 無障礙訪問的規劃和(hé)管理(lǐ)。
跳過鏈接
你(nǐ)應該在每個頁面的頂部添加一個直接指向主内容區(qū)域的鏈接,這(zhè)樣用(yòng)戶就可以跳過在多個網頁上(shàng)重複的内容。
通常這(zhè)個鏈接會(huì)放(fàng)在 App.vue 的頂部,這(zhè)樣它就會(huì)是所有頁面上(shàng)的第一個可聚焦元素:
template
<ul class="skip-links">
<li>
<a href="#main" ref="skipLink" class="skip-link">Skip to main content</a>
</li>
</ul>
若想在非聚焦狀态下(xià)隐藏該鏈接,可以添加以下(xià)樣式:
css
.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;
}
一旦用(yòng)戶改變路由,請(qǐng)将焦點放(fàng)回到(dào)這(zhè)個“跳過”鏈接。通過如下(xià)方式聚焦“跳過”鏈接的模闆引用(yòng) (假設使用(yòng)了(le) vue-router) 即可實現(xiàn):
vue
<script>
export default {
watch: {
$route() {
this.$refs.skipLink.focus()
}
}
}
</script>
閱讀關于跳過鏈接到(dào)主要内容的文(wén)檔
内容結構
确保設計(jì)可以支持易于訪問的實現(xiàn)是無障礙訪問最重要的部分之一。設計(jì)不僅要考慮顔色對(duì)比度、字體選擇、文(wén)本大(dà)小(xiǎo)和(hé)語言,還要考慮應用(yòng)中的内容是如何組織的。
标題
用(yòng)戶可以通過标題在應用(yòng)中進行導航。爲應用(yòng)的每個部分設置描述性标題,這(zhè)可以讓用(yòng)戶更容易地預測每個部分的内容。說到(dào)标題,有幾個推薦的無障礙訪問實踐:
按級别順序嵌套标題:<h1> - <h6>
不要在一個章節内跳躍标題的級别
使用(yòng)實際的标題标記,而不是通過對(duì)文(wén)本設置樣式以提供視(shì)覺上(shàng)的标題
閱讀更多有關标題的信息
template
<main role="main" aria-labelledby="main-title">
<h1 id="main-title">Main title</h1>
<section aria-labelledby="section-title-1">
<h2 id="section-title-1"> Section Title </h2>
<h3>Section Subtitle</h3>
<!-- 内容 -->
</section>
<section aria-labelledby="section-title-2">
<h2 id="section-title-2"> Section Title </h2>
<h3>Section Subtitle</h3>
<!-- 内容 -->
<h3>Section Subtitle</h3>
<!-- 内容 -->
</section>
</main>
Landmarks
Landmark 會(huì)爲應用(yòng)中的章節提供訪問規劃。依賴輔助技術的用(yòng)戶可以跳過内容直接導航到(dào)應用(yòng)的每個部分。你(nǐ)可以使用(yòng) ARIA role 幫助你(nǐ)實現(xiàn)這(zhè)個目标。
HTML ARIA Role 地标的目的
header role="banner" 主标題:頁面的标題
nav role="navigation" 适合用(yòng)作(zuò)文(wén)檔或相關文(wén)檔導航的鏈接集合
main role="main" 文(wén)檔的主體或中心内容
footer role="contentinfo" 關于父級文(wén)檔的信息:腳注/版權/隐私聲明(míng)鏈接
aside role="complementary" 用(yòng)來(lái)支持主内容,同時(shí)其自(zì)身的内容是相對(duì)獨立且有意義的
無對(duì)應元素 role="search" 該章節包含整個應用(yòng)的搜索功能(néng)
form role="form" 表單相關元素的集合
section role="region" 相關的且用(yòng)戶可能(néng)會(huì)導航至此的内容。必須爲該元素提供 label
提示:
建議(yì)同時(shí)使用(yòng) landmark HTML 元素和(hé) role 屬性,以最大(dà)程度地兼容不支持 HTML5 語義元素的傳統浏覽器。
閱讀更多有關标題的細節
語義化表單
當創建一個表單,你(nǐ)可能(néng)使用(yòng)到(dào)以下(xià)幾個元素:<form>、<label>、<input>、<textarea> 和(hé) <button>。
标簽通常放(fàng)置在表格字段的頂部或左側:
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">Submit</button>
</form>
請(qǐng)注意這(zhè)裏我們是如何在表單元素中引入 autocomplete='on' 的,它将應用(yòng)于表單中的所有 input 框。你(nǐ)也(yě)可以爲每個 input 框都設置不同的 autocomplete attribute 的值。
标簽
提供标簽來(lái)描述所有表單控件的用(yòng)途;使 for 和(hé) id 鏈接起來(lái):
template
<label for="name">Name</label>
<input type="text" name="name" id="name" v-model="name" />
如果你(nǐ)在 chrome 開(kāi)發工(gōng)具中檢查這(zhè)個元素,并打開(kāi) Elements 選項卡中的 Accessibility 選項卡,你(nǐ)将看(kàn)到(dào)輸入是如何從(cóng)标簽中獲取其名稱的:
警告:
你(nǐ)可能(néng)還見過這(zhè)樣的包裝 input 框的标簽:
template
<label>
Name:
<input type="text" name="name" id="name" v-model="name" />
</label>
但(dàn)我們仍建議(yì)你(nǐ)顯式地爲 input 元素設置 id 相匹配的标簽,以更好(hǎo)地實現(xiàn)無障礙訪問。
aria-label
你(nǐ)也(yě)可以爲 input 框配置一個帶有 aria-label 的無障礙訪問名。
template
<label for="name">Name</label>
<input
type="text"
name="name"
id="name"
v-model="name"
:aria-label="nameLabel"
/>
aria-labelledby
使用(yòng) aria-labelledby 類似于 aria-label,除非标簽文(wén)本在屏幕上(shàng)可見。它通過 id 與其他(tā)元素配對(duì),你(nǐ)可以鏈接多個 id:
template
<form
class="demo"
action="/dataCollectionLocation"
method="post"
autocomplete="on"
>
<h1 id="billing">Billing</h1>
<div class="form-item">
<label for="name">Name:</label>
<input
type="text"
name="name"
id="name"
v-model="name"
aria-labelledby="billing name"
/>
</div>
<button type="submit">Submit</button>
</form>
aria-describedby
aria-describedby 的用(yòng)法與 aria-labelledby 相同,它提供了(le)一條用(yòng)戶可能(néng)需要的附加描述信息。這(zhè)可用(yòng)于描述任何輸入的标準:
template
<form
class="demo"
action="/dataCollectionLocation"
method="post"
autocomplete="on"
>
<h1 id="billing">Billing</h1>
<div class="form-item">
<label for="name">Full Name:</label>
<input
type="text"
name="name"
id="name"
v-model="name"
aria-labelledby="billing name"
aria-describedby="nameDescription"
/>
<p id="nameDescription">Please provide first and last name.</p>
</div>
<button type="submit">Submit</button>
</form>
占位符
避免使用(yòng)占位符,因爲它們可能(néng)會(huì)使許多用(yòng)戶感到(dào)困惑。
占位符的缺陷之一是默認情況下(xià)它們不符合顔色對(duì)比度标準;應當修改其顔色,讓它看(kàn)起來(lái)像是預先填入 input 框中的數據一樣。
<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">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;
}
最好(hǎo)在表單外(wài)提供所有用(yòng)戶需要填寫輸入的信息。
用(yòng)法說明(míng)
添加用(yòng)法說明(míng)時(shí),請(qǐng)确保将其正确鏈接到(dào)目标 input 框。你(nǐ)可以提供附加用(yòng)法說明(míng)并在 aria-labelledby 内綁定多個 id。這(zhè)可以使設計(jì)更加靈活。
template
<fieldset>
<legend>Using aria-labelledby</legend>
<label id="date-label" for="date">Current Date:</label>
<input
type="date"
name="date"
id="date"
aria-labelledby="date-label date-instructions"
/>
<p id="date-instructions">MM/DD/YYYY</p>
</fieldset>
或者,你(nǐ)可以通過 aria-describedby 将用(yòng)法說明(míng)附加到(dào) input 框上(shàng)。
template
<fieldset>
<legend>Using aria-describedby</legend>
<label id="dob" for="dob">Date of Birth:</label>
<input type="date" name="dob" id="dob" aria-describedby="dob-instructions" />
<p id="dob-instructions">MM/DD/YYYY</p>
</fieldset>
隐藏内容
通常,即使 input 框具有無障礙的名稱,也(yě)不建議(yì)在視(shì)覺上(shàng)隐藏标簽。但(dàn)是,如果可以借助周圍的内容來(lái)理(lǐ)解輸入的功能(néng),那麽我們也(yě)可以隐藏視(shì)覺标簽。
讓我們看(kàn)看(kàn)這(zhè)個搜索框:
template
<form role="search">
<label for="search" class="hidden-visually">Search: </label>
<input type="text" name="search" id="search" v-model="search" />
<button type="submit">Search</button>
</form>
現(xiàn)在,隻要視(shì)力情況良好(hǎo),用(yòng)戶可以就能(néng)通過按鈕的内容識别出該 input 框的目的。
此時(shí)我們可以使用(yòng) CSS 從(cóng)視(shì)覺上(shàng)隐藏元素,同時(shí)也(yě)不會(huì)影響到(dào)無障礙訪問:
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" 在無障礙訪問時(shí)被隐藏,但(dàn)對(duì)其他(tā)可視(shì)用(yòng)戶仍然是可見的。不要在可聚焦的元素上(shàng)使用(yòng)它,請(qǐng)隻在裝飾性的、重複的或屏幕外(wài)的内容上(shàng)使用(yòng)它。
template
<p>This is not hidden from screen readers.</p>
<p aria-hidden="true">This is hidden from screen readers.</p>
按鈕
在表單中使用(yòng)按鈕時(shí),必須設置類型以防止提交表單。 你(nǐ)也(yě)可以使用(yòng)一個 input 元素來(lái)創建按鈕:
template
<form action="/dataCollectionLocation" method="post" autocomplete="on">
<!-- 按鈕 -->
<button type="button">Cancel</button>
<button type="submit">Submit</button>
<!-- 輸入按鈕 -->
<input type="button" value="Cancel" />
<input type="submit" value="Submit" />
</form>
功能(néng)圖片
你(nǐ)可以使用(yòng)這(zhè)種方式來(lái)創建一個帶有功能(néng)的圖片。
input 框
這(zhè)些(xiē)圖片會(huì)像一個類型爲 submit 的表單按鈕一樣
template
<form role="search">
<label for="search" class="hidden-visually">Search: </label>
<input type="text" name="search" id="search" v-model="search" />
<input
type="image"
class="btnImg"
src="https://img.icons8.com/search"
alt="Search"
/>
</form>
圖标
template
<form role="search">
<label for="searchIcon" class="hidden-visually">Search: </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">Search</span>
</button>
</form>
規範
萬維網聯盟 (W3C) Web 無障礙訪問倡議(yì) (WAI) 爲不同的組件制定了(le) Web 無障礙性标準:
用(yòng)戶代理(lǐ)無障礙訪問指南 (UAAG)
浏覽器和(hé)媒體查詢,包括一些(xiē)其他(tā)方面的輔助技術
創作(zuò)工(gōng)具無障礙訪問指南 (ATAG)
創作(zuò)工(gōng)具
Web 内容無障礙訪問指南 (WCAG)
網站(zhàn)内容 - 由開(kāi)發者、創作(zuò)工(gōng)具和(hé)無障礙訪問評估工(gōng)具使用(yòng)。
網絡内容無障礙指南 (WCAG)
WCAG 2.1 繼承自(zì) WCAG 2.0,接納 Web 演進過程中的新技術。W3C 鼓勵在開(kāi)發或更新 Web 無障礙訪問策略時(shí)使用(yòng) WCAG 的最新版本。
WCAG 2.1 四大(dà)指導原則 (縮寫 POUR):
可感知(zhī)性
用(yòng)戶必須能(néng)夠感知(zhī)所渲染的信息
可操作(zuò)性
表單界面,控件和(hé)導航是可操作(zuò)的
可理(lǐ)解性
信息和(hé)用(yòng)戶界面的操作(zuò)必須爲所有用(yòng)戶所理(lǐ)解
健壯性
随着技術的進步,用(yòng)戶必須能(néng)夠訪問内容
Web 無障礙倡議(yì) – 無障礙訪問豐富的互聯網應用(yòng) (WAI-ARIA)
W3C 的 WAI-ARIA 爲如何構建動态内容和(hé)高(gāo)階用(yòng)戶界面控件提供了(le)指導。
可便捷訪問的豐富互聯網應用(yòng) (WAI-ARIA) 1.2
WAI-ARIA 實踐 1.2
網站(zhàn)建設開(kāi)發|APP設計(jì)開(kāi)發|小(xiǎo)程序建設開(kāi)發