马黑黑 发表于 2024-6-16 10:11

不改变文档结构实时渲染彩虹字

本帖最后由 马黑黑 于 2024-6-16 12:18 编辑 <br /><br /><style>
        #t7 { margin: 20px auto; padding: 10px; width: 740px; height: 360px; font-size: 20px; background: white; -webkit-user-modify: read-write-plaintext-only; border: 1px solid lightblue; border-radius: 3px; outline-width: 4px; outline-color: cornflowerblue; }
        #h7 { text-align: center; font-size: 2em; }
        .mum { position: relative; margin: 0; padding: 10px; font: normal 16px/20px Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; color: black; background: rgba(240, 240, 240,.95); box-shadow: 2px 2px 4px gray; border: thick groove lightblue; border-radius: 6px; }
.mum ::selection { background-color: rgba(0,100,100,.35); }
.mum div { margin: 0; padding: 0; }
.mum cl-cd { display: block; position: relative; margin: 0 0 0 50px; padding: 0 0 0 10px; white-space: pre-wrap; overflow-wrap: break-word; border-left: 1px solid silver; }
.mum cl-cd::before { position: absolute; content: attr(data-idx); width: 50px; color: gray; text-align: right; transform: translate(-70px); }
.tRed { color: red; }
.tBlue { color: blue; }
.tGreen { color: green; }
.tDarkRed { color: darkred; }
.tMagenta { color: magenta; }
</style>

<h2 id="h7">CSS+JS原生文本高亮API测试</h2>
<div id="t7"></div>
<p>代码:<br><br></p>
<div class='mum'>
<cl-cd data-idx="1">&lt;<span class="tDarkRed">style</span>&gt;</cl-cd>
<cl-cd data-idx="2">&nbsp; &nbsp; #t7 { <span class="tBlue">margin:</span> 20px auto; <span class="tBlue">padding:</span> 10px; <span class="tBlue">width:</span> 800px; <span class="tBlue">height:</span> 400px; <span class="tBlue">font-size:</span> 20px; <span class="tBlue">-webkit-user-modify:</span> read-write-plaintext-only; <span class="tBlue">border:</span> 1px solid lightblue; <span class="tBlue">border-radius:</span> 3px; <span class="tBlue">outline-width:</span> 4px; <span class="tBlue">outline-color:</span> cornflowerblue; }</cl-cd>
<cl-cd data-idx="3">&nbsp; &nbsp; #h7 { <span class="tBlue">text-align:</span> center; }</cl-cd>
<cl-cd data-idx="4">&lt;<span class="tDarkRed">/style</span>&gt;</cl-cd>
<cl-cd data-idx="5">&nbsp;</cl-cd>
<cl-cd data-idx="6">&lt;<span class="tDarkRed">h</span>2 <span class="tRed">id</span>=<span class="tMagenta">"h7"</span>&gt;CSS+JS原生文本高亮API测试&lt;<span class="tDarkRed">/h</span>2&gt;</cl-cd>
<cl-cd data-idx="7">&lt;<span class="tDarkRed">div</span> <span class="tRed">id</span>=<span class="tMagenta">"t7"</span>&gt;&lt;<span class="tDarkRed">/div</span>&gt;</cl-cd>
<cl-cd data-idx="8">&nbsp;</cl-cd>
<cl-cd data-idx="9">&lt;<span class="tDarkRed">script</span>&gt;</cl-cd>
<cl-cd data-idx="10">&nbsp;</cl-cd>
<cl-cd data-idx="11"><span class="tBlue">const</span> highlights = [];</cl-cd>
<cl-cd data-idx="12"><span class="tBlue">const</span> addStyleSheet = () =&gt; {</cl-cd>
<cl-cd data-idx="13">&nbsp; &nbsp; <span class="tBlue">const</span> colors = [<span class="tMagenta">'#ad26ad'</span>, <span class="tMagenta">'#5d0a99'</span>,<span class="tMagenta">'#0000ff'</span>,<span class="tMagenta">' #07c607'</span>, <span class="tMagenta">'#b3b308'</span>, <span class="tMagenta">'#ffa500'</span>, <span class="tMagenta">'#ff0000'</span>];</cl-cd>
<cl-cd data-idx="14">&nbsp; &nbsp; <span class="tBlue">const</span> hstr = colors.map((c,k) =&gt; `::highlight(rainbow-color-${k+1}) {<span class="tBlue">color:</span> ${c}; <span class="tBlue">text-decoration:</span> underline; }`).join(<span class="tMagenta">'\n'</span>);</cl-cd>
<cl-cd data-idx="15">&nbsp; &nbsp; <span class="tBlue">var</span> style = <span class="tRed">document</span>.createElement(<span class="tMagenta">'style'</span>);</cl-cd>
<cl-cd data-idx="16">&nbsp; &nbsp; style.type = <span class="tMagenta">'text/css'</span>;</cl-cd>
<cl-cd data-idx="17">&nbsp; &nbsp; style.innerHTML = hstr;</cl-cd>
<cl-cd data-idx="18">&nbsp; &nbsp; <span class="tRed">document</span>.body.appendChild(style);</cl-cd>
<cl-cd data-idx="19">&nbsp;</cl-cd>
<cl-cd data-idx="20">&nbsp; &nbsp; <span class="tBlue">for</span> (<span class="tBlue">let</span> i = 0; i &lt; 7; i++) {</cl-cd>
<cl-cd data-idx="21">&nbsp; &nbsp; &nbsp; &nbsp; <span class="tBlue">const</span> colorHighlight = <span class="tBlue">new</span> Highlight();</cl-cd>
<cl-cd data-idx="22">&nbsp; &nbsp; &nbsp; &nbsp; highlights.push(colorHighlight);</cl-cd>
<cl-cd data-idx="23">&nbsp; &nbsp; &nbsp; &nbsp; CSS.highlights.set(`rainbow-color-${i + 1}`, colorHighlight);</cl-cd>
<cl-cd data-idx="24">&nbsp; &nbsp; }</cl-cd>
<cl-cd data-idx="25">};</cl-cd>
<cl-cd data-idx="26">&nbsp;</cl-cd>
<cl-cd data-idx="27"><span class="tBlue">const</span> hlight = (ele) =&gt; {</cl-cd>
<cl-cd data-idx="28">&nbsp; &nbsp; <span class="tBlue">const</span> walker = <span class="tRed">document</span>.createTreeWalker(ele, NodeFilter.SHOW_TEXT);</cl-cd>
<cl-cd data-idx="29">&nbsp; &nbsp; <span class="tBlue">while</span>(walker.nextNode()) {</cl-cd>
<cl-cd data-idx="30">&nbsp; &nbsp; &nbsp; &nbsp; <span class="tBlue">let</span> textNode = walker.currentNode;</cl-cd>
<cl-cd data-idx="31">&nbsp; &nbsp; &nbsp; &nbsp; <span class="tBlue">let</span> text = textNode.textContent;</cl-cd>
<cl-cd data-idx="32">&nbsp; &nbsp; &nbsp; &nbsp; <span class="tBlue">for</span>(<span class="tBlue">let</span> i = 0; i &lt; text.length; i++) {</cl-cd>
<cl-cd data-idx="33">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="tBlue">const</span> range = <span class="tBlue">new</span> Range();</cl-cd>
<cl-cd data-idx="34">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; range.setStart(textNode, i);</cl-cd>
<cl-cd data-idx="35">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; range.setEnd(textNode, i + 1);</cl-cd>
<cl-cd data-idx="36">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; highlights[(i % 7)].add(range);</cl-cd>
<cl-cd data-idx="37">&nbsp; &nbsp; &nbsp; &nbsp; }</cl-cd>
<cl-cd data-idx="38">&nbsp; &nbsp; }</cl-cd>
<cl-cd data-idx="39">};</cl-cd>
<cl-cd data-idx="40">&nbsp;</cl-cd>
<cl-cd data-idx="41"><span class="tBlue">if</span> (CSS.highlights) {</cl-cd>
<cl-cd data-idx="42">&nbsp; &nbsp; t7.textContent = <span class="tMagenta">'恭喜恭喜!您的浏览器完美支持CSS Custom Highlight API'</span>;</cl-cd>
<cl-cd data-idx="43">&nbsp; &nbsp; addStyleSheet();</cl-cd>
<cl-cd data-idx="44">&nbsp; &nbsp; hlight(h7);</cl-cd>
<cl-cd data-idx="45">&nbsp; &nbsp; hlight(t7);</cl-cd>
<cl-cd data-idx="46">&nbsp; &nbsp; t7.oninput = () =&gt; hlight(t7);</cl-cd>
<cl-cd data-idx="47">} <span class="tBlue">else</span> {</cl-cd>
<cl-cd data-idx="48">&nbsp; &nbsp; t7.textContent = <span class="tMagenta">'非常遗憾!您的浏览器不支持CSS Custom Highlight API'</span></cl-cd>
<cl-cd data-idx="49">}</cl-cd>
<cl-cd data-idx="50">&nbsp;</cl-cd>
<cl-cd data-idx="51">&lt;<span class="tDarkRed">/script</span>&gt;</cl-cd>
</div>

<script>
(function() {
const highlights = [];
const addStyleSheet = () => {
        const colors = ['#ad26ad', '#5d0a99','#0000ff',' #07c607', '#b3b308', '#ffa500', '#ff0000'];
        const hstr = colors.map((c,k) => `::highlight(rainbow-color-${k+1}) {color: ${c}; text-decoration: underline; }`).join('\n');
        var style = document.createElement('style');
        style.type = 'text/css';
        style.innerHTML = hstr;
        document.body.appendChild(style);

        for (let i = 0; i < 7; i++) {
                const colorHighlight = new Highlight();
                highlights.push(colorHighlight);
                CSS.highlights.set(`rainbow-color-${i + 1}`, colorHighlight);
        }
};

const hlight = (ele) => {
        const walker = document.createTreeWalker(ele, NodeFilter.SHOW_TEXT);
        while(walker.nextNode()) {
                let textNode = walker.currentNode;
                let text = textNode.textContent;
                for(let i = 0; i < text.length; i++) {
                        const range = new Range();
                        range.setStart(textNode, i);
                        range.setEnd(textNode, i + 1);
                        highlights[(i % 7)].add(range);
                }
        }
};

if (CSS.highlights) {
        t7.textContent = '恭喜恭喜!您的浏览器完美支持CSS Custom Highlight API';
        addStyleSheet();
        hlight(h7);
        hlight(t7);
        t7.oninput = () => hlight(t7);
} else {
        t7.textContent = '非常遗憾!您的浏览器不支持CSS Custom Highlight API'
}
})();
</script>

马黑黑 发表于 2024-6-16 10:27

本帖最后由 马黑黑 于 2024-6-16 12:22 编辑

如果浏览器支持新的文本高亮渲染方式,一楼的测试中,彩虹字文本框可以输入文本,新输入的文本一样是彩虹的。

CSS Custom Highlight API 是个较新的标准接口,它提供一种全新理念的文本高亮特效,不改变文档树的结构,仅需事先定义好一组伪元素 ::highlight(名称)、再通过JS建立和注册文本高亮设定,便可对特定文本进行高亮渲染。目前火狐浏览器(Firefox)还没有能够实现该功能,其他现代浏览器新版本均已支持。

使用 CSS Custom Highlight API 有点繁琐,它需要一系列的配套操作,包含但不限于CSS的设置、创建高亮并在页面中注册、遍历文本节点、创建选区等等操作。

马黑黑 发表于 2024-6-16 10:34

传统的文本着色实现方法,都是以改变文档结构的方式完成,例如下面的文字:

    花潮论坛

花潮两字都上彩,实现手段类似于:

<span style="color: red">花</span><span style="magenta">潮</span>论坛

文本节点中加入了两 span 元素节点,通过改变文档结构来实现给文本着色。

而 CSS Custom Highlight API 无需这么做,所以渲染性能提升100倍不止。

马黑黑 发表于 2024-6-16 11:15

::highlight() 伪元素支持的CSS属性有;

color
background-color
text-decoration 及其相关属性
text-shadow
-webkit-text-stroke-color、-webkit-text-fill-color 和 -webkit-text-stroke-width

马黑黑 发表于 2024-6-16 11:24

CSS Custom Highlight API 实现流程:

一、定义伪元素 ::highligh(custom-name) 样式
二、创建选区
三、创建高亮
四、注册高亮(到 custom-name 样式 )

其中,创建选区要遍历文档节点,找出要高亮的所有文本节点,而后一一为其创建高亮并注册(指定高亮样式)。

红影 发表于 2024-6-16 11:41

去试过了,首层的文本框里可以输入问题,一边输入一边就看到了颜色的变化,真神奇{:4_187:}

红影 发表于 2024-6-16 11:41

感谢黑黑又带来了好东西新东西{:4_199:}

南无月 发表于 2024-6-16 11:42

火狐不行,非常遗憾!您的浏览器不支持CSS Custom Highlight API
别的行。。恭喜恭喜!您的浏览器完美支持CSS Custom Highlight API

火狐落后了啊。。

马黑黑 发表于 2024-6-16 12:15

南无月 发表于 2024-6-16 11:42
火狐不行,非常遗憾!您的浏览器不支持CSS Custom Highlight API
别的行。。恭喜恭喜!您的浏览器完美支持 ...

火狐对 ::highlight() 伪元素的支持是局部支持,而对API完全没有支持。继续等待。

马黑黑 发表于 2024-6-16 12:16

红影 发表于 2024-6-16 11:41
感谢黑黑又带来了好东西新东西

这个很新,Chrome 从 105 版本才开始支持

马黑黑 发表于 2024-6-16 12:17

红影 发表于 2024-6-16 11:41
去试过了,首层的文本框里可以输入问题,一边输入一边就看到了颜色的变化,真神奇

这是w3c推出的新理念,非常先进

南无月 发表于 2024-6-16 17:51

马黑黑 发表于 2024-6-16 12:15
火狐对 ::highlight() 伪元素的支持是局部支持,而对API完全没有支持。继续等待。

好哒,这个挺稀罕的。。{:4_173:}觉得火狐还挺先进的,怎么这块却没跟上

红影 发表于 2024-6-16 22:04

马黑黑 发表于 2024-6-16 12:16
这个很新,Chrome 从 105 版本才开始支持

真是好东西啊,黑黑带来的好东西走在了最前列了{:4_199:}

红影 发表于 2024-6-16 22:05

马黑黑 发表于 2024-6-16 12:17
这是w3c推出的新理念,非常先进

非常神奇的体验,这个太棒了{:4_187:}

马黑黑 发表于 2024-6-16 22:15

红影 发表于 2024-6-16 22:05
非常神奇的体验,这个太棒了

彩虹字过去早就有的,只是现在这个API,确实令人惊叹

马黑黑 发表于 2024-6-16 22:16

红影 发表于 2024-6-16 22:04
真是好东西啊,黑黑带来的好东西走在了最前列了

还好吧。对这个的介绍,多少有点犹豫,主要是考虑它的兼容性方面

红影 发表于 2024-6-17 17:42

马黑黑 发表于 2024-6-16 22:15
彩虹字过去早就有的,只是现在这个API,确实令人惊叹

是的,它的七彩色非常漂亮{:4_187:}

红影 发表于 2024-6-17 17:45

马黑黑 发表于 2024-6-16 22:16
还好吧。对这个的介绍,多少有点犹豫,主要是考虑它的兼容性方面

还好,应该大多数人的浏览器都没问题的。

马黑黑 发表于 2024-6-17 18:23

红影 发表于 2024-6-17 17:45
还好,应该大多数人的浏览器都没问题的。

不见得的额。很多人都不升级浏览器,包括不少玩音画代码的。

马黑黑 发表于 2024-6-17 18:24

红影 发表于 2024-6-17 17:42
是的,它的七彩色非常漂亮

不错
页: [1] 2 3 4
查看完整版本: 不改变文档结构实时渲染彩虹字