文字片段可讓您在網址片段中指定文字摘要。瀏覽含有這類文字片段的網址時,瀏覽器可以強調及/或吸引使用者的注意力。
片段 ID
Chrome 80 是重大版本,其中包含許多備受期待的功能,例如網路工作站中的 ECMAScript 模組、空值合併、選用鏈結等。這次發布內容一如往常,透過 Chromium 網誌上的網誌文章發布。請參閱下方螢幕截圖,瞭解網誌文章的摘要。
您可能會想知道所有紅色方塊代表什麼。這些是開發人員工具中下列程式碼片段的結果。它會醒目顯示所有具有 id
屬性的元素。
document.querySelectorAll('[id]').forEach((el) => {
el.style.border = 'solid 2px red';
});
我可以使用片段 ID,為任何以紅色方塊標示的元素加入深層連結,然後將其用於網頁網址的 hash。假設我想連結至側邊欄中的「在產品論壇中提供意見」方塊,我可以手動建立網址 https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#HTML1
。如您在「開發人員工具」的「元素」面板中看到的,問題元素含有值為 HTML1
的 id
屬性。
如果我使用 JavaScript 的 URL()
建構函式剖析這個網址,就會顯示不同的元件。請注意,hash
屬性含有 #HTML1
值。
new URL('https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#HTML1');
/* Creates a new `URL` object
URL {
hash: "#HTML1"
host: "blog.chromium.org"
hostname: "blog.chromium.org"
href: "https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#HTML1"
origin: "https://blog.chromium.org"
password: ""
pathname: "/2019/12/chrome-80-content-indexing-es-modules.html"
port: ""
protocol: "https:"
search: ""
searchParams: URLSearchParams {}
username: ""
}
*/
不過,我必須開啟開發人員工具才能找到元素的 id
,這說明網頁的這個特定部分很可能與網誌文章作者的連結有關。
如果要連結至沒有 id
的項目,該怎麼做?假設我想連結至「ECMAScript Modules in Web Workers」標題。如您在下方螢幕截圖中看到的,問題中的 <h1>
沒有 id
屬性,因此我無法連結至這個標題。這就是 Text Fragments 解決的問題。
文字片段
文字片段提案新增了在網址雜湊中指定文字片段的支援功能。導覽至含有這類文字片段的網址時,使用者代理程式可強調及/或吸引使用者註意。
瀏覽器相容性
基於安全考量,這項功能要求連結必須在 noopener
情境中開啟。因此,請務必在 <a>
錨點標記中加入 rel="noopener"
,或是將 noopener
新增至窗口功能功能的 Window.open()
清單。
start
簡單來說,文字片段的語法如下:井字號 #
後面接著 :~:text=
,最後是 start
,代表我要連結的百分比編碼文字。
#:~:text=start
舉例來說,假設我想連結至 Chrome 80 功能發布網誌文章中的「Web Workers 中的 ECMAScript 模組」標題,此時的網址會是:
文字片段會以「這樣」的方式強調。如果你在 Chrome 等支援的瀏覽器中點選連結,文字片段就會醒目顯示並捲動至可見位置:
start
和end
那麼,如果我想連結至整個標題為「Web Workers 中的 ECMAScript 模組」的章節,而非僅連結至標題,該怎麼做?如果將該區段的整個文字以百分比編碼,產生的網址會過長,無法使用。
幸運的是,有更好的方法。我可以使用 start,end
語法框住所需的文字,而非整個文字。因此,我在所需文字開頭指定幾個使用百分比編碼的字詞,並在所需文字結尾指定幾個使用百分比編碼的字詞,並以半形逗號 ,
分隔。
看起來會像這樣:
start
的 ECMAScript%20Modules%20in%20Web%20Workers
為 ECMAScript%20Modules%20in%20Web%20Workers
,接著是半形逗號 ,
,然後是 ES%20Modules%20in%20Web%20Workers.
為 end
。在 Chrome 等支援的瀏覽器中點選連結後,整個部分都會醒目顯示,並捲動至可見範圍內:
您可能會好奇為何我選擇 start
和 end
。其實,只要在兩端各有兩個字的較短網址 https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=ECMAScript%20Modules,Web%20Workers.
也能正常運作。將 start
和 end
與先前的值進行比較。
如果我進一步將 start
和 end
都只使用一個字,您會發現我遇到問題。網址 https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=ECMAScript,Workers.
現在更短了,但醒目顯示的文字片段不再是原本想要的片段。系統第一次出現 Workers.
這個字詞時,系統會停止醒目顯示文字。雖然正確,但不是我原本想強調的內容。問題是,目前的單字 start
和 end
值無法明確識別所需的部分:
prefix-
和-suffix
為 start
和 end
使用過長的值是取得不重複連結的解決方案。但在某些情況下,這並不適用。順帶一提,為什麼我會選擇 Chrome 80 發布網誌文章做為範例?答案是,這個版本推出了文字片段:
請注意,在上述螢幕截圖中,「text」一詞出現了四次。第四個出現的字元則以綠色程式碼字型書寫。如果我想連結至這個特定字詞,就會將 start
設為 text
。由於「text」這個字只有一個字,因此無法出現 end
。該怎麼辦?網址 https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=text
會在標題中首次出現「Text」這個字詞時進行比對:
幸運的是,我們有解決方案。在這種情況下,我可以指定 prefix-
和 -suffix
。綠色程式碼字型「text」前面的字詞是「the」,後面的字詞則是「parameter」。其他三個「text」字詞的周圍字詞都不同。有了這些知識,我可以調整先前的網址,並新增 prefix-
和 -suffix
。如同其他參數,這些參數也必須以百分比編碼,且可包含多個字詞。https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=the-,text,-parameter
。為了讓剖析器清楚識別 prefix-
和 -suffix
,兩者必須以破折號 -
分隔與 start
和選用的 end
。
完整語法
以下是文字片段的完整語法。(方括號表示選用參數)。所有參數的值都必須經過百分比編碼。這對於破折號 -
、& 符號和 &
和半形逗號 ,
字元特別重要,因此系統不會將這兩個字元解讀為文字指令語法的一部分。
#:~:text=[prefix-,]start[,end][,-suffix]
prefix-
、start
、end
和 -suffix
各自只會比對單一區塊層級元素中的文字,但完整的 start,end
範圍可以跨越多個區塊。舉例來說,:~:text=The quick,lazy dog
在以下範例中無法比對,因為開頭字串「The quick」並未出現在單一連續的區塊層級元素中:
<div>
The
<div></div>
quick brown fox
</div>
<div>jumped over the lazy dog</div>
不過,這項範例相符如以下範例所示:
<div>The quick brown fox</div>
<div>jumped over the lazy dog</div>
使用瀏覽器擴充功能建立文字片段網址
手動建立文字片段網址相當繁瑣,尤其是在確保網址不重複時。如果您真的想這麼做,規格說明書中提供了一些提示,並列出產生文字片段網址的確切步驟。我們提供一個名為 Link to Text Fragment 的開源瀏覽器擴充功能,可讓您選取任何文字,然後在內容選單中按一下「Copy Link to Selected Text」(複製連結至所選文字),即可連結至任何文字。這項擴充功能適用於下列瀏覽器:
使用同一個網址處理多個文字片段
請注意,一個網址中可能會出現多個文字片段。特定文字片段需要以 &
字元分隔。以下是包含三個文字片段的連結範例:https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=Text%20URL%20Fragments&text=text,-parameter&text=:~:text=On%20islands,%20birds%20can%20contribute%20as%20much%20as%2060%25%20of%20a%20cat's%20diet
。
混合元素和文字片段
傳統元素片段可與文字片段結合。舉例來說,如果網頁上的原始文字有所變更,這兩個網址都會在同一網址中,因此可提供有意義的備用網址,以便在文字片段不再相符時使用。連結至「產品論壇產品論壇」專區中的網址 https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#HTML1:~:text=Give%20us%20feedback%20in%20our%20Product%20Forums.
同時包含元素片段 (HTML1
) 和文字片段 (text=Give%20us%20feedback%20in%20our%20Product%20Forums.
):
片段指令
我尚未說明的語法中有一個元素:片段指令 :~:
。如上所述,為避免與現有網址元素片段的相容性問題,文字片段規格引入了片段指示詞。片段指令是網址片段的一部分,由程式碼序列 :~:
分隔。它是保留給 text=
等使用者代理程式指示,並在載入期間從網址中移除,以免作者指令碼無法直接與其互動。使用者代理程式指示也稱為「指令」。在具體案例中,text=
稱為「文字指令」。
特徵偵測
如要偵測支援情形,請測試 document
上的唯讀 fragmentDirective
屬性。片段指令是一種機制,可讓網址指定指向瀏覽器的指令,而非指向文件。這項功能的用意在於避免與作者指令碼直接互動,日後可以直接新增使用者代理程式指示,不必擔心會對現有內容造成破壞性變更。日後可能會新增的功能之一,就是翻譯提示。
if ('fragmentDirective' in document) {
// Text Fragments is supported.
}
功能偵測功能主要適用於動態產生連結的情況 (例如由搜尋引擎產生),以免將文字片段連結提供給不支援的瀏覽器。
設定文字片段樣式
根據預設,瀏覽器會以與 mark
相同的方式設定文字片段樣式 (通常是黑底黃字,這是 mark
的 CSS 系統顏色)。使用者代理程式樣式表包含的 CSS 如下所示:
:root::target-text {
color: MarkText;
background: Mark;
}
如您所見,瀏覽器會顯示虛擬選取器 ::target-text
,可用來自訂已套用的醒目顯示功能。舉例來說,您可以將文字片段設計為紅色背景上的黑色文字。如常,請務必檢查色彩對比,確保覆寫樣式不會導致無障礙問題,並確保醒目顯示內容在視覺上與其他內容有所區隔。
:root::target-text {
color: black;
background-color: red;
}
可填充性
文字片段功能可在某種程度上進行多重填充。我們提供polyfill,供擴充功能在內部使用,適用於未為文字片段提供內建支援的瀏覽器,因為這些功能是在 JavaScript 中實作。
程式輔助文字片段連結產生
polyfill 包含的 fragment-generation-utils.js
檔案,可用來匯入該檔案,可用來產生文字片段連結。請參考下列程式碼範例:
const { generateFragment } = await import('https://unpkg.com/text-fragments-polyfill/dist/fragment-generation-utils.js');
const result = generateFragment(window.getSelection());
if (result.status === 0) {
let url = `${location.origin}${location.pathname}${location.search}`;
const fragment = result.fragment;
const prefix = fragment.prefix ?
`${encodeURIComponent(fragment.prefix)}-,` :
'';
const suffix = fragment.suffix ?
`,-${encodeURIComponent(fragment.suffix)}` :
'';
const start = encodeURIComponent(fragment.textStart);
const end = fragment.textEnd ?
`,${encodeURIComponent(fragment.textEnd)}` :
'';
url += `#:~:text=${prefix}${start}${end}${suffix}`;
console.log(url);
}
取得文字片段以供數據分析
許多網站都會使用片段進行路由,因此瀏覽器會移除文字片段,以免這些網頁發生錯誤。我們已確認,需要公開文字片段連結至網頁,例如用於分析,但建議的解決方案尚未實作。目前的解決方法是使用下列程式碼來擷取所需資訊。
new URL(performance.getEntries().find(({ type }) => type === 'navigate').name).hash;
安全性
只有在使用者啟用的結果為完整 (非同頁) 導覽時,才會叫用文字片段指示詞。此外,如果導覽來源與目的地不同,導覽需要在 noopener
情境中進行,例如已知到達網頁必須充分隔離。文字片段指令僅會套用至主畫面。也就是說,系統不會在 iframe 內搜尋文字,且 iframe 導覽不會叫用文字片段。
隱私權
實作 Text Fragments 規格時,請務必避免洩漏網頁上是否找到文字片段的資訊。雖然元素片段完全由原始網頁作者控管,但任何人都可以建立文字片段。請回想一下,在上述範例中,由於 <h1>
沒有 id
,因此無法連結至「ECMAScript Modules in Web Workers」標題,但我和其他人如何能透過精心設計的文字片段連結至任何位置?
假設我放送了一個邪惡廣告聯播網,evil-ads.example.com
。並進一步想像,我在其中一個廣告 iframe 中,於使用者與廣告互動後,用文字片段網址以 dating.example.com#:~:text=Log%20Out
動態建立對 dating.example.com
的隱藏跨來源 iframe。如果找到「Log Out」文字,我知道受害者目前登入的是 dating.example.com
,可用於剖析使用者。由於簡單的 Text Fragment 實作可能會判斷成功比對應應造成聚焦切換,因此我在 evil-ads.example.com
上監聽 blur
事件,進而瞭解何時發生比對。在 Chrome 中,我們已實作文字片段,以避免發生上述情況。
另一種攻擊可能是根據捲動位置入侵網路流量。假設我有權存取受害者的網路流量記錄,例如公司內部網路的管理員。假設有一篇冗長的人力資源文件「如果您有以下問題,該怎麼辦?」,接著列出一系列狀況,例如「職業倦怠」、「焦慮」等。我可以將追蹤像素放在清單上的每個項目旁邊。如果我接著確定在載入追蹤像素,之後又載入追蹤像素,之後載入文件的時間很久 (比如說消耗項目,我可以確定內部網路管理員是員工點選含有機密的 :~:text=burn%20out
項目的文字片段連結,因此不會假設有人這麼做。由於這個例子在開始時就有些不自然,且要利用這個例子進行攻擊必須符合非常特定的先決條件,因此 Chrome 安全性團隊評估了在導覽中實作捲動的風險,認為風險可控。其他使用者代理程式可能會改為顯示手動捲動 UI 元素。
對於希望停用的網站,Chromium 支援可傳送的 Document Policy 標頭值,這樣使用者代理程式就不會處理文字片段網址。
Document-Policy: force-load-at-top
停用文字片段
停用此功能最簡單的方法是使用可插入 HTTP 回應標頭的擴充功能 (例如 ModHeader (非 Google 產品)) 插入回應 (「不是」要求) 標頭,如下所示:
Document-Policy: force-load-at-top
另一種更複雜的選擇退出方式,是使用企業設定 ScrollToTextFragmentEnabled
。如要在 macOS 上執行這項操作,請在終端機中貼上下列指令。
defaults write com.google.Chrome ScrollToTextFragmentEnabled -bool false
在 Windows 上,請按照 Google Chrome Enterprise 說明支援網站上的說明文件操作。
網頁搜尋中的文字片段
針對某些搜尋,Google 搜尋引擎會提供快速解答或摘要,並附上相關網站的內容摘要。一般來說,這類精選摘要最可能在以問句形式進行搜尋時出現。按一下精選摘要後,系統會將使用者直接引導至來源網頁上的精選摘要文字。這是因為系統會自動建立文字片段網址。
結論
文字片段網址是一項強大的功能,可以連結網頁上的任意文字。學術界可利用這項功能提供極為準確的引用或參考連結。搜尋引擎可使用這項屬性,將深層連結指向網頁上的文字結果。社群網站可以使用這項功能,讓使用者分享網頁的特定段落,而非無法存取的螢幕截圖。希望您能開始使用「文字片段」網址,並照常找到這些網址。請務必安裝「Link to Text Fragment」(連結至文字片段) 瀏覽器擴充功能。
相關連結
特別銘謝
文字片段是由 Nick Burris 和 David Bokan 實作及指定,Grant Wang 也對此做出貢獻。感謝 Joe Medley 詳盡審查本文。主頁橫幅由 Greg Rakozy 提供,位於 Unsplash 網站上。