🛠️ Lecture 13: 無障礙網頁實戰:用 Vibe Coding 打造視障專屬「節拍器」Web App

NOTE作者資訊 (Author Info)

🎧 錄音室開場:為視障者量身打造的專屬工具


🎯 實戰專案:無障礙網頁節拍器 (Metronome Web App)


📝 大導演的 Vibe Coding 派工單 (Prompt)

我們不需要去背誦 JavaScript 的 setIntervalAudioContext 怎麼寫。我們只要給 AI 嚴格的「無障礙規範」!

請將以下 Prompt 貼給 AI:

「你現在是頂級的 Web 無障礙工程師。請幫我寫一個單一檔案的 HTML 網頁版節拍器 (包含 CSS 與 JS)。

功能需求: 1. 提供一個滑桿 (<input type="range">) 調整 BPM (範圍 40-208),並有一個文字框可手動輸入。 2. 提供一個下拉選單選擇節拍 (2/4, 3/4, 4/4)。 3. 一個播放/暫停按鈕。使用 Web Audio API 發出準確的滴答聲(第一拍頻率高一點)。

無障礙 (A11y) 嚴格規範(請嚴格遵守): 1. ARIA 標籤:所有按鈕、輸入框必須有 aria-label。 2. 焦點管理:點擊播放後,按鈕的文字要變成『暫停』,且焦點不能丟失。 3. Live Region 即時回饋:請建立一個 aria-live="polite" 的隱藏 div。當使用者用鍵盤左右鍵調整 BPM 滑桿時,請把目前的 BPM 數值寫入這個 div,讓 NVDA 能即時朗讀出來,而不會被節拍器的聲音蓋過! 4. 鍵盤支援:所有元素必須能透過 Tab 鍵導航。

請直接給我完整的 index.html 程式碼。」


💡 解密代碼:AI 幫我們寫了什麼無障礙黑科技?

當 AI 產出 index.html 後,你只要用瀏覽器(Chrome 或 Edge)雙擊打開,就能開始使用了。但身為大導演,我們要「看懂」AI 寫的核心架構:

1. 無障礙靈魂:aria-live 即時播報區

在代碼中,你會看到這段:

<div id="announcer" class="sr-only" aria-live="polite"></div>

這是一個視覺上隱藏 (sr-only) 的區塊。它的核心是 aria-live="polite"。這個屬性會告訴 NVDA:「只要這裡面的文字改變了,請在你不忙的時候,把文字唸出來。」 當你拉動滑桿時,AI 的 JavaScript 會自動執行 announcer.innerText = "目前速度 " + bpm + " 拍";。這樣一來,NVDA 就能順暢地讀出數字!

2. 語意化元件:<input type="range">

早期的網頁可能用好幾個 div 去畫一個假滑桿,導致 NVDA 只會唸「圖形」。AI 在這裡使用了 HTML5 原生的 type="range",NVDA 看到這個,就會自動把它翻譯成 NVDAObject 裡的「滑桿 (Slider)」,並且支援方向鍵操作。這印證了我們在前面章節學到的「Web ARIA 映射」原理!


🎓 結語

透過這個網頁節拍器專案,我們學會了如何把無障礙規範(如 ARIA 標籤、Live Region)寫進 Prompt 裡。只要掌握這些術語,AI 就能幫你把任何普通的網頁工具,變成視障者專屬的無障礙神器!

👉 下一堂課:Lecture 13.5 拆解 NVDA 核心大腦黑盒子
👉 回課程大綱:學習地圖

🔥 專家級深度思考與實戰挑戰 (Expert Challenge)

以下題目專為尋求真正硬核觀念與專家級實戰能力的學員設計。題目無法從講義表面抄寫解答,請嘗試獨立思考後再點擊展開解析。

❓ 挑戰 1:Web Audio API 精確時間調度 vs `setInterval` 的計時漂移災難 👉 點擊展開專家解析答案

【實戰情境問題】:在開發無障礙網頁節拍器時,為什麼絕對不能使用 JavaScript 的 `setInterval` 或 `setTimeout` 來觸發節拍聲音?在瀏覽器 Event Loop 中,這會引發什麼致命的節奏漂移(Jitter)?Web Audio API 的 `AudioContext.currentTime` 如何解決此問題?

【鑑別點說明】:測試學員對瀏覽器單執行緒渲染、Event Loop 延遲與 Web Audio 系統級硬體時鐘 (Hardware Audio Clock) 的深度理解。

【專家級解答與深度剖析】: `setInterval` 運作於 JavaScript 主執行緒中。當頁面進行 DOM 渲染、垃圾回收 (GC) 或背景分頁切換時,主執行緒會被阻塞,導致 `setInterval` 的回呼延遲數毫秒甚至數百毫秒,產出的節拍聲音極度不穩定。Web Audio API 擁有獨立的音訊硬體時鐘(`audioCtx.currentTime`),這是一個高精度的浮點數硬體時間戳。透過 `oscillator.start(nextNoteTime)` 提前將音訊節點排程入硬體佇列,音訊晶片會在精確到亞毫秒級的物理時間點自動發聲,徹底免疫主執行緒的干擾。

❓ 挑戰 2:無障礙節拍器與 ARIA Live Region 的語音同步策略 👉 點擊展開專家解析答案

【實戰情境問題】:當節拍器以每分鐘 120 拍 (BPM) 高速播放聲音時,如果我們將每一拍的數字(1, 2, 3, 4)都寫入 `aria-live="assertive"` 中,為什麼 NVDA 報讀器會變成一片混亂?如何設計聲響音效 (Audio Cue) 與語音播報的分工?

【鑑別點說明】:考驗學員在高頻動態音效與螢幕報讀語音佇列之間的無障礙互動設計能力。

【專家級解答與深度剖析】: NVDA 的語音合成器朗讀一個數字(如「一」)需要約 200 毫秒,在 120 BPM 下每 500 毫秒就有一拍。若將每一拍寫入 `aria-live`,語音佇列會迅速積壓溢出,報讀器會瘋狂切斷並重複播報,產生嚴重的噪音干擾。最佳無障礙實踐:1. **節拍本體**:使用 Web Audio API 產生高低音調的短促音效(如高音 880Hz 代表第一拍,低音 440Hz 代表副拍);2. **ARIA Live 僅用於狀態變更**:僅在學員按下「開始」、「停止」或「調整 BPM 至 130」時,才發送一次性的語音播報。