被多數(shù)前端開發(fā)忽略的重要特性!
作為前端開發(fā)者,我們常常沉浸在UI動效、性能優(yōu)化和新技術(shù)棧的研究中,卻忽視了一個直接影響25%用戶的重要問題——Web 可訪問性。本文將深入解析前端可訪問性的核心要點及具體實現(xiàn)。
可訪問性是什么?
Web 可訪問性是指通過設(shè)計和開發(fā)技術(shù),確保網(wǎng)頁或應(yīng)用能夠被所有人無障礙地訪問和使用,包括殘障人士、老年用戶、臨時受傷者(如手部受傷)或使用特殊設(shè)備(如屏幕閱讀器、語音控制工具)的人群。其核心目標(biāo)是消除訪問障礙,實現(xiàn)信息平等。
Web 可訪問性的重要性:
- 法律合規(guī):許多國家和地區(qū)(如歐盟、美國)要求公共網(wǎng)站必須符合可訪問性標(biāo)準(zhǔn)(如 WCAG),否則可能面臨法律風(fēng)險。如果你的應(yīng)用用戶人群是這些國家的,就需要特別關(guān)注開發(fā)中的可訪問性。
- 用戶體驗:提升所有用戶的操作便利性,例如清晰的導(dǎo)航、高對比度配色對普通用戶同樣友好。
- SEO 優(yōu)化:可訪問性實踐(如語義化 HTML)通常與搜索引擎優(yōu)化(SEO)兼容,提升搜索排名。
WCAG
WCAG(Web Content Accessibility Guidelines,網(wǎng)頁內(nèi)容可訪問性指南)是由 W3C(萬維網(wǎng)聯(lián)盟)制定的國際標(biāo)準(zhǔn),旨在確保網(wǎng)頁內(nèi)容對所有人均可訪問和使用。
根據(jù) Web 內(nèi)容可訪問性指南(WCAG),Web 可訪問性可以歸納為以下四個核心原則:
- 可感知: 用戶必須能夠感知提供的信息。
文本替代:為非文本內(nèi)容(如圖片、圖表)提供 alt
文本或描述。
多媒體可訪問:為視頻提供字幕,為音頻提供文本轉(zhuǎn)錄。
適配性:內(nèi)容在不同設(shè)備(如屏幕閱讀器、移動端)上可正常顯示。
- 可操作: 用戶界面組件和導(dǎo)航必須是可操作的。
- 鍵盤導(dǎo)航:所有功能可通過鍵盤(Tab、Enter、方向鍵)操作。
- 避免閃爍內(nèi)容:防止快速閃爍的動畫引發(fā)光敏性癲癇。
- 足夠時間:用戶有充足時間閱讀或操作(如表單填寫倒計時可延長)。
- 可理解: 用戶必須能夠理解和使用信息和用戶界面。
- 一致性:導(dǎo)航、標(biāo)簽、按鈕功能保持一致。
- 錯誤提示:表單輸入錯誤時提供明確的文字說明和修正建議。
- 語言明確:避免使用復(fù)雜術(shù)語,頁面語言通過
lang
屬性聲明。 - 健壯: 內(nèi)容必須兼容當(dāng)前和未來的技術(shù)。
- 語義化 HTML:使用標(biāo)準(zhǔn)標(biāo)簽(如
<button>
、<nav>
),避免濫用<div>
模擬控件。 - ARIA 支持:為動態(tài)內(nèi)容補充 ARIA 屬性(如
role
、aria-label
)。
WCAG 要求分為三個等級,從低到高依次為:
可訪問性的前端實現(xiàn)
Web 可訪問性需要貫穿開發(fā)全流程,從前端技術(shù)實現(xiàn)到設(shè)計協(xié)作,再到測試驗證。
語義化HTML
根據(jù)內(nèi)容的含義選擇合適的 HTML 標(biāo)簽,這有助于屏幕閱讀器等輔助技術(shù)理解頁面結(jié)構(gòu),方便用戶導(dǎo)航。
<!-- 錯誤:用 div 模擬按鈕 -->
<div onclick="submit()">提交</div>
<!-- 正確:語義化按鈕 -->
<button onclick="submit()">提交</button>
常見的語義化標(biāo)簽包括:
標(biāo)簽 | 作用 |
| 定義文檔或節(jié)的頁眉,包含介紹性內(nèi)容,如網(wǎng)站標(biāo)志、標(biāo)題、導(dǎo)航欄等 |
| 專門定義導(dǎo)航鏈接部分,包含指向不同頁面或同一頁面不同部分的主要導(dǎo)航鏈接 |
| 規(guī)定文檔的主要內(nèi)容,該內(nèi)容應(yīng)獨一無二,不包含重復(fù)出現(xiàn)的內(nèi)容 |
| 表示文檔中獨立、完整且可獨立分發(fā)的內(nèi)容塊,如博客文章、新聞報道等 |
| 對文檔內(nèi)容進行分塊,將相似主題的內(nèi)容分組,不一定能獨立存在 |
| 定義所處內(nèi)容之外的內(nèi)容,常表現(xiàn)為側(cè)邊欄或插入內(nèi)容,與周圍內(nèi)容相關(guān)但非主要部分 |
| 定義文檔或節(jié)的頁腳,包含版權(quán)信息、作者信息、聯(lián)系方式等 |
| 定義不同級別的標(biāo)題,構(gòu)建文檔大綱結(jié)構(gòu),利于搜索引擎理解及用戶瀏覽 |
| 創(chuàng)建無序列表,列表項無特定順序,以項目符號顯示 |
| 創(chuàng)建有序列表,列表項按數(shù)字或字母順序排列,適用于強調(diào)順序的內(nèi)容 |
| 創(chuàng)建定義列表,包含 |
| 定義從其他來源引用的內(nèi)容,視覺上常呈現(xiàn)為縮進,可搭配 |
| 定義短的行內(nèi)引用,瀏覽器自動在兩端加引號 |
| 定義日期和時間,方便瀏覽器和搜索引擎識別,可通過 |
語義化 HTML 的好處:
- 提高可訪問性: 語義化HTML可以幫助輔助技術(shù)(如屏幕閱讀器)更好地理解頁面結(jié)構(gòu)和內(nèi)容,從而為殘障用戶提供更好的體驗。
- 增強SEO(搜索引擎優(yōu)化): 搜索引擎爬蟲依賴 HTML 標(biāo)簽來理解網(wǎng)頁的內(nèi)容和結(jié)構(gòu)。使用語義化HTML可以使搜索引擎更準(zhǔn)確地抓取和索引頁面,有助于提高搜索排名。
- 改善代碼可讀性和維護性: 語義化HTML使代碼更具結(jié)構(gòu)性和邏輯性,易于理解和維護。
- 符合Web標(biāo)準(zhǔn)和最佳實踐: 語義化HTML符合W3C和其他標(biāo)準(zhǔn)組織推薦的最佳實踐,有助于構(gòu)建高質(zhì)量的Web應(yīng)用。
鍵盤導(dǎo)航
鍵盤導(dǎo)航是 Web 可訪問性的重要組成部分,它允許用戶僅使用鍵盤來瀏覽和操作網(wǎng)頁,這對于那些無法使用鼠標(biāo)或其他指針設(shè)備的用戶(如肢體殘障人士、鍵盤快捷方式偏好者)來說至關(guān)重要。
可聚焦元素
可聚焦元素是指用戶可以通過鍵盤的 Tab 鍵將焦點移動到這些元素上的元素,并且焦點順序應(yīng)符合邏輯。常見的可聚焦元素包括鏈接(<a>
)、按鈕(<button>
)、輸入框(<input>
、<textarea>
)、下拉框(<select>
)等。
<a href="#">前端充電寶</a>
<button>點擊我</button>
<input type="text" placeholder="輸入內(nèi)容">
<select>
<option value="1">選項1</option>
<option value="2">選項2</option>
</select>
在上述代碼中,用戶可以使用 Tab 鍵依次將焦點移動到鏈接、按鈕、輸入框和下拉框上。
焦點順序
- 自然順序:鍵盤焦點的移動順序應(yīng)該與網(wǎng)頁內(nèi)容的邏輯和視覺順序一致。通常,焦點會按照 HTML 文檔中元素出現(xiàn)的先后順序進行移動。例如,在一個表單中,焦點會從第一個輸入框開始,依次移動到后續(xù)的輸入框、按鈕等元素。
- 調(diào)整順序:在某些情況下,可能需要調(diào)整焦點順序。可以使用
tabindex
屬性來實現(xiàn)。
tabindex="0"
:將元素添加到正常的 Tab 順序中,即使該元素默認(rèn)不可聚焦。
tabindex="-1"
:使元素可聚焦,但不包含在正常的 Tab 順序中,可以通過 JavaScript 等方式將焦點設(shè)置到該元素上。
tabindex="正數(shù)"
:指定元素的焦點順序,數(shù)值越小越先獲得焦點,但不建議過多使用這種方式,因為可能會破壞自然的焦點順序。
焦點可見性
當(dāng)元素獲得焦點時,應(yīng)該有明顯的視覺指示,以便用戶清楚地知道當(dāng)前焦點所在的位置。可以通過修改元素的樣式(如改變邊框顏色、添加背景色、顯示下劃線等)來實現(xiàn)。
button:focus, input:focus, a:focus {
outline: 2px solid #007BFF; /* 藍色邊框 */
box-shadow: 0 0 5px rgba(0, 123, 255, 0.5); /* 添加陰影效果 */
}
注意事項:
- 避免移除默認(rèn)的
outline
樣式,除非提供了更好的替代方案。 - 提供高對比度的顏色,確保視覺上有足夠的可見性。
鍵盤操作支持
- 常見操作:不同類型的元素應(yīng)該支持相應(yīng)的鍵盤操作。例如:
- 鏈接:按下 Enter 鍵可以激活鏈接,跳轉(zhuǎn)到相應(yīng)的頁面。
- 按鈕:按下 Enter 鍵或 Space 鍵可以觸發(fā)按鈕的點擊事件。
- 輸入框:可以使用方向鍵在輸入框內(nèi)移動光標(biāo),按下 Enter 鍵在某些情況下可以提交表單。
- 下拉框:使用方向鍵可以選擇下拉框中的選項,按下 Enter 鍵可以確認(rèn)選擇。
- 自定義元素的鍵盤操作:對于自定義的交互元素(如自定義菜單、對話框等),需要通過 JavaScript 來實現(xiàn)相應(yīng)的鍵盤操作支持。例如,一個自定義菜單可以通過監(jiān)聽鍵盤事件,根據(jù)用戶按下的方向鍵來切換菜單項的選中狀態(tài),按下 Enter 鍵來執(zhí)行相應(yīng)的操作。
跳過導(dǎo)航
對于一些大型網(wǎng)頁,可能存在大量的導(dǎo)航鏈接和重復(fù)的內(nèi)容,用戶可能希望快速跳過這些內(nèi)容,直接訪問主要內(nèi)容。這時可以提供 “跳過導(dǎo)航” 鏈接。
實現(xiàn)方法:在頁面頂部添加一個隱藏的鏈接,當(dāng)用戶使用鍵盤將焦點移動到該鏈接時,鏈接顯示出來,用戶按下 Enter 鍵可以直接跳轉(zhuǎn)到頁面的主要內(nèi)容區(qū)域。
<a href="#main-content" class="skip-nav">跳過導(dǎo)航</a>
<header>
<nav>
<ul>
<li><a href="#">首頁</a></li>
<li><a href="#">產(chǎn)品</a></li>
<li><a href="#">關(guān)于我們</a></li>
</ul>
</nav>
</header>
<main id="main-content">
<h1>主要內(nèi)容標(biāo)題</h1>
<p>主要內(nèi)容文本...</p>
</main>
.skip-nav {
position: absolute;
top: -40px;
left: 0;
background: #fff;
padding: 8px;
border: 1px solid #ccc;
transition: top 0.3s ease;
}
.skip-nav:focus {
top: 0;
}
這樣,當(dāng)用戶使用鍵盤將焦點移動到該鏈接時,鏈接會顯示出來,按下 Enter 鍵可以直接跳轉(zhuǎn)到頁面的主要內(nèi)容區(qū)域。
測試驗證
- 手動測試: 使用鍵盤在網(wǎng)頁上進行導(dǎo)航,檢查焦點順序是否正確、焦點可見性是否明顯、元素的鍵盤操作是否正常等。
Tab鍵測試:通過Tab鍵逐個測試頁面上的交互元素,確保每個元素都可以被聚焦并操作。
Shift + Tab:測試反向?qū)Ш剑_保焦點順序正確。
Enter和Space 鍵:測試按鈕、鏈接等交互元素是否可以通過Enter或Space鍵激活。
Esc鍵:測試模態(tài)對話框、下拉菜單等是否可以通過Esc鍵關(guān)閉。
- 自動化測試:使用 axe-core 工具庫進行檢查。
ARIA 屬性
ARIA(Accessible Rich Internet Applications)屬性是 HTML5 規(guī)范的一部分,旨在幫助開發(fā)者增強網(wǎng)頁的可訪問性,特別是在處理動態(tài)內(nèi)容和復(fù)雜用戶界面時。通過使用ARIA屬性,可以為屏幕閱讀器和其他輔助技術(shù)提供更多的信息,從而提升用戶體驗。
ARIA 屬性主要分為三類:角色、狀態(tài)、屬性。
角色
角色定義了元素在頁面中的功能或用途,常見的角色包括button
、menu
、dialog
等。
role="button"
:將一個普通的<div>
元素定義為按鈕,使其具有按鈕的語義。
<div role="button" tabindex="0">前端充電寶</div>
role="menu"
和role="menuitem"
:用于創(chuàng)建自定義菜單,明確菜單和菜單項的角色。
<ul role="menu">
<li role="menuitem"><a href="#">選項1</a></li>
<li role="menuitem"><a href="#">選項2</a></li>
</ul>
role="dialog"
:用于定義一個對話框。
<div id="dialog" role="dialog" aria-modal="true">
<h2>標(biāo)題</h2>
<p>內(nèi)容</p>
<button id="closeDialog">關(guān)閉</button>
</div>
注意事項:
- 盡量使用原生HTML元素(如
<button>
、<nav>
等),它們自帶語義化角色。 - 只有在必要時才使用
role
屬性來增強自定義組件的可訪問性。
狀態(tài)
狀態(tài)表示元素當(dāng)前的狀態(tài),如是否選中、是否展開等。常見的狀態(tài)包括aria-checked
、aria-expanded
等。
aria-checked
:用于復(fù)選框和單選框,指示其選中狀態(tài)。
<input type="checkbox" id="check-box" aria-checked="false">
<label for="check-box">選擇</label>
aria - expanded
:用于可展開 / 折疊的元素,如菜單、手風(fēng)琴組件等,指示其展開狀態(tài)。
<button aria - controls="content" aria - expanded="false">展開內(nèi)容</button>
<div id="content" hidden>具體內(nèi)容</div>
屬性
屬性提供了額外的信息,如標(biāo)簽、描述等。常見的屬性包括aria-label
、aria-labelledby
、aria-describedby
等。
aria-label
:為元素提供一個明確的標(biāo)簽,用于替代元素內(nèi)部的文本,特別是當(dāng)元素沒有可見文本時,適用于簡單的替代文本。
<input type="search" aria-label="搜索框">
<button aria-label="關(guān)閉菜單">X</button>
aria-labelledby
:引用其他元素的ID作為標(biāo)簽來源,適用于引用現(xiàn)有文本作為標(biāo)簽的情況。
<h1 id="page-title">網(wǎng)站</h1>
<nav aria-labelledby="page-title">
<ul>
<li><a href="#home">首頁</a></li>
<li><a href="#about">關(guān)于我們</a></li>
</ul>
</nav>
aria-describedby
用于為元素提供額外的描述信息,通常與表單驗證錯誤消息一起使用。
<label for="email">郵箱地址:</label>
<input type="email" id="email" name="email" aria-invalid="true" aria-describedby="email-error">
<span id="email-error" class="error">請輸入有效的郵箱地址</span>
多媒體內(nèi)容
確保多媒體內(nèi)容對所有用戶都是可訪問的,包括視力障礙者、聽力障礙者以及其他有特殊需求的用戶,是創(chuàng)建包容性網(wǎng)站的重要部分。
圖片可訪問性
- 替代文本: 為圖像提供替代文本(
alt
屬性),以便屏幕閱讀器能夠描述圖像的內(nèi)容。需要注意:
提供有意義的alt
屬性,避免使用空字符串(除非圖像是純粹裝飾性的)。
對于裝飾性圖像,可以使用alt=""
來告訴屏幕閱讀器忽略該圖像。
<img src="logo.png" alt="公司Logo">
- 長描述: 對于復(fù)雜的圖像或圖表,簡單的
alt
屬性可能不足以描述其全部內(nèi)容,此時可以使用<figcaption>
標(biāo)簽結(jié)合<figure>
標(biāo)簽為圖像添加說明。
<figure>
<img src="complex_graph.png" alt="一張復(fù)雜的銷售數(shù)據(jù)折線圖">
<figcaption>該折線圖展示了過去一年中不同季度的產(chǎn)品銷售數(shù)據(jù)變化趨勢。</figcaption>
</figure>
視頻可訪問性
- 字幕: 為視頻添加字幕,幫助聽力障礙者理解視頻內(nèi)容,也有助于在嘈雜環(huán)境或用戶選擇靜音時理解視頻內(nèi)容。可以在
<video>
標(biāo)簽中使用<track>
標(biāo)簽添加字幕文件,kind
屬性設(shè)置為captions
。
<video controls>
<source src="example.mp4" type="video/mp4">
<track kind="captions" src="captions.vtt" srclang="zh" label="中文字幕">
</video>
- 音頻描述: 音頻描述是對視頻中視覺內(nèi)容的口頭描述,幫助視力障礙者理解視頻中的重要視覺元素。同樣使用
<track>
標(biāo)簽來實現(xiàn),kind
屬性設(shè)置為descriptions
。
<video controls>
<source src="video.mp4" type="video/mp4">
<track kind="descriptions" src="descriptions.vtt" srclang="zh" label="視頻描述">
</video>
- 控制和交互: 提供易于使用的視頻控制功能,讓所有用戶都能方便地播放、暫停、調(diào)整音量、快進等。可以在
<video>
標(biāo)簽中添加controls
屬性,顯示默認(rèn)的視頻控制條。也可以通過 JavaScript 自定義控制界面,但要確保其可通過鍵盤操作。
<video id="myVideo" controls>
<source src="example.mp4" type="video/mp4">
</video>
<script>
const video = document.getElementById('myVideo');
// 添加鍵盤事件監(jiān)聽器
document.addEventListener('keydown', (e) => {
if (e.key = ' ') { // 空格鍵播放/暫停
e.preventDefault();
if (video.paused) {
video.play();
} else {
video.pause();
}
} else if (e.key = 'ArrowLeft') { // 左箭頭后退5秒
video.currentTime -= 5;
} else if (e.key === 'ArrowRight') { // 右箭頭前進5秒
video.currentTime += 5;
}
});
</script>
音頻可訪問性
- 音頻轉(zhuǎn)錄: 為聽障用戶或在無法播放音頻的情況下提供音頻內(nèi)容的文字版本。
<audio controls>
<source src="audio.mp3" type="audio/mpeg">
</audio>
<p>點擊 <a href="audio_transcription.txt">這里</a> 查看音頻轉(zhuǎn)錄文本。</p>
- 音頻控制: 確保音頻播放器的控制按鈕可以通過鍵盤操作,并且對屏幕閱讀器友好。
<audio id="myAudio" controls>
<source src="example.mp3" type="audio/mpeg">
</audio>
<script>
const audio = document.getElementById('myAudio');
// 添加鍵盤事件監(jiān)聽器
document.addEventListener('keydown', (e) => {
if (e.key = ' ') { // 空格鍵播放/暫停
e.preventDefault();
if (audio.paused) {
audio.play();
} else {
audio.pause();
}
} else if (e.key = 'ArrowLeft') { // 左箭頭后退5秒
audio.currentTime -= 5;
} else if (e.key === 'ArrowRight') { // 右箭頭前進5秒
audio.currentTime += 5;
}
});
</script>
整體策略
- 自動播放限制: 避免自動播放多媒體內(nèi)容,特別是帶有聲音的視頻或音頻,以免干擾用戶的體驗。可以使用
preload="none"
或preload="metadata"
來延遲加載視頻,直到用戶明確請求播放。
<video controls preload="none">
<source src="example.mp4" type="video/mp4">
</video>
- 焦點管理: 確保當(dāng)多媒體內(nèi)容加載或動態(tài)更新時,焦點正確管理,不會導(dǎo)致用戶失去當(dāng)前的操作上下文。
表單設(shè)計
設(shè)計一個易于理解和使用的表單是提升用戶體驗和可訪問性的關(guān)鍵。
結(jié)構(gòu)與布局
- 清晰的層次結(jié)構(gòu): 確保表單有一個清晰的層次結(jié)構(gòu),使用戶能夠輕松理解每個部分的目的和內(nèi)容。可以使用
<fieldset>
和<legend>
來分組相關(guān)的表單元素,并且確保每個表單部分都有明確的標(biāo)題或說明。
<form id="registrationForm">
<fieldset>
<legend>注冊信息</legend>
<label for="username">用戶名:</label>
<input type="text" id="username" name="username" required>
<label for="email">郵箱地址:</label>
<input type="email" id="email" name="email" required>
<label for="password">密碼:</label>
<input type="password" id="password" name="password" required>
</fieldset>
<fieldset>
<legend>聯(lián)系方式</legend>
<label for="phone">電話號碼:</label>
<input type="tel" id="phone" name="phone">
<label for="address">地址:</label>
<textarea id="address" name="address"></textarea>
</fieldset>
<button type="submit">提交</button>
</form>
- 邏輯順序: 按照用戶的自然填寫順序排列表單字段,避免跳躍式布局。
<label for="firstName">名字:</label>
<input type="text" id="firstName" name="firstName" required>
<label for="lastName">姓氏:</label>
<input type="text" id="lastName" name="lastName" required>
<label for="email">郵箱地址:</label>
<input type="email" id="email" name="email" required>
標(biāo)簽
- 使用
<label>
標(biāo)簽: 為每個表單控件提供明確的標(biāo)簽,以便屏幕閱讀器能夠正確讀取,可以使用for
屬性將標(biāo)簽與相應(yīng)的輸入字段關(guān)聯(lián)起來。
<label for="email">郵箱地址:</label>
<input type="email" id="email" name="email" required>
- 隱藏標(biāo)簽: 對于某些裝飾性或視覺上不必要的標(biāo)簽,可以使用CSS將其隱藏,但仍然對屏幕閱讀器可見。
<label for="search" class="sr-only">搜索:</label>
<input type="search" id="search" name="search" placeholder="搜索...">
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
border: 0;
}
輸入字段
- 類型提示: 使用HTML5的輸入類型提示(如
email
、tel
、date
等),幫助瀏覽器提供更好的輸入體驗(如自動完成、鍵盤布局等)。
<input type="email" id="email" name="email" required>
<input type="tel" id="phone" name="phone">
<input type="date" id="birthday" name="birthday">
- 占位符: 占位符文本可以幫助用戶了解應(yīng)該輸入的內(nèi)容,但不應(yīng)替代標(biāo)簽。
<input type="email" id="email" name="email" placeholder="example@example.com" required>
表單驗證
- 客戶端驗證: 在用戶提交表單之前進行客戶端驗證,以防止無效數(shù)據(jù)提交,可以使用 HTML5 內(nèi)置的驗證屬性(如
required
、pattern
等)。
<form id="registrationForm">
<label for="email">郵箱地址:</label>
<input type="email" id="email" name="email" required aria-invalid="false" aria-describedby="email-error">
<span id="email-error" class="error"></span>
<button type="submit">提交</button>
</form>
<script>
const form = document.getElementById('registrationForm');
const emailInput = document.getElementById('email');
const emailError = document.getElementById('email-error');
form.addEventListener('submit', (e) => {
if (!emailInput.validity.valid) {
e.preventDefault();
emailInput.setAttribute('aria-invalid', 'true');
emailError.textContent = '請輸入有效的郵箱地址';
emailInput.focus();
}
});
</script>
- 服務(wù)器端驗證: 即使有客戶端驗證,仍需在服務(wù)器端進行驗證,以確保數(shù)據(jù)的安全性和完整性。
即時反饋
- 實時驗證: 在用戶輸入過程中提供即時反饋,幫助他們在提交表單前糾正錯誤,可以使用
aria-invalid
屬性指示輸入的有效性狀態(tài)。
<form id="registrationForm">
<label for="email">郵箱地址:</label>
<input type="email" id="email" name="email" required aria-invalid="false" aria-describedby="email-error">
<span id="email-error" class="error"></span>
<button type="submit">提交</button>
</form>
<script>
const emailInput = document.getElementById('email');
const emailError = document.getElementById('email-error');
emailInput.addEventListener('input', () => {
if (!emailInput.validity.valid) {
emailInput.setAttribute('aria-invalid', 'true');
emailError.textContent = '請輸入有效的郵箱地址';
} else {
emailInput.setAttribute('aria-invalid', 'false');
emailError.textContent = '';
}
});
</script>
- 成功反饋: 在用戶成功提交表單后,提供明確的成功確認(rèn)信息。
輔助功能
- ARIA屬性: 使用ARIA屬性增強表單的可訪問性,特別是在復(fù)雜交互中。
使用aria-required
指示必填字段。
使用aria-describedby
提供額外描述信息(如錯誤消息)。
<label for="email">郵箱地址:</label>
<input type="email" id="email" name="email" required aria-required="true" aria-describedby="email-error">
<span id="email-error" class="error"></span>
- 鍵盤導(dǎo)航: 確保表單可以通過鍵盤操作,并且焦點管理合理。
<form id="registrationForm">
<label for="username">用戶名:</label>
<input type="text" id="username" name="username" required>
<label for="email">郵箱地址:</label>
<input type="email" id="email" name="email" required>
<button type="submit">提交</button>
</form>
<script>
document.addEventListener('keydown', (e) => {
if (e.key === 'Enter') {
const focusedElement = document.activeElement;
if (focusedElement.tagName.toLowerCase() === 'button') {
focusedElement.click();
}
}
});
</script>
模態(tài)框
模態(tài)框是一種常見的UI組件,用于顯示臨時信息或要求用戶進行特定操作。
HTML結(jié)構(gòu)
模態(tài)框的基本結(jié)構(gòu)應(yīng)包含一個對話框容器和關(guān)閉按鈕,并且使用適當(dāng)?shù)腁RIA屬性來定義其角色和狀態(tài)。
- 使用
role="dialog"
來標(biāo)識模態(tài)框。 - 使用
aria-modal="true"
來告知屏幕閱讀器這是一個模態(tài)對話框,阻止背景內(nèi)容的交互。 - 提供明確的標(biāo)題(
aria-labelledby
)和描述(aria-describedby
),幫助用戶理解對話框的內(nèi)容。
<div id="myModal" role="dialog" aria-modal="true" aria-labelledby="modalTitle" aria-describedby="modalDescription" style="display: none;">
<h2 id="modalTitle">模態(tài)標(biāo)題</h2>
<p id="modalDescription">這是模態(tài)內(nèi)容。</p>
<button id="closeModal">關(guān)閉</button>
</div>
焦點管理
- 初始焦點: 當(dāng)模態(tài)框打開時,應(yīng)將焦點移動到模態(tài)框內(nèi)的第一個可聚焦元素上。如果模態(tài)框有多個可聚焦元素,選擇最相關(guān)的元素作為初始焦點。
function openModal() {
const modal = document.getElementById('myModal');
modal.style.display = 'block';
// 將焦點移到關(guān)閉按鈕上
document.getElementById('closeModal').focus();
}
- 模態(tài)框內(nèi)焦點循環(huán):在模態(tài)框打開時,焦點應(yīng)限制在模態(tài)框內(nèi)部,防止用戶通過 Tab 鍵將焦點移出模態(tài)框,與頁面其他部分交互。可以通過第三方庫如
react-focus-lock
來實現(xiàn),也可以通過監(jiān)聽keydown
事件,處理Tab鍵導(dǎo)航,確保焦點始終停留在模態(tài)框內(nèi)。
function trapFocus(event) {
const modal = document.getElementById('myModal');
const focusableElements = modal.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
const firstFocusableElement = focusableElements[0];
const lastFocusableElement = focusableElements[focusableElements.length - 1];
if (event.shiftKey && document.activeElement = firstFocusableElement) {
// Shift + Tab 從第一個元素移出
lastFocusableElement.focus();
event.preventDefault();
} else if (!event.shiftKey && document.activeElement = lastFocusableElement) {
// Tab 從最后一個元素移出
firstFocusableElement.focus();
event.preventDefault();
}
}
document.addEventListener('keydown', trapFocus);
- 關(guān)閉模態(tài)框時恢復(fù)焦點:當(dāng)模態(tài)框關(guān)閉時,應(yīng)將焦點恢復(fù)到打開模態(tài)框的觸發(fā)元素上,以便用戶可以繼續(xù)之前的操作。
const closeModalButton = document.getElementById('close-modal');
closeModalButton.addEventListener('click', () => {
modal.hidden = true;
openModalButton.focus();
});
樣式與視覺提示
- 視覺焦點指示: 為可聚焦元素提供清晰的視覺焦點指示,幫助視力障礙者識別當(dāng)前聚焦的位置。
button:focus, input:focus, select:focus, textarea:focus {
outline: 2px solid #007bff;
outline-offset: 2px;
}
- 背景遮罩: 使用背景遮罩來模糊或隱藏背景內(nèi)容,使模態(tài)框更加突出,背景遮罩應(yīng)覆蓋整個視口,并具有一定的透明度。
<div id="overlay" style="display: none;"></div>
<div id="myModal" role="dialog" aria-modal="true" aria-labelledby="modalTitle" aria-describedby="modalDescription" style="display: none;">
<!-- 模態(tài)框內(nèi)容 -->
</div>
<style>
#overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 9998;
}
#myModal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: white;
padding: 20px;
z-index: 9999;
}
</style>
<script>
function openModal() {
const overlay = document.getElementById('overlay');
const modal = document.getElementById('myModal');
overlay.style.display = 'block';
modal.style.display = 'block';
// 將焦點移到關(guān)閉按鈕上
document.getElementById('closeModal').focus();
}
function closeModal() {
const overlay = document.getElementById('overlay');
const modal = document.getElementById('myModal');
overlay.style.display = 'none';
modal.style.display = 'none';
// 恢復(fù)之前的焦點
if (previousActiveElement) {
previousActiveElement.focus();
}
}
</script>
小結(jié):可訪問性不是功能,而是責(zé)任。通過實現(xiàn)這些技術(shù)細節(jié),我們不僅滿足 WCAG 標(biāo)準(zhǔn),更是為所有用戶構(gòu)建真正的包容性網(wǎng)絡(luò)。從下一個功能需求開始,將可訪問性刻進你的開發(fā) DNA。