被低估的 Speech Synthesis API
在眾多 Web API 中,有一個強大、支援度極高,卻經常被開發者忽略的 API:Web Speech API 中的 speechSynthesis 介面。
UpdatedMarch 24, 2026•3 min read
JJhihHao Wu**近期研究重點包含 AI Agent 的供應鏈攻擊、PII 偵測模型評估,以及醫療 AI 在臨床流程中的安全落地。
在這裡,我分享深度技術實測報告(如 NVIDIA NeMo, WildGuard)與職場技術成長心得,致力於在 AI 浪潮中打造具備資安韌性的解決方案。**Part of seriesAI 工具與模型評測
On this page
被低估的 Speech Synthesis API認識 speechSynthesis不只是螢幕閱讀器的替代品增強重要通知與警報 (Notifications & Alerts)語言學習與發音指南案例三:引導複雜的操作流程控制聲音與參數
被低估的 Speech Synthesis API
Speech Synthesis API
在眾多 Web API 中,有一個強大、支援度極高,卻經常被開發者忽略的 API:Web Speech API 中的 speechSynthesis 介面。
簡單來說,它允許我們透過 JavaScript,指揮瀏覽器將任意字串「朗讀」出來。
這原本只是為視障用戶設計的功能,不過我們將深入探討如何利用這個 API 來「增強」現代網頁的使用者體驗(UX),而不僅僅是為了無障礙(Accessibility)。
認識 speechSynthesis
Web Speech API 包含兩個部分:語音識別(Speech Recognition,將語音轉文字)和語音合成(Speech Synthesis,將文字轉語音),而我們今天要介紹的主角是後者,通常也被稱為 TTS (Text-to-Speech),不需要引入任何外部龐大的 Library,現代瀏覽器(Chrome, Firefox, Safari, Edge)幾乎都原生支援。
要讓瀏覽器說話demo,你只需要兩行核心程式碼:
JavaScript
// 1. 建立一個「話語」物件 (Utterance),內容是你想要朗讀的文字
const msg = new SpeechSynthesisUtterance('你好,歡迎來到我的網站!');
// 2. 指揮語音合成控制器將這個物件「說」出來
window.speechSynthesis.speak(msg);
試著打開瀏覽器的開發者工具 (F12),在 Console 貼上這段程式碼並按下 Enter,你的電腦就會開始對你說話了XD
不只是螢幕閱讀器的替代品
在深入探討應用案例之前,我們必須先釐清一個至關重要的觀念:
speechSynthesisAPI 絕不是原生螢幕閱讀器(如 NVDA, VoiceOver, JAWS)的替代品。
螢幕閱讀器 (Screen Reader) 是一種複雜的輔助技術 (AT)。它不僅僅是朗讀文字,它還負責解釋頁面的語意結構(標題、列表、表單)、導航焦點,並提供上下文資訊。視障用戶依賴它們來「理解」和「操作」整個網站。
speechSynthesis則是一個「發聲工具」,只負責將你給它的字串機械地讀出來,它不懂 HTML 結構,也不懂 ARIA 標籤。
那麼,它的價值在哪裡?
如果說語意化的 HTML 和 ARIA 是無障礙的基礎設施,那麼 speechSynthesis 就是錦上添花的功能,它可以在特定的互動時刻,提供額外的聽覺回饋,這對所有用戶(不僅僅是視障用戶)都有幫助。
我們不應該用它來朗讀整篇文章(那是螢幕閱讀器的工作),但我們可以用它來處理以下場景:
增強重要通知與警報 (Notifications & Alerts)
在繁忙的儀表板或應用中,視覺的 Toast 通知有時會被忽略。特別是當用戶在進行多工處理,目光暫時離開螢幕時。
加入聽覺提示可以顯著提高注意度。
JavaScript
function showVisualAlert(message) {
// ... 顯示視覺 Toast 的程式碼 ...
console.log("Visual Alert:", message);
}
function announceImportantAlert(message) {
// 先顯示視覺提示
showVisualAlert(message);
// 增加聽覺增強
// 檢查瀏覽器是否支援
if ('speechSynthesis' in window) {
// 取消之前的發聲,避免排隊太多聲音
window.speechSynthesis.cancel();
const utterance = new SpeechSynthesisUtterance(message);
// 可以稍微提高語速和音調來表示緊急
utterance.rate = 1.1;
utterance.pitch = 1.2;
window.speechSynthesis.speak(utterance);
}
}
// 使用情境:
announceImportantAlert("注意:您的連線已中斷,請檢查網路設定。");
announceImportantAlert("恭喜!您的資料已成功儲存。");
語言學習與發音指南
在語言學習網站或線上字典中,允許用戶點擊一個單字或句子來聆聽標準發音,這比嵌入預錄的 MP3 檔案更靈活、更輕量。
我們甚至可以指定語言:
function speakWord(word, langCode) {
if (!'speechSynthesis' in window) return;
const utterance = new SpeechSynthesisUtterance(word);
// 指定語言代碼,例如 'en-US', 'ja-JP', 'es-ES', 'zh-TW'
// 這有助於瀏覽器選擇正確的發音引擎
utterance.lang = langCode;
window.speechSynthesis.speak(utterance);
}
// 使用情境:在 HTML 中
// <button onclick="speakWord('Bonjour', 'fr-FR')">🔊 法語發音</button>
// <button onclick="speakWord('こんにちは', 'ja-JP')">🔊 日語發音</button>
案例三:引導複雜的操作流程
在冗長或複雜的表單填寫過程中,當用戶完成一個關鍵步驟時,提供簡短的語音確認可以增加信心。
例如,在一個多步驟的購物車結帳流程中,當用戶點擊「確認付款」後,除了顯示 loading spinner,還可以同時播放:「正在處理您的付款,請稍候」,能有效減少用戶的焦慮感。
控制聲音與參數
SpeechSynthesisUtterance 物件提供了許多屬性讓我們調整聲音的表現,包括:
rate: 語速 (預設 1, 範圍通常 0.1 ~ 10)pitch: 音調 (預設 1, 範圍 0 ~ 2)volume: 音量 (預設 1, 範圍 0 ~ 1)voice: 指定特定的聲音(例如 Google 小姐、微軟的聲音等)
以下是一個互動式的 Demo,展示如何獲取系統可用的聲音列表並調整參數:
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Speech Synthesis API 進階 Demo</title>
<style>
body { font-family: system-ui, sans-serif; padding: 2rem; line-height: 1.5; max-width: 600px; margin: 0 auto; }
.control-group { margin-bottom: 1rem; border: 1px solid #ddd; padding: 1rem; border-radius: 8px;}
label { display: block; margin-bottom: 0.5rem; font-weight: bold;}
select, input, textarea, button { width: 100%; padding: 0.5rem; margin-bottom: 0.5rem; box-sizing: border-box;}
button { background-color: #0056b3; color: white; border: none; cursor: pointer; font-size: 1rem;}
button:hover { background-color: #004494; }
</style>
</head>
<body>
<h1>🗣️ 給你的網頁一把聲音</h1>
<p>調整下方參數,體驗 speechSynthesis 的效果。</p>
<div class="control-group">
<label for="text-to-speak">要朗讀的文字:</label>
<textarea id="text-to-speak" rows="3">你好,Web Speech API 真的很酷!</textarea>
</div>
<div class="control-group">
<label for="voice-select">選擇聲音 (Voices):</label>
<select id="voice-select">
<option value="">載入聲音中...</option>
</select>
</div>
<div class="control-group">
<label for="rate-range">語速 (Rate): <span id="rate-value">1</span></label>
<input type="range" id="rate-range" min="0.5" max="2" value="1" step="0.1">
<label for="pitch-range">音調 (Pitch): <span id="pitch-value">1</span></label>
<input type="range" id="pitch-range" min="0.1" max="2" value="1" step="0.1">
</div>
<button id="speak-btn">🔊 開始朗讀</button>
<script>
const synth = window.speechSynthesis;
const textInput = document.getElementById('text-to-speak');
const voiceSelect = document.getElementById('voice-select');
const rateRange = document.getElementById('rate-range');
const pitchRange = document.getElementById('pitch-range');
const rateValue = document.getElementById('rate-value');
const pitchValue = document.getElementById('pitch-value');
const speakBtn = document.getElementById('speak-btn');
let voices = [];
// 獲取並填充可用的聲音列表
function populateVoiceList() {
voices = synth.getVoices();
voiceSelect.innerHTML = '';
voices.forEach((voice, index) => {
const option = document.createElement('option');
option.textContent = `${voice.name} (${voice.lang})`;
option.setAttribute('data-lang', voice.lang);
option.setAttribute('data-name', voice.name);
// 嘗試預設選中一個中文聲音
if (voice.lang.includes('zh') || voice.lang.includes('cmn')) {
option.selected = true;
}
voiceSelect.appendChild(option);
});
}
// 瀏覽器聲音列表載入是非同步的,需要監聽事件
populateVoiceList();
if (speechSynthesis.onvoiceschanged !== undefined) {
speechSynthesis.onvoiceschanged = populateVoiceList;
}
// 更新 Range 顯示數值
rateRange.oninput = () => rateValue.textContent = rateRange.value;
pitchRange.oninput = () => pitchValue.textContent = pitchRange.value;
// 朗讀功能
speakBtn.addEventListener('click', () => {
if (synth.speaking) {
console.error('已經在說話了...');
return;
}
if (textInput.value !== '') {
const utterThis = new SpeechSynthesisUtterance(textInput.value);
const selectedOption = voiceSelect.selectedOptions[0].getAttribute('data-name');
// 找到選中的聲音物件
const selectedVoice = voices.find(v => v.name === selectedOption);
if (selectedVoice) {
utterThis.voice = selectedVoice;
}
utterThis.rate = rateRange.value;
utterThis.pitch = pitchRange.value;
synth.speak(utterThis);
}
});
</script>
</body>
</html>
speechSynthesis 是一個強大、易用且相容性極佳的原生 API,雖然它不能取代專業的無障礙工具,但若能將其視為一種「聽覺的漸進增強 (Progressive Enhancement)」,它就能在語言學習、重要通知和互動引導等方面,為你的網站帶來更豐富、更具包容性的使用者體驗。
下次在設計互動功能時,不妨思考一下:「這裡如果加上一點聲音提示,體驗會不會更好?」

Top comments (0)