当前位置: 首页 > 科技观察

NativeCSSCustomHighlight终于来了

时间:2023-03-12 06:14:05 科技观察

介绍了一个很前沿但是非常好用的新特性:一个浏览器原生支持的CSS文本高亮功能,官方名称是CSSCustomHighlightAPI[1],有了它,你可以自定义在不改变dom结构的情况下任意文本的样式,比如image-20230210141449363然后高亮搜索词image-20230210200730128轻松实现代码高亮image-20230210200832167有多少令人兴奋的功能,现在在Chrome105中正式支持(无需启用实验性功能),一起来学习一下1.伪元素::highlight()自定义任意文字样式需要CSS和JS的联合作用。先看CSS部分,新增一个伪元素,很简单::highlight(custom-highlight-name){color:red}类似于::selection这样的伪元素,只支持一些文本相关的样式,比如如下文字颜色颜色背景颜色背景颜色文字装饰文字装饰文字阴影文字阴影文字描边-webkit-文字-描边文字填充-webkit-文字-填充颜色注意注意注意不支持background-image,即不支持渐变之类的。然而,只知道这个伪类是没有用的。她还需要一个“参数”,就是上面的custom-highlight-name,表示高亮的名字,这是怎么来的?或者换句话说,如何识别页面上需要自定义样式的文本部分?这就需要借助下面的内容来看这个“参数”是如何生成的,这是重点2、介绍CSSCustomHighlightAPI之前,建议仔细阅读这篇文章:“cursor”和“cursor”在网页“选区”的大部分操作其实和这个原理是一样的,只是对得到的选区进行了进一步的处理,具体步骤如下:1、创建选区(关键点)首先,通过创建一个文本选区范围Range[2]对象,就像鼠标悬停在选择上一样,这也是最复杂的部分,例如constparentNode=document.getElementById("foo");constrange1=newRange();range1.setStart(parentNode,10);range1.setEnd(parentNode,20);常量范围2=新范围();range2.setStart(parentNode,40);range2.setEnd(parentNode,60);这样就可以得到选择对象range1,range22。创建高亮并实例化创建的选择高亮,需要用到Highlight[3]对象consthighlight=newHighlight(range1,range2,...);当然你也可以根据需要创建多个consthighlight1=new突出显示(user1Range1,user1Range2);consthighlight2=newHighlight(user2Range1,user2Range2,user2Range3);这样就可以得到高亮对象highlight1,highlight23。注册高亮接下来需要实例化高亮对象,通过[CSS.Highlight](HighlightRegistry-WebAPIs|MDN(mozilla.org"CSS.Highlight"))将高亮对象注册到页面中,有点类似于Map对象的操作CSS.highlights.set("highlight1",highlight1);CSS.highlights.set("highlight2",highlight2);目前兼容性比较差,需要额外判断if(CSS.highlights){//...supportCSS.highlights}注意,上面注册的keyname,highlight1就是上一节提到的高亮名称,也就是CSS中需要的“参数”4.自定义样式最后,结合定义的高亮名称::highlight,这样就可以自定义选中的样式::highlight(highlight1){背景颜色:黄色;color:black;}以上就是整个过程,有点复杂,但是还是比较容易理解的,关键是第一步创建选区的过程,这个过程是最复杂的,推荐阅读这篇文章再次仔细看:web中的“光标”和“选择区域”,这里用一张图来总结image-20230209193416579的原理,我们来看一些例子3.彩虹文字下面我们来实现开头的图标效果文章,彩虹文字效果一共有7种颜色,文字依次变色,循环往复,只有一个标签CSSCustomHighlightAPI

一共有7种这里的颜色,所以需要创建7个高亮区域,可以先定义高亮CSS,如下::highlight(rainbow-color-1){color:#ad26ad;文本修饰:下划线;}::highlight(rainbow-color-2){颜色:#5d0a99;文本修饰:下划线;}::highlight(rainbow-color-3){颜色:#0000ff;文本修饰:下划线;}::highlight(rainbow-color-4){颜色:#07c607;文本修饰:下划线;}::highlight(rainbow-color-5){颜色:#b3b308;文本修饰:下划线;}::highlight(rainbow-color-6){颜色:#ffa500;文本修饰:下划线;}::highlight(rainbow-color-7){颜色:#ff0000;文本修饰:下划线;}现在肯定不会有任何变化,因为选区image-20230209200130823还没有创建试试高亮区域,比如第一个文本consttextNode=document.getElementById("rainbow-text").firstChild;if(CSS.highlights){constrange=newRange();range.setStart(textNode,0);//选择范围的起点.setEnd(textNode,1);//选择结束点constHighlight=newHighlightt(范围);CSS.highlights.set(`rainbow-color-1`,Highlight);}效果如下image-20230209200616748循环创建7个高亮区域consttextNode=document.getElementById("rainbow-text").firstChild;if(CSS.highlights){consthighlights=[];for(leti=0;i<7;i++){//为每种颜色实例化一个Highlight对象constcolorHighlight=newHighlight();highlights.push(colorHighlight);//注册高亮CSS.highlights.set(`rainbow-color-${i+1}`,colorHighlight);}//遍历文本节点for(leti=0;iSearch

阅文旗下包括QQ阅读、起点中文网、新丽传媒等行业知名品牌。丰富的内容品类,触达数亿用户,成功输出《庆余年》《赘婿》《鬼吹灯》《全职高手》《斗罗大陆》《琅琊榜》等一大批优秀网络IP,改编成动漫、影视、游戏等多格式产品。

《盗墓笔记》原连载于起点中文网,是南派三叔成名的代表作。2015年,网剧开播首日点击量破亿,开启了盗墓文学IP化元年。该片于2016年上映,由井柏然、鹿晗、马思纯等主演,累计票房10亿元。

《庆余年》是阅文集团白金作家毛倪的作品。2007年起在起点中文网连载,一直位列历史类最爱前五名。剧本改编成为2019年的现象级作品,播出期间微博出现次数超过100次。腾讯视频和爱奇艺双平台总观看量超过160亿次。获得第26届白玉兰奖最佳编剧(改编)、最佳男配角两项大奖。

《鬼吹灯》是天下霸场创作的经典盗墓悬疑小说,在起点中文网连载。先后改编了漫画、游戏、电影、网络电视剧,均取得了不俗的成绩。是当之无愧的超级IP。

经过简单的美化,效果如下image-20230210143359875然后监听输入框,遍历文本节点(推荐使用原来的treeWalker,当然普通递归也是可以的),并根据搜索词创建选择区域,具体代码如下constquery=document.getElementById("query");constarticle=document.querySelector("article");//创建createTreeWalker迭代器,用于遍历文本节点并将它们保存到数组中consttreeWalker=document.createTreeWalker(article,NodeFilter.SHOW_TEXT);constallTextNodes=[];letcurrentNode=treeWalker.nextNode();while(currentNode){allTextNodes.push(currentNode);currentNode=treeWalker.nextNode();}//监听输入事件query.addEventListener("input",()=>{//检查是否支持CSS.highlightsif(!CSS.highlights){article.textContent="CSSCustomHighlightAPInotsupported.";return;}//清除最后的高亮CSS.highlights.clear();//清空判断conststr=query.value.trim().toLowerCase();if(!str){return;}//找出是否所有文本节点都包含搜索词constranges=allTextNodes.map((el)=>{return{el,text:el.textContent.toLowerCase()};}).map(({文本,el})=>{const索引=[];让startPos=0;while(startPos{constrange=newRange();range.setStart(el,index);range.setEnd(el,index+str.length);返回范围;});});//创建高亮对象constsearchResultsHighlight=newHighlight(...ranges.flat());//注册高亮CSS.highlights.set("search-results",searchResultsHighlight);});最后,通过CSS::highlight(search-results){background-color:#f06;设置高亮颜色白颜色;}实时搜索效果如下Kapture2023-02-10at14.51.51完整代码可在以下任一链接查看:(注意需要Chrome105+)CSS高亮搜索(juejin.cn)[7]CSS高亮搜索(codepen.io)[8]CSS高亮搜索(runjs.work)[9]也可以把高亮效果改成波浪线::highlight(search-results){text-decoration:underlinewavy#f06;}效果如下,是不是也可以当错字标记使用?image-20230210145628936除了可以避免dom操作带来的便利,性能也可以有很大的提升。毕竟,创建和删除dom也是一个大戏。以下是测试demo,移植自https://ffiori.github.io/highlight-api-demos/demo-performance.html[10]测试代码可在以下任意链接查看:高亮性能demo(juejin.cn)[11]高亮性能demo(codepen.io)[12]高亮性能demo(runjs.work)[13]测试结果如下image-20230210152018214在10000个节点的情况下,区别两者之间是100倍!而且数字越大,性能差距越明显,甚至直接导致浏览器卡顿!5.代码高亮编辑器最后来看一个非常实用的例子,可以轻松实现一个代码高亮编辑器假设HTML结构是这样的,很简单,就是一个纯文本标签ul{min-height:0;}.sub{display:grid;网格-模板行:0fr;过渡:0.3s;overflow:hidden;}:checked~.sub{grid-template-rows:1fr;}.txt{animation:color.001s.5linearforwards;}@keyframescolor{from{color:var(--c1)}to{color:var(--c2)}}简单修改一下,设置为可编辑元素。编辑器{空白:预包装;-webkit-user-modify:read-write-plaintext-only;/*读写明文*/}效果如下image-20230210191607226那么,如何让这些代码高亮呢?这就需要进行关键字分析和提取内容,我们可以使用已有的代码高亮库,如highlight.js[14]。hljs.highlight(pre.textContent,{language:'css'})._emitter.rootNode.children通过这个方法可以得到CSS语言的关键字和类型,如下图-20230210194630601简单说明一下,这个是一个数组,如果是纯文本表示普通字符,如果是对象表示关键字,比如第一个,children中的ul是关键字,类型是selector-tag,这是选择器。此外,还有属性、数字、选择器类等多种类型。有了这些关键字,我们就可以单独选择这些文本,然后用不同的颜色突出显示它们。接下来需要遍历代码内容,方法类似,如下constnodes=pre.firstChildconsttext=nodes.textContentconsthighlightMap={}letstartPos=0;words.filter(el=>el.scope)。forEach(el=>{conststr=el.children[0]constscope=el.scopeconstindex=text.indexOf(str,startPos);if(index<0){return}constitem={start:index,scope:scope,end:index+str.length,str:str}if(highlightMap[scope]){highlightMap[scope].push(item)}else{highlightMap[scope]=[item]}startPos=index+str}.length;})Object.entries(highlightMap).forEach(function([k,v]){constranges=v.map(({start,end})=>{constrange=newRange();范围。setStart(nodes,start);range.setEnd(nodes,end);返回范围;});consthighlight=newHighlight(...ranges.flat());CSS.highlights.set(k,highlight);})}highlights(code)code.addEventListener('input',function(){highlights(this)})最后根据不同的类型定义不同的颜色,如下::highlight(built_in){颜色:#c18401;}::highlight(评论){颜色:#a0a1a7;字体样式:斜体;}::highlight(number),::highlight(selector-class){颜色:#986801;}::highlight(attr){颜色:#986801;}::highlight(字符串){颜色:#50a14f;}::highlight(selector-pseudo){颜色:#986801;}::highlight(属性){颜色:#50a14f;}::highlight(关键字){颜色:#a626a4;}这样就得到了一个支持代码高亮的简单编辑器Lightweight,高亮时不会影响光标,因为不会生成新的dom,性能超棒