I try to style a code pre box with line numbers in front of each line. I prefer to do it with CSS only. This is what I have done
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>>> 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>
However, all the lines have the number 1. The increment doesn't work. Here is a jsfiddle
We can use the built-in counter function in CSS in combination with counter-increment to add the line numbers. The counter function expects an arbitrary name that we define for counter-increment . This is going to add the content inside a ::before pseudo-element.
Why does the the counter not increment?
You are not resetting or creating the counter at the parent tag level. If you add the following line to the pre
selector, the code will work fine. When you don't create the counter (using a counter-reset
) at the parent level, each element would create its own counter and then increment it.
counter-reset: line;
When does a counter get created?
From the W3C Specs:
The counter-reset property creates new counters on an element.
The counter-set and counter-increment properties manipulate the value of existing counters. They only create new counters if there is no counter of the given name on the element yet.
In this case what happens is that we haven't created a counter by using the counter-reset
property and so the counter-increment
property in the span:before
pseudo-element selector would create a counter of the given name and increment it.
How does the counter get to know the current value?
Again from the W3C Specs:
If an element has a previous sibling, it must inherit all of the sibling’s counters. Otherwise, if the element has a parent, it must inherit all of the parent’s counters. Otherwise, the element must have an empty set of counters.
The element then inherits counter values from the immediately preceding element in document order.
Here since the counter is only created in the pseudo-element, its parent (the span
) is not aware of its creation and so the siblings of this span
doesn't inherit the counter. Since it doesn't even inherit any counter, it doesn't get the current value from the preceding element either.
Why does creating the counter on parent work?
When the counter is created at the pre
tag level, the counter is then passed on to each of its children elements (that is, each span
and in turn each span:before
would know about or inherit this counter) and now the increment statements in the span:before
would only increment the value of the counter which it received from the parent.
Now since each span
inherits the line
counter from its previous sibling, they will also inherit current value from the preceding element in the document order and thus it keeps going up from 1 to 2, 3 etc.
Why does using counter-increment on span or pre work?
As you've guessed, the counter-increment property creates a new counter when there is no existing counter and so adding counter-increment: line
on the span
will create a counter on the first span that is encountered. Now, since each sibling of the span
inherits this counter, it doesn't create a new one every time and rather just inherits the value from the preceding element. Thus this approach will work but it is always better to create the counter explicitly using a counter-reset
statement.
How is the browser support?
Browser support for CSS counters is unbelievably good. It is not a new thing in CSS and support for it is available even in IE8.
Demo:
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>>> 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> <span>lorem ipsum</span> <span>lorem ipsum</span> <span>lorem ipsum</span> </pre>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With