網頁文本樣式化一直是開發者關注的焦點。令人期待的是CSS Custom Highlight API的出現,它將革新網頁文本範圍樣式化。
舉例來說,Google Docs、Word或Dropbox Paper等文本編輯軟件會檢測拼寫和語法錯誤,並在下方顯示波浪線以提示用戶。 VS Code等代碼編輯器對代碼錯誤也採用類似方法。
另一個常見的文本高亮用例是搜索和高亮功能,用戶在輸入框中輸入文本,頁面會搜索匹配結果並高亮顯示。現在,您可以在瀏覽器中嘗試按下Ctrl/⌘ F,然後輸入本文中的部分文本。
瀏覽器通常會自動處理這些樣式情況。可編輯區域(如)會自動顯示拼寫錯誤的波浪線。查找命令會自動高亮顯示找到的文本。
但是,如果我們想自己進行這種樣式化怎麼辦?長期以來,如何在網頁上實現這一點一直是一個常見問題,它可能浪費了許多人大量的時間。
這不是一個簡單的難題。我們不僅僅是用帶有class的<span></span>
標籤包裹文本並應用一些CSS。實際上,這需要能夠正確地高亮顯示跨越任意複雜DOM樹的多個文本範圍,並且可能跨越DOM元素的邊界。
解決這個問題的常見方法有兩種:
我們首先回顧一下這兩種方法,然後看看即將推出的CSS Custom Highlight API如何改變這一切。
最著名的可樣式化文本範圍可能是用戶選擇。當您使用指向設備選擇網頁上的文本時,會自動創建一個Selection對象。事實上,現在嘗試選擇此頁面上的文本,然後在DevTools控制台中運行document.getSelection()
。您應該會看到所選文本的位置信息。
事實證明,您還可以通過JavaScript以編程方式創建文本選擇。以下是一個示例:
// 首先,創建一個Range對象。 const range = new Range(); // 並設置其起始和結束位置。 range.setStart(parentNode, startOffset); range.setEnd(parentNode, endOffset); // 然後,將當前選擇設置為此範圍。 document.getSelection().removeAllRanges(); document.getSelection().addRange(range);
最後一塊拼圖是樣式化此範圍。 CSS有一個名為::selection
的偽元素可以做到這一點,並且它在所有瀏覽器中都受支持。
::selection { background-color: #f06; color: white; }
以下是一個使用此技術依次高亮顯示頁面中所有單詞的示例:
除了::selection
偽元素之外,還有許多其他偽元素:
::target-text
選擇瀏覽器中已滾動到的文本(支持滾動到文本功能的瀏覽器)。 (MDN)::spelling-error
的文本。 (MDN)::grammar-error
選擇瀏覽器標記為包含語法錯誤的文本。 (MDN)不幸的是,這裡的瀏覽器支持不是很好,儘管這些範圍本身很有用,但它們不能用於樣式化自定義文本片段——只能樣式化瀏覽器預定義的文本片段。
因此,用戶文本選擇很好,因為它相對容易實現,並且不會更改頁面的DOM。實際上,Range對象本質上是頁面中段落的坐標,而不是需要創建才能存在的HTML元素。
然而,一個主要的缺點是,創建選擇會重置用戶已經手動選擇的任何內容。嘗試在上面的演示中選擇文本以測試這一點。您會看到代碼將選擇移動到其他位置時,它會消失。
如果您使用Selection對像不足以滿足您的需求,那麼第二個解決方案幾乎是唯一的選擇。此解決方案圍繞著自己動手做所有事情,使用JavaScript在您希望高亮顯示出現的位置插入新的HTML元素。
不幸的是,這意味著需要編寫和維護更多的JavaScript代碼,更不用說每當高亮顯示更改時,它都會強制瀏覽器重新創建頁面的佈局。此外,還有一些複雜的邊緣情況,例如,當您想高亮顯示跨越多個DOM元素的文本片段時。
有趣的是,CodeMirror和Monaco(為VS Code提供支持的JavaScript文本編輯器庫)有自己的高亮邏輯。它們使用稍微不同的方法,其中高亮顯示包含在DOM樹的單獨部分中。文本行和高亮顯示的段落在DOM中的兩個不同位置呈現,然後彼此定位。如果您檢查包含文本的DOM子樹,則沒有高亮顯示。通過這種方式,可以重新渲染高亮顯示而不會影響文本行,並且不必在文本行中引入新的元素。
總的來說,感覺缺少一個瀏覽器支持的高亮顯示功能。某些功能可以幫助解決所有這些缺點(不會干擾用戶文本選擇,支持多選,代碼簡單)並且比自定義解決方案更快。
幸運的是,這就是我們在這裡要討論的內容!
CSS Custom Highlight API是一個新的W3C規範(目前處於工作草案狀態),它使得可以從JavaScript樣式化任意文本範圍!這裡的方法與我們前面回顧的用戶文本選擇技術非常相似。它為開發人員提供了一種方法來創建任意範圍(來自JavaScript),然後使用CSS對其進行樣式化。
第一步是創建要高亮顯示的文本範圍,這可以使用JavaScript中的Range來完成。因此,就像我們在設置當前選擇時所做的那樣:
const range = new Range(); range.setStart(parentNode, startOffset); range.setEnd(parentNode, endOffset);
值得注意的是,如果作為第一個參數傳遞的節點是文本節點或不是文本節點,則setStart
和setEnd
方法的工作方式不同。對於文本節點,偏移量對應於節點中的字符數。對於其他節點,偏移量對應於父節點中的子節點數。
還值得注意的是, setStart
和setEnd
並不是描述範圍起始和結束位置的唯一方法。查看Range類上可用的其他方法以查看其他選項。
第二步包括為上一步中創建的範圍創建Highlight對象。 Highlight對象可以接收一個或多個Range。因此,如果您想以完全相同的方式高亮顯示許多文本片段,則可能應該創建一個Highlight對象並使用與這些文本片段對應的所有Range來初始化它。
const highlight = new Highlight(range1, range2, ..., rangeN);
但是您也可以根據需要創建任意數量的Highlight對象。例如,如果您正在構建一個協作文本編輯器,其中每個用戶獲得不同的文本顏色,那麼您可以為每個用戶創建一個Highlight對象。然後可以對每個對象進行不同的樣式化,正如我們接下來將看到的。
現在,Highlight對象本身不會執行任何操作。它們首先需要在所謂的突出顯示註冊表中註冊。這是使用CSS Highlights API完成的。註冊表就像一個地圖,您可以通過為高亮顯示指定名稱來註冊新的高亮顯示,以及刪除高亮顯示(甚至清除整個註冊表)。
以下是註冊單個高亮顯示的方法。
CSS.highlights.set('my-custom-highlight', highlight);
其中my-custom-highlight
是您選擇的名稱, highlight
是上一步中創建的Highlight對象。
最後一步是實際樣式化已註冊的高亮顯示。這是使用新的CSS ::highlight()
偽元素完成的,使用您在註冊Highlight對象時選擇的名稱(在我們的示例中為my-custom-highlight
)。
::highlight(my-custom-highlight) { background-color: yellow; color: black; }
值得注意的是,就像::selection
一樣,只有一部分CSS屬性可以與::highlight()
偽元素一起使用:
background-color
caret-color
color
cursor
fill
stroke
stroke-width
text-decoration
(這可能只在規範的版本2中受支持)text-shadow
有多種方法可以更新頁面上的高亮顯示文本。
例如,您可以使用CSS.highlights.clear()
完全清除高亮顯示註冊表,然後從頭開始。或者,您還可以更新底層範圍,而無需重新創建任何對象。為此,再次使用range.setStart
和range.setEnd
方法(或任何其他Range方法),瀏覽器將重新繪製高亮顯示。
但是,Highlight對象的工作方式類似於JavaScript Set,這意味著您還可以使用highlight.add(newRange)
將新的Range對象添加到現有的Highlight中,或者使用highlight.delete(existingRange)
刪除Range。
第三,您還可以向CSS.highlights註冊表添加或刪除特定的Highlight對象。由於此API的工作方式類似於JavaScript Map,您可以使用set
和delete
來更新當前已註冊的Highlights。
CSS Custom Highlight API的規範相對較新,其在瀏覽器中的實現仍不完整。因此,儘管這將成為Web平台的一個非常有用的補充,但它還不太適合用於生產環境。
Microsoft Edge團隊目前正在Chromium中實現CSS Custom Highlight API。事實上,通過啟用實驗性Web平台功能標誌(在about:flags下),現在就可以在Canary版本中使用此功能。目前還沒有關於該功能何時將在Chrome、Edge和其他基於Chromium的瀏覽器中發布的明確計劃,但它已經非常接近了。
Safari 99 也支持此API,但在實驗標誌(Develop → Experimental Features → Highlight API)之後,並且接口略有不同,因為它使用StaticRange對象而不是Range對象。
Firefox尚不支持此API,不過您可以閱讀Mozilla關於此API的立場以了解更多信息。
說到Microsoft Edge,他們已經設置了一個演示,您可以在其中試用CSS Custom Highlight API。但在嘗試演示之前,請確保您使用的是啟用了about:flags頁面中實驗性Web平台功能標誌的Chrome或Edge Canary。
/button 查看演示
該演示使用Custom Highlight API根據您在頁面頂部搜索字段中輸入的內容來高亮顯示頁面中的文本範圍。
頁面加載後,JavaScript代碼檢索頁面中的所有文本節點(使用TreeWalker),當用戶在搜索字段中鍵入內容時,代碼會迭代這些節點,直到找到匹配項。然後使用這些匹配項創建Range對象,然後使用Custom Highlight API對其進行高亮顯示。
那麼,這個新的瀏覽器提供的高亮顯示API真的值得嗎?絕對值得!
首先,即使CSS Custom Highlight API起初看起來有點複雜(例如,必須創建範圍,然後是高亮顯示,然後註冊它們,最後樣式化它們),它仍然比創建新的DOM元素並將它們插入到正確的位置要簡單得多。
更重要的是,瀏覽器引擎可以非常非常快速地樣式化這些範圍。
僅允許使用一部分CSS屬性與::highlight()
偽元素一起使用的理由是,這部分屬性只包含瀏覽器可以非常有效地應用的屬性,而無需重新創建頁面的佈局。通過在頁面周圍插入新的DOM元素來高亮顯示文本範圍,需要引擎做更多工作。
但不要相信我的話。 Fernando Fiori參與了該API的開發,他創建了這個不錯的性能比較演示。在我的電腦上,CSS Custom Highlight API的性能平均比基於DOM的高亮顯示快5倍。
由於Chromium和Safari已經提供了實驗性支持,我們正越來越接近可以在生產環境中使用的東西。我迫不及待地想看到瀏覽器一致地支持Custom Highlight API,並看看這將解鎖哪些功能!
以上是CSS自定義突出顯示API:首次查看的詳細內容。更多資訊請關注PHP中文網其他相關文章!