DEV Community

JH5
JH5

Posted on • Originally published at Medium

被低估的 Speech Synthesis API

#ai

被低估的 Speech Synthesis API

在眾多 Web API 中,有一個強大、支援度極高,卻經常被開發者忽略的 API:Web Speech API 中的 speechSynthesis 介面。

UpdatedMarch 24, 2026•3 min read

被低估的 Speech Synthesis API

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);
Enter fullscreen mode Exit fullscreen mode

試著打開瀏覽器的開發者工具 (F12),在 Console 貼上這段程式碼並按下 Enter,你的電腦就會開始對你說話了XD

不只是螢幕閱讀器的替代品

在深入探討應用案例之前,我們必須先釐清一個至關重要的觀念:

speechSynthesis API 絕不是原生螢幕閱讀器(如 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("恭喜!您的資料已成功儲存。");
Enter fullscreen mode Exit fullscreen mode

語言學習與發音指南

在語言學習網站或線上字典中,允許用戶點擊一個單字或句子來聆聽標準發音,這比嵌入預錄的 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>
Enter fullscreen mode Exit fullscreen mode

案例三:引導複雜的操作流程

在冗長或複雜的表單填寫過程中,當用戶完成一個關鍵步驟時,提供簡短的語音確認可以增加信心。

例如,在一個多步驟的購物車結帳流程中,當用戶點擊「確認付款」後,除了顯示 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>
Enter fullscreen mode Exit fullscreen mode

speechSynthesis 是一個強大、易用且相容性極佳的原生 API,雖然它不能取代專業的無障礙工具,但若能將其視為一種「聽覺的漸進增強 (Progressive Enhancement)」,它就能在語言學習、重要通知和互動引導等方面,為你的網站帶來更豐富、更具包容性的使用者體驗。

下次在設計互動功能時,不妨思考一下:「這裡如果加上一點聲音提示,體驗會不會更好?」

# ai

Top comments (0)