仅使用 CSS 在 pre 上创建行号

问题描述 投票:0回答:5

我尝试在每行前面添加行号来设置代码预框的样式。我更喜欢只使用 CSS 来实现。这就是我所做的

pre {
  background: #303030;
  color: #f1f1f1;
  padding: 10px 16px;
  border-radius: 2px;
  border-top: 4px solid #00aeef;
  -moz-box-shadow: inset 0 0 10px #000;
  box-shadow: inset 0 0 10px #000;
}
pre span {
  display: block;
  line-height: 1.5rem;
}
pre span:before {
  counter-increment: line;
  content: counter(line);
  display: inline-block;
  border-right: 1px solid #ddd;
  padding: 0 .5em;
  margin-right: .5em;
  color: #888
}
<pre>
  <span>lorem ipsum</span>
  <span>&gt;&gt; lorem ipsum</span>
  <span>lorem ipsum,\ </span>
  <span>lorem ipsum.</span>
  <span>&gt;&gt; lorem ipsum</span>
  <span>lorem ipsum</span>
  <span>lorem ipsum</span>
  <span>lorem ipsum</span>
</pre>

但是,所有行的数字都是1。增量不起作用。这是一个jsfiddle

  1. 我做错了什么?
  2. 此纯 CSS 解决方案的浏览器兼容性如何?
html css css-counter
5个回答
98
投票

为什么计数器不增加?

您没有在父标签级别重置或创建计数器。如果将以下行添加到

pre
选择器,代码将正常工作。当您不在父级别创建计数器(使用
counter-reset
)时,每个元素都会创建自己的计数器,然后递增它。

counter-reset: line;

计数器何时创建?

来自 W3C 规范

计数器重置属性在元素上创建新计数器。

计数器设置和计数器增量属性操纵现有计数器的值。如果元素上还没有给定名称的计数器,它们仅创建新计数器

在这种情况下,我们没有使用

counter-reset
属性创建计数器,因此
counter-increment
伪元素选择器中的
span:before
属性将创建给定名称的计数器并递增它。


计数器如何得知当前值?

再次来自 W3C 规范

如果一个元素有一个前一个兄弟元素,它必须继承所有兄弟元素的计数器。否则,如果该元素有父元素,则它必须继承父元素的所有计数器。否则,该元素必须具有一组空的计数器。

该元素然后继承文档顺序中前一个元素的计数器值

这里,由于计数器仅在伪元素中创建,因此其父元素(

span
)不知道其创建,因此该
span
的兄弟元素不会继承计数器。由于它甚至不继承任何计数器,因此它也无法从前一个元素获取当前值。


为什么在父级上创建计数器有效?

当在

pre
标签级别创建计数器时,计数器会传递给其每个子元素(即,每个
span
以及每个
span:before
都会知道或继承此计数器)并且现在
span:before
中的增量语句只会增加从父级接收到的计数器的值。

现在,由于每个

span
都从其前一个兄弟继承了
line
计数器,因此它们还将继承文档顺序中前一个元素的当前值,因此它会不断从 1 增加到 2、3 等。


为什么在span或pre上使用反增量会起作用?

正如您所猜测的,当没有现有计数器时,计数器增量属性 会创建 一个新计数器,因此在

counter-increment: line
上添加
span
将在遇到的第一个跨度上创建一个计数器。现在,由于
span
的每个同级都继承了此计数器,因此它不会每次都创建一个新计数器,而只是继承前一个元素的值。因此,这种方法可行,但最好使用
counter-reset
语句显式创建计数器。


浏览器支持如何?

浏览器对 CSS 计数器的支持非常好。这在 CSS 中并不是什么新鲜事,甚至在 IE8 中也支持它


演示:

pre {
  background: #303030;
  color: #f1f1f1;
  padding: 10px 16px;
  border-radius: 2px;
  border-top: 4px solid #00aeef;
  -moz-box-shadow: inset 0 0 10px #000;
  box-shadow: inset 0 0 10px #000;
  counter-reset: line;
}
pre span {
  display: block;
  line-height: 1.5rem;
}
pre span:before {
  counter-increment: line;
  content: counter(line);
  display: inline-block;
  border-right: 1px solid #ddd;
  padding: 0 .5em;
  margin-right: .5em;
  color: #888
}
<pre><span>lorem ipsum</span>
<span>&gt;&gt; lorem ipsum</span>
<span>lorem ipsum,\ </span>
<span>lorem ipsum.</span>
<span>&gt;&gt; lorem ipsum</span>
<span>lorem ipsum</span>
<span>lorem ipsum</span>
<span>lorem ipsum</span>
<span>lorem ipsum</span>
<span>lorem ipsum</span>
<span>lorem ipsum</span>
<span>lorem ipsum</span>
</pre>


4
投票

您必须在跨度内增加

line

pre span {
    display: block;
    line-height: 1.5rem;
    counter-increment: line;
}

看看这个更新的jsfiddle


2
投票

您好,您需要重置先前/更高加载项目的计数器,请查看 https://jsfiddle.net/n2xkgt7s/2/

pre { counter-reset: line; }


2
投票

您可以考虑使用有序列表

<pre>
,而不是
<ol>
,它已经带有右对齐编号(当位数跳跃时更好,例如 9 -> 10)。
<li>
也不需要结束标签
</li>
https://html.spec.whatwg.org/multipage/syntax.html#optional-tags),这样可以节省打字时间。

ol {
  font-family: monospace;
  white-space: pre; 
}

li::marker {
  font-size: 10px;
  color: grey;
}
<ol><li>lorem ipsum      
<li>&gt;&gt; lorem ipsum
<li>lorem ipsum,\ 
<li>lorem ipsum.
<li>&gt;&gt; lorem ipsum
<li>lorem ipsum
<li>lorem ipsum
<li>lorem      
<li>ipsum
<li>&gt;&gt; lorem ipsum
<li>lorem ipsum
</ol> 

然而,

::marker
的造型似乎有限(
list-style-type
)。例如。删除句号或
vertical-align: super
似乎需要其他解决方法(回到
li:before
counter
)。


0
投票

受此启发,我制作了一个支持长行的版本。

.pre {
    font-size: 16px;
    font-family: monospace;
    background-color: #303030;
    color: #e6be49;
    padding: 15px 20px;
    border-radius: 3px;
    counter-reset: line;
    position: relative;
    line-height: 1.45;
    margin: 0 !important;

    &::after {
        content: "";
        position: absolute;
        top: 15px;
        bottom: 15px;
        left: 40px;
        border-right: 1px solid #5e5e5e;
    }

    span {
        display: block;
        counter-increment: line;
        padding-left: 35px;

        &::before {
            content: counter(line);
            display: inline-block;
            margin-left: -34px;
            margin-right: 25px;
            color: #a0a0a0;
        }
    }
}

Codepen:https://codepen.io/herrfischer/pen/zYXePdR

© www.soinside.com 2019 - 2024. All rights reserved.