媒體和 Web Audio API 自動播放指南

在頁面載入時立即自動開始播放音訊(或帶有音軌的影片)可能會給使用者帶來意想不到的驚喜。雖然媒體的自動播放有其用處,但應謹慎使用,並且僅在需要時使用。為了讓使用者能夠控制這一點,瀏覽器通常會提供各種形式的自動播放阻止。在本指南中,我們將介紹各種媒體和 Web Audio API 中的自動播放功能,包括如何使用自動播放以及如何與瀏覽器協作以優雅地處理自動播放阻止的簡要概述。

當源媒體沒有音軌或音軌已靜音時,自動播放阻止不適用於 <video> 元素。具有活動音軌的媒體被認為是可聽見的,自動播放阻止適用於它們。不可聽見的媒體不受自動播放阻止的影響。

自動播放和自動播放阻止

術語自動播放指任何導致媒體在使用者未明確請求播放開始的情況下開始播放的功能。這包括使用 HTML 屬性自動播放媒體以及在處理使用者輸入上下文之外使用 JavaScript 程式碼開始播放。

這意味著以下兩種情況都被視為自動播放行為,因此受瀏覽器自動播放阻止策略的約束

html
<audio src="/music.mp3" autoplay></audio>

and

js
audioElement.play();

以下 Web 功能和 API 可能會受到自動播放阻止的影響

從使用者的角度來看,一個未經警告就突然發出聲音的網頁或應用程式可能會令人不安、不便或令人反感。因此,瀏覽器通常只允許在特定情況下成功進行自動播放。

自動播放可用性

一般來說,你可以假定只有在滿足以下至少一項條件時,媒體才會被允許自動播放

  • 音訊已靜音或其音量設定為 0
  • 使用者已與站點互動(透過點選、輕觸、按鍵等)
  • 如果該站點已被列入允許列表;如果瀏覽器確定使用者經常與媒體互動,這可能會自動發生,或者透過偏好設定或其他使用者介面功能手動發生
  • 如果使用自動播放 許可權策略 來授予 <iframe> 及其文件自動播放支援。

否則,播放很可能會被阻止。導致阻止的具體情況以及站點如何被列入允許列表的細節因瀏覽器而異,但上述是很好的指導原則。

有關詳細資訊,請參閱 Google ChromeWebKit 的自動播放策略。

注意:換句話說,如果在尚未進行任何使用者互動的標籤頁中以程式設計方式啟動播放,則通常會阻止播放任何包含音訊的媒體。瀏覽器還可以選擇在其他情況下阻止。

媒體元素的自動播放

現在我們已經介紹了什麼是自動播放以及什麼可以阻止自動播放,我們將看看您的網站或應用程式如何在頁面載入時自動播放媒體,如何檢測自動播放失敗的情況,以及當瀏覽器拒絕自動播放時如何應對的提示。

自動播放屬性

自動播放內容最簡單的方法是將 autoplay 屬性新增到您的 <audio><video> 元素中,這會將元素的 autoplay 屬性設定為 true。當 autoplaytrue 時,媒體將在以下情況發生後儘快自動開始播放

  • 頁面被允許使用自動播放功能
  • 元素已在頁面載入期間建立
  • 已接收足夠的媒體以開始播放並持續播放到媒體結束而不會中斷,假設網路效能或頻寬沒有顯著變化。

示例:自動播放屬性

使用 autoplay 屬性的 <audio> 元素可能看起來像這樣

html
<audio id="musicplayer" autoplay>
  <source src="/music/chapter1.mp3" />
</audio>

示例 2:檢測是否允許自動播放

如果自動播放對您的應用程式很重要,您可能需要根據是否允許、不允許或僅支援不可聽內容來定製行為。例如,如果您的應用程式需要自動播放影片,並且您知道頁面只允許自動播放不可聽內容,您可以將其靜音或提供沒有音軌的影片。同樣,如果您知道完全不允許自動播放,您可以為影片提供預設影像(使用 poster 屬性),或者選擇延遲載入影片直到它被請求。

可以使用 Navigator.getAutoplayPolicy() 方法來檢查文件中媒體功能型別(即所有媒體元素或所有音訊上下文)的自動播放策略,或者檢查特定媒體元素或音訊上下文是否可以自動播放。

以下示例展示瞭如何傳遞 mediaelement 字串以獲取文件中所有媒體元素的自動播放策略(傳遞 audiocontext 以獲取音訊上下文的策略)。程式碼假定 video 是使用 <video> 標籤或 HTMLVideoElementHTMLVideoElement 媒體元素,並且預設配置為自動播放音訊。如果自動播放只允許不可聽內容,我們會靜音音訊;如果自動播放被禁止,我們確保影片顯示佔位符影像。

js
if (navigator.getAutoplayPolicy("mediaelement") === "allowed") {
  // The video element will autoplay with audio.
} else if (navigator.getAutoplayPolicy("mediaelement") === "allowed-muted") {
  // Mute audio on video
  video.muted = true;
} else if (navigator.getAutoplayPolicy("mediaelement") === "disallowed") {
  // Set a default placeholder image.
  video.poster = "http://example.com/poster_image_url";
}

測試特定元素或音訊上下文的程式碼是相同的,只是您傳入要測試的元素或上下文而不是型別字串。這裡我們傳入要測試的 video 物件。

js
if (navigator.getAutoplayPolicy(video) === "allowed") {
  // The video element will autoplay with audio.
} else if (navigator.getAutoplayPolicy(video) === "allowed-muted") {
  // Mute audio on video
  video.muted = true;
} else if (navigator.getAutoplayPolicy(video) === "disallowed") {
  // Set a default placeholder image.
  video.poster = "http://example.com/poster_image_url";
}

由於使用者與站點、頁面或特定元素的互動,某種型別的自動播放策略可能會更改。同樣,在某些瀏覽器上,即使型別的策略沒有更改(例如,在某些瀏覽器上,觸控特定元素可以只允許該元素自動播放),特定元素的策略也可能更改。

由於無法在自動播放策略更改時收到通知(無論是針對型別還是元素),我們通常建議在載入頁面時使用型別檢查策略。

示例 3:檢測自動播放失敗作為回退

自動播放成功或失敗不會觸發特定事件(或其他通知),因此不支援 Navigator.getAutoplayPolicy() 的瀏覽器無法輕鬆確定是否支援自動播放,或者在觸發或未觸發時做出反應。

一種方法是監聽 play 事件的第一次例項,該事件在媒體元素暫停後恢復以及發生自動播放時觸發。這意味著 play 事件第一次觸發時,您就知道您的媒體在頁面開啟後第一次開始播放,

考慮一下這個媒體元素的 HTML

html
<video src="my-video.mp4" id="video" autoplay></video>

這裡我們有一個 <video> 元素,其 autoplay 屬性已設定,並且設定了 play 事件處理程式;該事件由一個名為 handleFirstPlay() 的函式處理,該函式接收 play 事件作為輸入。

handleFirstPlay() 如下所示

js
const video = document.getElementById("video");
video.addEventListener("play", handleFirstPlay);

let hasPlayed = false;
function handleFirstPlay(event) {
  if (!hasPlayed) {
    hasPlayed = true;

    // Remove listener so this only gets called once.
    const vid = event.target;
    vid.removeEventListener("play", handleFirstPlay);

    // Start whatever you need to do after first playback has started
  }
}

Event 物件的 target 獲取影片元素的引用後,我們使用它來移除事件監聽器。這將阻止任何未來的 play 事件傳遞給處理程式。如果影片被使用者暫停並恢復,或者當文件在後臺標籤頁中時由瀏覽器自動暫停和恢復,則可能會發生這種情況。

此時,您的站點或應用程式可以開始任何需要依靠影片已啟動的操作。

play() 方法

“自動播放”一詞也指指令碼嘗試在處理使用者輸入事件的上下文之外觸發包含音訊的媒體播放的場景。這是透過呼叫媒體元素的 play() 方法來完成的。

注意:強烈建議您儘可能使用 autoplay 屬性,因為 autoplay 屬性對自動播放偏好的支援比其他自動播放媒體的方式更廣泛。它還讓瀏覽器負責啟動播放,讓它最佳化播放的時間。

示例:播放影片

此示例播放文件中找到的第一個 <video> 元素。除非文件有權自動播放媒體,否則 play() 不會允許播放開始。

js
document.querySelector("video").play();

示例:處理 play() 失敗

當您使用 play() 方法啟動媒體時,檢測自動播放失敗要容易得多。play() 返回一個 Promise,該 Promise 在媒體成功開始播放時解決,並在播放失敗時(例如自動播放被拒絕時)拒絕。當自動播放失敗時,您可能希望提供一種方法讓使用者手動告訴瀏覽器請求使用者授予播放媒體的許可權。

您可以使用以下程式碼來完成這項工作

js
let startPlayPromise = videoElem.play();

if (startPlayPromise !== undefined) {
  startPlayPromise
    .then(() => {
      // Start whatever you need to do only after playback
      // has begun.
    })
    .catch((error) => {
      if (error.name === "NotAllowedError") {
        showPlayButton(videoElem);
      } else {
        // Handle a load or playback error
      }
    });
}

我們對 play() 結果所做的第一件事是確保它不是 undefined。我們檢查這一點是因為在 HTML 規範的早期版本中,play() 不返回任何值。最近才添加了返回 Promise 以讓您確定操作的成功或失敗的功能。檢查 undefined 可以防止此程式碼在舊版本的 Web 瀏覽器上因錯誤而失敗。

如果 play() 返回的 Promise 順利解決,則會執行 then() 子句,並可以開始在自動播放開始時需要完成的任何操作。

然後我們為 Promise 新增一個 catch() 處理程式。它會檢查錯誤的 name 以檢視它是否是 NotAllowedError。這表示播放因許可權問題而失敗,例如自動播放被拒絕。如果是這種情況,我們應該呈現一個使用者介面,讓使用者手動開始播放;這裡由函式 showPlayButton() 處理。

任何其他錯誤都會酌情處理。

如果您想在與頁面第一次互動後開始播放影片,可以使用 setInterval() 來實現此目的

js
let playAttempt = setInterval(() => {
  videoElem
    .play()
    .then(() => {
      clearInterval(playAttempt);
    })
    .catch((error) => {
      console.log("Unable to play the video, User has not interacted yet.");
    });
}, 3000);

使用 Web Audio API 自動播放

Web Audio API 中,網站或應用程式可以使用連結到 AudioContext 的源節點上的 start() 方法開始播放音訊。在處理使用者輸入事件的上下文之外這樣做受自動播放規則的約束。

自動播放許可權策略

除了上述瀏覽器端對自動播放功能的管理和控制之外,Web 伺服器還可以表達其允許自動播放功能的意願。HTTP Permissions-Policy 頭的 autoplay 指令用於控制哪些域(如果有)可以用於自動播放媒體。預設情況下,autoplay 許可權策略設定為 self,表示自動播放是允許的,因為它們託管在與文件相同的域上。

您還可以指定一個空允許列表 (()) 以完全停用自動播放,* 以允許所有域的自動播放,或一個或多個可以自動播放媒體的特定來源。這些來源由空格字元分隔。

注意:指定的許可權策略適用於文件及其巢狀的所有 <iframe>,除非這些框架包含一個 allow 屬性,該屬性為該框架及其巢狀的所有框架設定新的許可權策略。

<iframe> 上使用 allow 屬性為該框架及其巢狀框架指定許可權策略時,您還可以指定值 'src' 以僅允許來自與框架 src 屬性指定的域相同的媒體自動播放。

示例:僅允許文件域自動播放

要使用 Permissions-Policy 頭僅允許媒體從文件的 來源 自動播放

http
Permissions-Policy: autoplay=(self)

<iframe> 執行相同操作

html
<iframe src="mediaplayer.html" allow="autoplay"> </iframe>

示例:允許自動播放和全屏模式

在上一個示例中新增 全屏 API 許可權會導致如下所示的 Permissions-Policy 頭(如果允許全屏訪問,無論域如何;也可以根據需要新增域限制)。

http
Permissions-Policy: autoplay=(self), fullscreen=(self)

使用 <iframe> 元素的 allow 屬性授予相同的許可權,如下所示

html
<iframe src="mediaplayer.html" allow="autoplay; fullscreen"> </iframe>

示例:允許特定來源自動播放

允許媒體從文件(或 <iframe>)自己的域和 https://example.media 播放的 Permissions-Policy 頭如下所示

http
Permissions-Policy: autoplay=(self "https://example.media")

可以這樣編寫 <iframe> 以指定此自動播放策略應應用於自身和任何子框架

html
<iframe
  width="300"
  height="200"
  src="mediaplayer.html"
  allow="autoplay 'src' https://example.media">
</iframe>

示例:停用自動播放

autoplay 許可權策略設定為 ()/none 會完全停用文件或 <iframe> 以及所有巢狀框架的自動播放。HTTP 頭是

http
Permissions-Policy: autoplay=()

使用 <iframe>allow 屬性

html
<iframe src="mediaplayer.html" allow="autoplay 'none'"> </iframe>

最佳實踐

此處提供了提示和推薦的最佳實踐,以幫助您充分利用自動播放功能。

使用媒體控制元件處理自動播放失敗

自動播放的常見用例是自動開始播放與文章、廣告或頁面主要功能的預覽相伴的影片剪輯。要自動播放此類影片,您有兩個選擇:不帶音軌,或者帶音軌但將 <video> 元素配置為預設靜音,如下所示

html
<video
  src="/videos/awesomevid.webm"
  controls
  autoplay
  playsinline
  muted></video>

此影片元素配置為包含使用者控制元件(通常是播放/暫停、在影片時間軸上拖動、音量控制和靜音);此外,由於包含了 muted 屬性以及 Safari 中自動播放所需的 playsinline 屬性,影片將自動播放但音訊靜音。然而,使用者可以選擇透過單擊控制元件中的取消靜音按鈕來重新啟用音訊。

瀏覽器配置選項

瀏覽器可能具有控制自動播放工作方式或如何處理自動播放阻止的偏好設定。這裡列出了作為 Web 開發人員對您可能具有特殊意義或重要性的任何此類偏好設定。這些包括任何可能有助於測試或除錯的偏好設定,以及任何您需要準備處理的設定方式。

Firefox

media.allowed-to-play.enabled

一個布林偏好設定,指定非標準 HTMLMediaElement.allowedToPlay 屬性是否暴露給 Web。目前預設為 false(在夜間構建中預設為 true)。如果此值為 false,則 allowedToPlay 屬性在 HTMLMediaElement 介面中缺失,因此在 <audio><video> 元素上均不存在。

media.autoplay.allow-extension-background-pages

此布林偏好設定,如果為 true,則允許瀏覽器擴充套件的後臺指令碼自動播放音訊媒體。將此值設定為 false 會停用此功能。預設值為 true

media.autoplay.allow-muted

一個布林偏好設定,如果為 true(預設值),則允許當前靜音的音訊媒體自動播放。如果此值已更改為 false,則即使靜音,帶有音軌的媒體也無法播放。

media.autoplay.block-webaudio

一個布林偏好設定,指示是否將自動播放阻止應用於 Web Audio API。如果為 false,則始終允許 Web 音訊自動播放。如果為 true,則只有在頁面具有 粘性啟用 後,音訊上下文才能播放。預設設定為 true

media.autoplay.default

一個整數偏好設定,指定是否預設允許(0)、阻止(1)或按使用提示(2)進行自動播放支援的每域配置。預設值為 0

media.autoplay.enabled.user-gestures-needed(僅限夜間構建)

一個布林偏好設定,控制是否允許使用者手勢檢測覆蓋 media.autoplay.default 的設定。如果 media.autoplay.default 設定為 0(預設允許自動播放),則此偏好設定為 true 允許在頁面已透過使用者手勢啟用的情況下自動播放帶音軌的媒體,並且不限制不可聽媒體。

media.block-autoplay-until-in-foreground

一個布林偏好設定,指示當在後臺標籤頁中啟動時是否阻止媒體播放。預設值 true 意味著即使在其他情況下可用,自動播放也不會發生,直到標籤頁被帶到前臺。這可以防止令人分心的情況,即標籤頁開始播放聲音而使用者無法在所有標籤頁和視窗中找到該標籤頁。

另見