1

I am looking for a possible way, solely using CSS that could allow one to increment a CSS counter for every line of text within a DOM element.

This question is similar, but not the same as this SO question.

Using this as an example:

<p>Here is a basic "hello world" program, written in Rust:</p>
<code>
fn main() {
    println!("Hello, world!");
}
</code>

With white space preservation:

code {
    white-space: pre-wrap;
}

I am looking for a way that I could make this appear with a line number before each line of text (or just before each newline character).

1. | fn main() {
2. |    println!("Hello, world!");
3. | }

I was thinking that I could use pseudo-selectors, CSS counters, contents: , and a few other ideas, to make it happen, but I have no way to select each line.

I know that there are the ::first-letter and ::first-line pseudo-elements, but after looking everywhere I could find no mention of something like an nth-line(), or ::line selectors.

Does anyone know of any obscure CSS trick that could make this possible?

1 Answers1

2

If the number of lines will be limited, you can try something like below:

code {
    white-space: pre-wrap;
    position: relative;
    padding-left: 5ch; /* the space for the numbers */
    display: block;
    overflow: hidden; /* hide the non needed numbers */
    border: 1px solid;
}
code::before,
code::after {
  content: "1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14."; /* and so on*/
  position: absolute;
  width: 0; /* force a line break */
  top: 0;
  left: 0;
}

code::after {
  content: "| | | | | | | | | | | | | | | | | |"; /* and so on*/
  left: 3ch; /* a small offset to not overlap the numbers */
}
<p>Here is a basic "hello world" program, written in Rust:</p>
<code>
fn main() {
    println!("Hello, world!");
}
</code>
Another code block:
<code>
fn main() {
    let mut a = 0;
    let mut b = 2;

    println!("Hello, world!");

    for i in 0..5) {
        a += b;
    }

    println!("{}", a);
}
</code>
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
  • Whoa, that seems nice, but can you elaborate in the answer on how the numbers are all on the side, and how this actually works!? –  Nov 15 '20 at 22:11
  • @xxh the `width:0` is the trick. It will force a line break so each number is on a line then I simply position it on the left using absolute – Temani Afif Nov 15 '20 at 22:12
  • I'm going to definitely try this right away, I'll report back if anything weird happens. –  Nov 15 '20 at 22:14
  • You learn something new every day I guess; would've never thought of this. Nice job, thank you! –  Nov 15 '20 at 22:34
  • Doesn't work with line wrapping though. The wrapped lines still increment the counter. – geekley Dec 10 '20 at 21:27
  • @geekley *The wrapped lines still increment the counter* --> it's by design since we are using `white-space: pre-wrap`. It does work like expected – Temani Afif Dec 10 '20 at 21:29
  • Sure, but it's assuming you have lines that aren't too long in your code. If you have, it's worth warning that this solution wont work for people expecting normal line-wrap behavior, like you usually see in text editors. – geekley Dec 10 '20 at 21:33