马黑黑 发表于 2025-3-9 11:51

使用CSS counter 函数实现文本行号

<style>
        .artBox > p { margin: 8px 0; }
        .resBox { padding: 8px 0; cursor: pointer; }
        .artBox textarea { width: 600px;height: 200px; padding: 10px; tab-size: 4; }
        .resBox > p { counter-increment: idx; white-space: pre; tab-size: 4; position: relative; margin: 4px 0 4px 40px; }
        .resBox > p::before { content: counter(idx); position: absolute; left: -30px; color: #aaa; }
</style>

<div class="artBox">
        <p>先看效果:在文本框输入任意文本,两三行就可以,然后点击下方的文本按钮,文本框中的内容将在该处以带行号的显示显示出来。</p>
        <p><textarea id="txtbox" placeholder="请输入文字"></textarea></p>
        <div id="r1" class="resBox">点击查看效果</div>
        <p>这里,行号是使用基于CSS伪元素 counter 函数实现的,具体做法是,首先在指定类型元素比如 p 或 div 的CSS设置中指定一个自然递增的变量,然后在该类型元素的伪元素 ::before 或 ::after 的 content 属性中使用 counter 函数指向递增变量,写成 couter(变量) 。以下是参考代码:</p>
        <div id="hEdiv"><pre id="hEpre">
&lt;style&gt;
        /* 限定 class="mydiv" 的 p 标签带行号 */
        .mydiv &gt; p {
                counter-increment: idx; /* 计数器递增属性 : 通过变量名 idx 传递 */
                /* 以下是排版样式 */
                white-space: pre;
                tab-size: 4;
                position: relative;
                margin: 4px 0 4px 40px;
        }
        /* p选择器伪元素应用 counter 函数 */
        .mydiv &gt; p::before {
                content: counter(idx); /* 伪元素文本内容: 用 counter() 函数返回 idx 传值*/
                /* 以下是排版样式 */
                position: absolute;
                left: -30px;
                color: #aaa;
        }
&lt;/style&gt;

&lt;div class="mydiv"&gt;
        &lt;p&gt;我是第一行&lt;/p&gt;
        &lt;p&gt;我是第二行&lt;/p&gt;
&lt;/div&gt;
        </pre></div>
        <div id="r2" class="resBox">点击查看效果</div>
        <p>代码中CSS排版样式是为了让行号和正文区分开来,不然行号和正文是连接在一块儿的,具体行为是 ::before 在正文前、::after 在正文后。若仅仅是 counter(变量名) 的应用最简单的只需两三行代码,一是在指定元素用 counter-increment 属性指定传参变量,然后便是在对应的伪元素的 content 内容属性应用 counter(变量名) 实现计数器的输出。当然,CSS的 counter 函数可做的事情不止于此,它可以重置(counter-reset,比如从10开始)、设置输出内容和样式(counters(变量名, 字串, 样式)),细细打磨可以实现很多实用效果,感兴趣的朋友可以自行研究。</p>
</div>

<script type="module">
import hlight from 'https://638183.freep.cn/638183/web/helight/helight1.js';

function showRes() {
        if (!txtbox.value) return;
        let str = '';
        let ar = txtbox.value.replace(/</g,'&lt;').replace(/>/g,'&gt;').split('\n');
        ar.forEach(line => {
                str += '<p>' + line + '</p>';
        });
        r1.innerHTML = str;
};

hlight.hl(hEdiv, hEpre);
r1.onclick = () => showRes();
r2.onclick = () => r2.innerHTML = hEpre.textContent;
</script>

红影 发表于 2025-3-9 12:47

这个css的 counter 函数好,因为设置了white-space: pre;的缘故吧,所以能自动识别段落并加上序号{:4_187:}

红影 发表于 2025-3-9 12:49

“首先在指定类型元素比如 p 或 div 的CSS设置中指定一个自然递增的变量,然后在该类型元素的伪元素 ::before 或 ::after 的 content 属性中使用 counter 函数指向递增变量,写成 couter(变量) 。”
学习了。好像黑黑在多歌曲的那个帖子里就用过这个功能吧{:4_187:}

马黑黑 发表于 2025-3-9 13:33

红影 发表于 2025-3-9 12:47
这个css的 counter 函数好,因为设置了white-space: pre;的缘故吧,所以能自动识别段落并加上序号

段落都可以识别。之所以给显示行号的盒子加上 white-space 属性,主要是为了让该盒子能正常显示缩进(否则所有连续的空格、制表符会被压缩成一个空格),属性值选取 pre 或 pre-wrap 都可以,前者不换行,后者会换行,换行的还需要加入一个 word-break 属性设置连续字母数字的换行方式,值有break-all 等,break-all 表示需要折行时任何地方都可以折行。

马黑黑 发表于 2025-3-9 13:35

红影 发表于 2025-3-9 12:49
“首先在指定类型元素比如 p 或 div 的CSS设置中指定一个自然递增的变量,然后在该类型元素的伪元素 ::befo ...
不完全是,实际上是用到伪元素,但不是通过 counter 实现序号,而是伪元素 content 的另一个函数 attr(data-xxx) 来显示,HTML代码中对应标签需要配套提供 data-xxx="N" 来显示序号。

红影 发表于 2025-3-9 13:44

马黑黑 发表于 2025-3-9 13:33
段落都可以识别。之所以给显示行号的盒子加上 white-space 属性,主要是为了让该盒子能正常显示缩进(否 ...

这里面的细节还挺多的呢。{:4_187:}

红影 发表于 2025-3-9 13:45

马黑黑 发表于 2025-3-9 13:35
不完全是,实际上是用到伪元素,但不是通过 counter 实现序号,而是伪元素 content 的另一个函数 attr(da ...

嗯,我去看过那个多歌曲了,的确不是用这个函数加的序号。

马黑黑 发表于 2025-3-9 13:51

红影 发表于 2025-3-9 13:45
嗯,我去看过那个多歌曲了,的确不是用这个函数加的序号。

实现思路还是很多的

马黑黑 发表于 2025-3-9 13:51

红影 发表于 2025-3-9 13:44
这里面的细节还挺多的呢。

所以CSS要深入进去,也不是一件轻松的事情

杨帆 发表于 2025-3-9 14:02

长知识了,谢谢马老师的精彩科普,祝开心天天{:4_191:}

梦江南 发表于 2025-3-9 15:21

黑黑老师,我输入了三行文字,怎么没反应啊?是我的浏览器问题吗?

红影 发表于 2025-3-9 15:54

马黑黑 发表于 2025-3-9 13:51
实现思路还是很多的

都是从黑黑这里知道的呢{:4_187:}

红影 发表于 2025-3-9 15:54

马黑黑 发表于 2025-3-9 13:51
所以CSS要深入进去,也不是一件轻松的事情

是的,越来越觉得它的水也很深。

花飞飞 发表于 2025-3-9 16:55

马黑黑 发表于 2025-3-9 13:33
段落都可以识别。之所以给显示行号的盒子加上 white-space 属性,主要是为了让该盒子能正常显示缩进(否 ...

难怪,我开始复制了一段文字和长代码进去,都是一行排下来。。。
看你这回复如果换成pre-wrap 就会换行了。{:4_170:}
还是要换行的好{:4_173:}

花飞飞 发表于 2025-3-9 16:58

还有这函数命令好厉害啊,
如果去掉那排版样式
.mydiv > p {counter-increment: idx; }
.mydiv > p::before {content: counter(idx); }
这两行就解决问题了{:4_173:}
谁发现的这么好用的咒语。。。

马黑黑 发表于 2025-3-9 18:31

花飞飞 发表于 2025-3-9 16:58
还有这函数命令好厉害啊,
如果去掉那排版样式
.mydiv > p {counter-increment: idx; }


这其实就是伪元素,伪元素要用 content 表示它的内容是什么:

content: ''; /* 空内容,通常用来配套显示伪元素美丽的界面 */
content: url(图片地址); /* 显示图片的URL函数 */
content: attr(data-xxx); /* 显示标签提供的 data-xxx="啥啥啥",LRC歌词同步就用这个函数 */
content: counter(变量名); /* counter函数的变量名要做宿主元素用 counter-increment 属性指明 */

马黑黑 发表于 2025-3-9 18:34

花飞飞 发表于 2025-3-9 16:55
难怪,我开始复制了一段文字和长代码进去,都是一行排下来。。。
看你这回复如果换成pre-wrap 就会换行 ...

像鼎鼎有名的女程序员写的 prism.js 就不支持代码换行,可能的原因是换行后她的程序行号就和代码对不上,一行代码一个行号是事先设定好的,所以都用了 pre 属性值。

我的着色机制则可以折行,不影响序号的整体排版。

马黑黑 发表于 2025-3-9 18:38

红影 发表于 2025-3-9 15:54
是的,越来越觉得它的水也很深。

将来CSS的编程特性会越发突显

马黑黑 发表于 2025-3-9 18:38

红影 发表于 2025-3-9 15:54
都是从黑黑这里知道的呢

多尝试自己也能弄出来

红影 发表于 2025-3-9 19:39

马黑黑 发表于 2025-3-9 18:38
将来CSS的编程特性会越发突显

要是能兼并JS岂不更厉害了{:4_173:}
页: [1] 2 3 4 5
查看完整版本: 使用CSS counter 函数实现文本行号