原生 CSS Custom Highlight 終于來(lái)了
介紹一個(gè)比較前沿但是非常有用的新特性:一個(gè)瀏覽器原生支持的 CSS? 文本高亮高亮功能,官方名稱叫做 CSS Custom Highlight API[1],有了它,可以在不改變 dom 結(jié)構(gòu)的情況下自定義任意文本的樣式,例如:
再例如搜索詞高亮。
還可以輕易實(shí)現(xiàn)代碼高亮。
多么令人興奮的功能啊,現(xiàn)在在 Chrome 105 中已經(jīng)正式支持了(無(wú)需開啟實(shí)驗(yàn)特性),一起學(xué)習(xí)一下吧
一、偽元素 ::highlight()
要自定義任意文本樣式需要 CSS 和 JS 的共同作用。
首先來(lái)看 CSS 部分,一個(gè)新的偽元素,非常簡(jiǎn)單、
和::selection這類偽元素比較類似,僅支持部分文本相關(guān)樣式,如下
- 文本顏色 color。
- 背景顏色 background-color。
- 文本修飾 text-decoration。
- 文本陰影 text-shadow。
- 文本描邊 -webkit-text-stroke。
- 文本填充 -webkit-text-fill-color。
注意,注意,注意不支持background-image,也就是漸變之類的也不支持。
但是,僅僅知道這個(gè)偽類是沒用的,她還需要一個(gè)“參數(shù)”,也就是上面的custom-highlight-name,表示高亮的名稱,那這個(gè)是怎么來(lái)的呢?或者換句話說(shuō),如何去標(biāo)識(shí)頁(yè)面中需要自定義樣式的那部分文本呢?
這就需要借助下面的內(nèi)容了,看看如何生成這個(gè)“參數(shù)”,這才是重點(diǎn)
二、CSS Custom Highlight API
大部分操作其實(shí)和這個(gè)原理是相同的,只是把拿到的選區(qū)做了進(jìn)一步處理,具體分以下幾步
1、創(chuàng)建選區(qū)(重點(diǎn))
首先,通過Range[2]對(duì)象創(chuàng)建文本選擇范圍,就像用鼠標(biāo)滑過選區(qū)一樣,這也是最復(fù)雜的一部分,例如:
這樣可以得到選區(qū)對(duì)象range1、range2。
2、創(chuàng)建高亮
然后,將創(chuàng)建的選區(qū)高亮實(shí)例化,需要用到Highlight[3]對(duì)象。
當(dāng)然也可以根據(jù)需求創(chuàng)建多個(gè)。
這樣可以得到高亮對(duì)象highlight1、highlight2。
3、注冊(cè)高亮
接著,需要將實(shí)例化的高亮對(duì)象通過[CSS.Highlight](HighlightRegistry - Web APIs | MDN (mozilla.org "CSS.Highlight"))注冊(cè)到頁(yè)面。
有點(diǎn)類似于Map對(duì)象的操作。
目前兼容性比較差,所以需要額外判斷一下。
注意看,上面注冊(cè)的key名,highlight1就是上一節(jié)提到的高亮名稱,也就是 CSS 中需要的“參數(shù)”
4、自定義樣式
最后,將定義的高亮名稱結(jié)合::highlight,這樣就可以自定義選中樣式了
以上就是全部過程了,稍顯復(fù)雜,但是還是比較好理解的,關(guān)鍵是第一步創(chuàng)建選區(qū)的過程,最為復(fù)雜。
原理就是這樣,下面看一些實(shí)例。
三、彩虹文本
現(xiàn)在來(lái)實(shí)現(xiàn)文章開頭圖示效果,彩虹文本效果。總共7種顏色,文字依次變色,不斷循環(huán),而且僅有一個(gè)標(biāo)簽。
這里總共有7?種顏色,所以需要?jiǎng)?chuàng)建7?個(gè)高亮區(qū)域,可以先定義高亮 CSS,如下:
現(xiàn)在肯定不會(huì)有什么變化,因?yàn)檫€沒創(chuàng)建選區(qū)
先創(chuàng)建一個(gè)高亮區(qū)域試試,比如第一個(gè)文字。
效果如下:
下面通過循環(huán),創(chuàng)建7個(gè)高亮區(qū)域。
這樣就在不改變dom的情況下實(shí)現(xiàn)了彩虹文字效果。
完整代碼可以查看以下任意鏈接:(注意需要Chrome 105+)
- CSS Custom Highlight API (juejin.cn)[4]
- CSS Custom Highlight API (codepen.io)[5]
- CSS Custom Highlight API (runjs.work)[6]
四、文本搜索高亮
大家都知道瀏覽器的搜索功能,ctrl+f就可以快速對(duì)整個(gè)網(wǎng)頁(yè)就行查找,查找到的關(guān)鍵詞會(huì)添加黃色背景的高亮,如下:
以前一直很疑惑這個(gè)顏色是怎么添加的,畢竟沒有任何包裹標(biāo)簽。現(xiàn)在有了CSS Custom Highlight API ,完全可以手動(dòng)實(shí)現(xiàn)一個(gè)和原生瀏覽器一模一樣的搜索高亮功能。
到目前為止,還無(wú)法自定義原生搜索高亮的黃色背景,以后可能會(huì)開放。
假設(shè)HTML結(jié)構(gòu)是這樣的,一個(gè)搜索框和一堆文本。
簡(jiǎn)單美化一下后效果如下:
然后就是監(jiān)聽輸入框,遍歷文本節(jié)點(diǎn)(推薦使用原生的treeWalker,當(dāng)然普通的遞歸也可以),根據(jù)搜索詞創(chuàng)建選區(qū),詳細(xì)代碼如下。
最后,通過CSS設(shè)置高亮的顏色。
實(shí)時(shí)搜索效果如下:
完整代碼可以查看以下任意鏈接:(注意需要Chrome 105+)
- CSS Highlight search (juejin.cn)[7]
- CSS Highlight search (codepen.io)[8]
- CSS Highlight search (runjs.work)[9]
還可以將高亮效果改成波浪線。
效果如下,是不是也可用作錯(cuò)別字標(biāo)識(shí)呢?
除了避免dom?操作帶來(lái)的便利外,性能也能得到極大的提升,畢竟創(chuàng)建、移除dom也是性能大戶,下面是一個(gè)測(cè)試 demo,搬運(yùn)自
??https://ffiori.github.io/highlight-api-demos/demo-performance.html??[10]
測(cè)試代碼可以查看以下任意鏈接:
- Highlight performance demo (juejin.cn)[11]
- Highlight performance demo (codepen.io)[12]
- Highlight performance demo (runjs.work)[13]
測(cè)試效果如下:
在10000?個(gè)節(jié)點(diǎn)的情況下,兩者相差100倍的差距!而且數(shù)量越大,性能差距越明顯,甚至直接導(dǎo)致瀏覽器卡死!
五、代碼高亮編輯器
最后再來(lái)看一個(gè)非常實(shí)用的例子,可以輕易實(shí)現(xiàn)一個(gè)代碼高亮的編輯器。
假設(shè) HTML結(jié)構(gòu)是這樣的,很簡(jiǎn)單,就一個(gè)純文本的標(biāo)簽。
簡(jiǎn)單修飾一下,設(shè)置為可編輯元素。
效果如下:
那么,如何讓這些代碼高亮呢?
這就需要對(duì)內(nèi)容進(jìn)行關(guān)鍵詞分析提取了,我們可以用現(xiàn)有的代碼高亮庫(kù),比如highlight.js[14]。
通過這個(gè)方法可以獲取到CSS語(yǔ)言的關(guān)鍵詞以及類型,如下:
簡(jiǎn)單解釋一下,這是一個(gè)數(shù)組,如果是純文本,表示普通的字符,如果是對(duì)象,表示是關(guān)鍵詞,例如第一個(gè),children?里面的ul?就是關(guān)鍵詞,類型是selector-tag?,也就是選擇器,除此之外,還有attribute、number、selector-class等各種類型。有了這些關(guān)鍵詞,我們就可以把這些文本單獨(dú)選取出來(lái),然后高亮成不同的顏色。
接下來(lái),就需要對(duì)代碼內(nèi)容進(jìn)行遍歷了,方法也是類似的,如下:
最后,根據(jù)不同的類型,定義不同的顏色就行了,如下:
這樣就得到了一個(gè)支持代碼高亮的簡(jiǎn)易編輯器了。
相比傳統(tǒng)的編輯器而言,這個(gè)屬于純文本編輯,非常輕量,在高亮的同時(shí)也不會(huì)影響光標(biāo),因?yàn)椴粫?huì)生成新的??dom?
?,性能也是超級(jí)棒。
完整代碼可以查看以下任意鏈接:
- CSS highlight editor (juejin.cn)[15]
- CSS highlight editor (codepen.io)[16]
- CSS highlight editor (runjs.work)[17]
六、最后總結(jié)一下
以上就是關(guān)于CSS Custom Highlight API的使用方式以及應(yīng)用示例了,下面再來(lái)回顧一下使用步驟:
- 創(chuàng)建選區(qū),new Range。
- 創(chuàng)建高亮,new Highlight。
- 注冊(cè)高亮,CSS.highlights.set。
- 自定義樣式,::highlight()。
相比傳統(tǒng)使用標(biāo)簽的方式而已,有很多優(yōu)點(diǎn)
- 使用場(chǎng)景更廣泛,很多情況下不能修改dom或者成本極大
- 性能更高,避免了操作dom?帶來(lái)的額外開銷,在dom?較多情況下性能差異至少100倍
- 幾乎沒有副作用,能有效減少dom變化引起的其他影響,比如光標(biāo)選區(qū)的處理
其實(shí)歸根結(jié)底,都是dom?變化帶來(lái)的,而Highlight API恰好能有效避開這個(gè)問題。當(dāng)然也有一些缺陷,由于僅僅能改變文本相關(guān)樣式,所以也存在一些局限性,這個(gè)就需要權(quán)衡了,目前兼容性也還不足,僅適用于內(nèi)部項(xiàng)目,敬請(qǐng)期待
參考資料
[1]CSS Custom Highlight API: https://developer.mozilla.org/en-US/docs/Web/API/CSS_Custom_Highlight_API。
[2]Range: https://developer.mozilla.org/en-US/docs/Web/API/Range。
[3]Highlight: https://developer.mozilla.org/en-US/docs/Web/API/Highlight。
[4]CSS Custom Highlight API (juejin.cn): https://code.juejin.cn/pen/7198496899391815736。
[5]CSS Custom Highlight API (codepen.io): https://codepen.io/xboxyan/pen/qByzGYr。
[6]CSS Custom Highlight API (runjs.work): https://runjs.work/projects/450431c8f0064298。
[7]CSS Highlight search (juejin.cn): https://code.juejin.cn/pen/7198488612801871929。
[8]CSS Highlight search (codepen.io): https://codepen.io/xboxyan/pen/eYjwoqo。
[9]CSS Highlight search (runjs.work): https://runjs.work/projects/a661feba3dad44c9。
[10]https://ffiori.github.io/highlight-api-demos/demo-performance.html: https://ffiori.github.io/highlight-api-demos/demo-performance.html。
[11]Highlight performance demo (juejin.cn): https://code.juejin.cn/pen/7198487962978353208。
[12]Highlight performance demo (codepen.io): https://codepen.io/xboxyan/pen/YzjoMmp。
[13]Highlight performance demo (runjs.work): https://runjs.work/projects/e5fe09f70d324d99。
[14]highlight.js: https://highlightjs.org/。
[15]CSS highlight editor (juejin.cn): https://code.juejin.cn/pen/7198487629262749756。
[16]CSS highlight editor (codepen.io): https://codepen.io/xboxyan/pen/RwBzOmK。
[17]CSS highlight editor (runjs.work): https://runjs.work/projects/9ff7ab8f12844ce1。