發布日期:2026 年 5 月 19 日,上次更新日期:2026 年 9 月 8 日
網路早已不再是最初的靜態、文件導向媒介。現代人會基於各種原因使用功能豐富的網頁應用程式,包括通訊、購物、瀏覽多媒體內容,以及管理複雜的生活。
儘管 HTML 有所進步,但仍會由上而下依序傳送,幾乎不考慮內容何時準備就緒,或使用者何時使用。CSS 可讓您變更內容順序,但通常會對無障礙功能造成重大副作用。JavaScript 可讓您透過各種 API 操控 DOM,在某種程度上擺脫這種限制,但這些 API 通常需要冗長的語法,或建構 DOM 樹狀結構才能插入 HTML。
由於網路媒介具有用戶端與伺服器特性,因此效能對網路至關重要。不過,為了規避 HTML 的這種依序性質,通常會做出次佳選擇,導致效能降低。包括等待整個網頁準備就緒,或使用繁重的架構以非同步方式提供元件。JavaScript 架構的普及程度,顯示網頁程式開發人員偏好以元件為基礎的模型,而非網頁起源的剛性文件心智模型。
Chrome 團隊一直在思考這個問題,並開發了新的網頁平台功能,稱為宣告式部分更新。
前兩組新的 API 可讓您更輕鬆地以非線性方式提供 HTML,無論是在 HTML 文件本身中不按順序提供,還是使用新的 JavaScript API 以更簡單的方式將 HTML 動態插入現有文件。您也可以使用 Polyfill,立即使用這些新的 API,即使在尚未支援這些 API 的瀏覽器中也沒問題。
不按順序串流
第一組異動是新的不依序串流 API,使用處理指令預留位置和具有 for 屬性的 <template> HTML 元素。例如:
<div>
<?marker name="placeholder">
</div>
...
<template for="placeholder">
Here is some <em>HTML content</em>!
</template>
處理指令在 XML 中已存在很長一段時間,但在 HTML 中會被視為註解並忽略。這個新的 API 改變了這一點,並將處理指令帶入 HTML。舉例來說,當瀏覽器看到 <?marker name="placeholder"> 處理指令時,不會立即執行任何動作 (與先前類似),但之後可以參照。
含有 for 屬性的 <template> 元素會查詢含有 name 屬性的對應處理指令,並取代內容。在這種情況下,DOM 剖析後會變成以下內容 (忽略部分空白字元差異):
<div>
Here is some <em>HTML content</em>!
</div>
除了用於替換的 <?marker> 屬性外,還有 <?start> 和 <?end> 範圍標記,可在處理範本前顯示暫時的預留位置內容:
<div>
<?start name="another-placeholder">
Loading…
<?end>
</div>
...
<template for="another-placeholder">
Here is some <em>HTML content</em>!
</template>
在這種情況下,系統會顯示 Loading… 字串,直到看到 <template> 為止,然後替換成新內容。
您也可以在範本中加入處理指令,以便進行多項更新:
<ul id="results">
<?start name="results">
Loading…
<?end>
</ul>
...
<template for="results">
<li>Result One</li>
<?marker name="results">
</template>
...
<template for="results">
<li>Result Two</li>
<?marker name="results">
</template>
...
經過剖析和處理後,最終會產生下列 HTML:
<ul id="results">
<li>Result One</li>
<li>Result Two</li>
<?marker name="results">
</ul>
最後加上最終處理指示,以防日後在文件中加入更多 <template for="results"> 預留位置。
為什麼要使用處理指令,而不是標準 HTML 元素?
這是初次使用這個 API 的使用者常問的問題,建議使用 <slot> 或甚至 <template> 元素本身。這項提案的初始版本使用標準 HTML 元素,但隨著設計反覆調整,處理指令已改為處理指令可讓修補作業在不影響 DOM 的情況下進行。這樣一來,您就可以在 <head> 中使用這個元素 (例如用於 <title> 更新),甚至在 <table> 等其他元素中使用 (例如新增選用的額外資料列)。
雖然許多網頁程式開發人員不熟悉這種語法,但處理指令的彈性更大,且較不容易發生回溯相容性問題。這類元素已用於 XML,且由於這項提案,現已成為 HTML 標準的一部分。
示範
在這部影片中,我們使用串流 HTML 實作基本的相簿應用程式:
初始版面配置完成後,狀態和相片都會串流至 HTML。
用途
這項不按順序修補 HTML 的功能,搭配串流 HTML 使用時,有許多用途:
- 島嶼架構。孤島架構是 Astro 等架構推廣的常見模式,元件會在靜態 HTML 上獨立凍結。
<template for>API 可讓靜態內容直接在 HTML 中以類似方式處理。JavaScript 架構也可以使用這個 API,建立互動性更高的孤島或處理元件。 - 在內容準備就緒時提供。有了這種孤島架構,內容準備就緒後即可串流,不必等待需要額外處理的內容 (例如資料庫查詢)。雖然許多平台允許串流 HTML,但 HTML 的依序性質意味著內容通常會保留,或透過複雜的 JavaScript DOM 操作。現在,您可以在等待期間提供靜態內容,然後在 HTML 串流結束時插入更昂貴的動態內容。
- HTML 可按照最佳順序放送,提升載入網頁效能。更進一步來說,即使訂單已準備就緒,你還是可以變更訂單。舉例來說,大型選單是常見的導覽功能,其中包含大量 HTML,使用者必須等到網頁可供互動後才能看到。這段大型 HTML 程式碼可以稍後再傳送,優先處理初始網頁載入所需的重要 HTML。HTML 不再受順序限制。
以上只是部分用途,我們很期待看到開發人員如何運用這個新 API。
限制和細微差異
API 有一些限制和細微差異,請務必留意:
- 基於安全考量,
<template for>只能更新相同父項元素中的處理指令。直接將<template for>新增至<body>元素,即可存取整份文件 (包括<head>)。 <?end>處理指令為選用,如果缺少,系統會取代<?start>元素與所含元素結尾之間的內容。<template for>開始串流後,如果移動處理指示,也可能導致非預期後果,例如新內容繼續串流至舊位置。- 請注意,使用
setHTML或innerHTML屬性等方法動態插入<template for>時,範本在剖析時的「父項」是中繼文件片段。也就是說,使用這些方法插入 HTML 無法修改現有的 DOM,且修補作業會在片段中「就地」進行。不過,使用streamHTMLUnsafe等方法 (稍後會介紹) 串流時,不會有中繼片段,因此範本可以取代現有內容。
標準化狀態
<template for> 屬性是 HTML 標準的一部分,但目前並非所有瀏覽器都支援。
未來可能新增的功能
我們正在考慮未來可能新增的功能,包括:
- 用戶端包含。例如
<template for="footer" src="/partials/footer.html">,甚至不修補<template src="/partials/footer.html">。詳情請參閱說明。這項功能可透過chrome://flags/#enable-experimental-web-platform-features旗標使用。 - 避免覆寫不會變更的內容。這可以透過內容修訂版本編號或版本管理來達成。這樣一來,狀態就能在路徑變更或其他更新之間維持不變,而不是重設內容。
- 在修補時進行清理。例如:
<template for=icon safe><svg id="from-untrusted-source">...</svg></template>
Polyfill
Chrome 團隊已發布 template-for-polyfill,並在 npm 上提供,讓網站能立即使用這項新功能,不必等其他瀏覽器支援。
由於無法直接更新瀏覽器的 HTML 剖析器,因此有一些限制,但最常見的用途都涵蓋在內。網站仍應在其他瀏覽器中進行測試。
更新 HTML 插入和串流方法
並非所有內容都能以 HTML 格式提交。Chrome 在這方面的第二部分工作,旨在讓使用者更輕鬆地使用 JavaScript 更新內容。
目前已有許多方法,可使用 JavaScript 將 HTML 動態插入現有文件:
setHTMLsetHTMLUnsafeinnerHTML和outerHTMLcreateContextualFragmentinsertAdjacentHTML
不過,這些方法的運作方式略有不同,開發人員不一定會注意到這些細微差異:
- 新內容會覆寫還是附加?
- 是否會清理可能有害的 HTML,例如逸出
<script>標記? - 如果沒有,是否應執行
<script>? - 如何與可信任類型搭配使用?
很少有開發人員能誠實地看待這些 API,並自信地回答每個 API 的問題。
一項重大限制是,只有在預先知道一組完整的 HTML 時,才能使用這些方法,而目前已有呼叫允許串流 HTML。實際上,這表示您必須先下載整個內容,才能插入內容,而 HTML 的其中一個優點是能夠立即串流內容。您可以透過分割酬載或使用 document.write 等不建議使用的駭客方法,以有限的方式解決這個問題,但這些方法會帶來其他問題。
一組新的靜態和串流 API
Browser Support
Chrome 致力開發一系列新 API,並擴充現有的 setHTML 和 setHTMLUnsafe,以簡化這項作業,同時推出串流功能。
開發人員可從 Chrome 148 開始,使用 chrome://flags/#enable-experimental-web-platform-features 旗標測試這些功能,預計在 Chrome 155 正式推出。
你可以使用方法來設定或取代內容,也可以在現有 HTML 前後插入內容。每個方法都有對應的串流:
| 動作 | 靜態 | 串流 |
|---|---|---|
| 設定元素的 HTML 內容 | setHTML(html, options); |
streamHTML(options); |
| 將整個元素替換為這個 HTML | replaceWithHTML(html, options); |
streamReplaceWithHTML(options); |
| 在元素前加入 HTML | beforeHTML(html, options); |
streamBeforeHTML(options); |
| 將 HTML 新增為元素的第一個子項 | prependHTML(html, options); |
streamPrependHTML(options); |
| 將 HTML 新增為元素的最後一個子項 | appendHTML(html, options); |
streamAppendHTML(options); |
| 在元素後方加入 HTML | afterHTML(html, options); |
streamAfterHTML(options); |
此外,我們很快就會介紹 Unsafe 版本。雖然這些方法看起來很多 (尤其是加入 Unsafe 對等方法時),但一致的命名慣例可讓您更清楚瞭解每個方法的作用,而不像先前提到不相關的方法。
靜態版本會將新的 HTML 做為 DOM 字串引數,並提供選用選項:
const newHTML = "<p>This is a new paragraph</p>";
const contentElement = document.querySelector('#content-to-update');
contentElement.setHTML(newHTML);
串流版本可與 Streams API 搭配使用,例如 getWriter():
const contentElement = document.querySelector('#content-to-update');
const writer = contentElement.streamHTMLUnsafe().getWriter();
// Example stream of updating content
while (true) {
await writer.write(`<p>${++i}</p>`);
await new Promise((resolve) => setTimeout(resolve, 1000));
}
writer.close();
或者,也可以使用管道鏈從擷取回應中取得:
const contentElement = document.querySelector('#content-to-update');
const response = await fetch('/api/content.html');
response.body
.pipeThrough(new TextDecoderStream())
.pipeTo(contentElement.streamHTMLUnsafe());
textStream() 便利方法
我們也新增了 textStream 便利方法,可直接串流,不需經過中間的 TextDecoderStream() 步驟:
const contentElement = document.querySelector('#content-to-update');
const response = await fetch('/api/content.html');
response.textStream().pipeTo(contentElement.streamHTMLUnsafe());
options
options 引數可讓您指定自訂 sanitizer,預設值為 default,表示預設清理工具設定。使用方式如下:
const newHTML = '<p>This is a new paragraph</p>';
const contentElement = document.querySelector('#content-to-update');
// Only allows basic formatting
const basicFormattingSanitzer = new Sanitizer({ elements: ['em', 'i', 'b', 'strong'] });
contentElement.setHTML(newHTML, {sanitizer: basicFormattingSanitzer});
「不安全」方法
每個 API 也有「不安全」版本:
| 動作 | 靜態 | 串流 |
|---|---|---|
| 設定元素的 HTML 內容 | setHTMLUnsafe(html,options); |
streamHTMLUnsafe(options); |
| 將整個元素替換為這個 HTML | replaceWithHTMLUnsafe(html, options); |
streamReplaceWithHTMLUnsafe(options); |
| 在元素前加入 HTML | beforeHTMLUnsafe(html, options); |
streamBeforeHTMLUnsafe(options); |
| 將 HTML 新增為元素的第一個子項 | prependHTMLUnsafe(html, options); |
streamPrependHTMLUnsafe(options); |
| 將 HTML 新增為元素的最後一個子項 | appendHTMLUnsafe(html, options); |
streamAppendHTMLUnsafe(options); |
| 在元素後方加入 HTML | afterHTMLUnsafe(html, options); |
streamAfterHTMLUnsafe(options); |
這些「不安全」方法預設會關閉淨化器,但您可以視需要指定自訂淨化器。這些方法也允許使用選用的 runScripts 選項執行指令碼,預設值為 false。
與 setHTML 相同,setHTMLUnsafe 是現有方法,但已新增 runScripts 選項參數,以便與指令碼執行搭配使用:
const newHTML = `<p>This is a new paragraph</p>
<script src=script.js></script>`;
const contentElement = document.querySelector('#content-to-update');
contentElement.setHTMLUnsafe(newHTML, {runScripts: true});
方法中的「unsafe」字詞是為了提醒開發人員潛在風險,以及如何清理或限制指令碼,並非表示不應使用這些方法。
這項操作的「不安全」程度取決於輸入內容的可信度。Unsafe 靜態方法都適用於 DOM 字串或 TrustedHTML 做為 html 引數,也允許使用清理工具。不過,runScript 的主要目的是允許指令碼,因此預設不會使用任何清理工具。
用途
這些新 API 讓開發人員能更輕鬆地將 HTML 新增至現有頁面,並新增具有一致名稱和選項的新 API。串流 API 的優點在於,不必等到所有新內容都上傳至平台,就能開始播放。
用途包括:
- 在單頁應用程式中動態串流大型內容更新。如前所述,目前 SPA 架構的一大缺點,就是無法利用初始 HTML 載入的串流特性,但現在這個問題已獲得解決!
- 插入 HTML 頁尾等常見內容。使用 JavaScript API 可提取部分內容並插入網頁,充分利用快取功能,而不必在每個傳送的網頁中重複這些內容。不過,由於這項功能需要 JavaScript 才能執行,因此只能用於初始載入時不會顯示的內容。
再次提醒,以上只是幾個例子,我們很期待看到各位的創意!
限制和細微差異
這些新 API 也有一些限制和細微差異,請務必留意:
- 如要整合串流與 Trusted Types API,必須使用新的
createParserOptions方法,將清理工具插入任何 HTML 設定作業。如要進一步瞭解 Trusted Types 整合,請參閱說明文件 - 與
<template for>類似,移動正在串流的元素可能會導致非預期結果或串流錯誤。 streamHTMLUnsafe在許多方面都更像主要剖析器,包括在<template for>指令新增至主要文件時處理這些指令,以及將defer指令碼延遲到串流結束。
標準化狀態
較新的插入和串流方法正在加入 HTML 標準,但尚未在所有瀏覽器中支援。
Polyfill
Chrome 團隊已發布 html-setters-polyfill,並在 npm 上提供,讓網站能立即使用這項新功能,不必等其他瀏覽器支援。
請注意,這個 polyfill 不會串流,而是在完成後緩衝並套用。這比較像是 API 形狀的 polyfill,而非功能。
此外,安全內容的設定取決於 setHTML 和 Sanitizer API,而 Safari 不支援這項 API。
兩者並用
雖然這兩個 API 各自獨立,但結合使用更能發揮效益。只要將新的 <template for> 元素串流至 HTML,就能動態更新內容的不同部分,不必使用個別的 JavaScript 參照直接指定 DOM。
如要實作基本的 SPA 樣式載入網頁,可以載入含有處理指令的大綱網頁,然後將每個新網頁的範本串流至 HTML 底部,插入這些處理指令。
這兩個 API 還有更多潛力和用途,請盡情發揮想像力。簡化部分更新的管理作業,可減少樣板程式碼、簡化更新作業,並發掘網頁的新潛力!
Chrome 團隊正在宣告式部分更新專案中開發更多 API,但我們很高興能先推出這兩個 API。我們會持續提供最新消息,並在有更多相關資訊時通知你。