Adding Line Numbers to HTML Code Blocks Using data- Attributes and CSS
Numbers of Lines
I've been using the CSS counter counter function to add line numbers to code
blocks forever. For example, this CSS:
fn main() {
println!("Hello World");
}
It works great for basic code blocks that start at 1 and go up uninterrupted from there.
Start Position
Starting with another number is done
with the counter-resetreset property. For
example, you can start the line numbers
at 7 like this:
fn main() {
println!("Hello World");
}
Just remember to reset the counter value to one before the value you want to start with (e.g. 6 gets you 7).
The Skipping Problem
The problem I've been running into is how to show some parts of the code while skipping others. For example, say I've got this code block coming in from an included file:
fn main() {
let alfa = "thing 1";
println!("{}", alfa);
let bravo = "thing 2";
println!("{}", alfa);
}
But, instead of displaying the entire thing, I
only want to show the opening and closing
of the main function and the alfa lines.
I could make another copy of the file
with the lines removed. That causes two issues:
- I'd have to duplicate the code. That, in turn requires updating it multiple times for any changes. A pain and entirely too easy to mess up and publish incorrect code.
- Lines that are removed don't increment the counter. Any lines after a removal end up with different numbers than the original.
For example, the closing } in this
display is marked as line 4 instead
of 7:
fn main() {
let alfa = "thing 1";
println!("{}", alfa);
}
I want to keep the numbers the same for each line:
fn main() {
let alfa = "thing 1";
println!("{}", alfa);
}
I could use the counter-reset approach to
set the line number after each removal. It would get
complicated fast. Each block would have
to be adjusted individually.
Solution Attributes
Enter the CSS attr()attr function. It's been
around since 2015 and provides a better
way to control line numbering. Specifically,
it lets you grab the value from a data-*
attribute in an HTML element for display.
Here's the code that makes it work:
And here's what it looks like:fn main() {
let alfa = "thing 1";
println!("{}", alfa);
}
The technique requires hard coding the values. The complexity of doing that will vary between systems. It's straight forward with my setupsetup.
The hard coding opens up other opportunities as well. Placing an empty line with a dot instead of a number to replace the skipped lines, for example. So, this:
Becomes this:fn main() {
let alfa = "thing 1";
println!("{}", alfa);
}
Exactly what I'm looking for.
-a
Endnotes
-
This page has an addition snippet of CSS to add a little padding between the line number and the content:
It's not shown to help focus on the counter lines themselves.
- The approach presupposes you have the ability to control that HTML for your code blocks. That is, you need a way to determine which lines show up and what the associated `data-num` attributes for each one are.
- I removed syntax highlighting from the HTML of the examples to make them easier to read. The technique works just as well when highlighting is applied.
Footnotes
-
counter CSS Counters let you add numbers to content without having to use JavaScript or hard coding the values.
-
reset The CSS counter-reset property starts or reset counters to a specific value.
-
attr The CSS attr() function retrieves the value of an attribute. The retrieved value can be displayed on the page with the content property in pseudo-elements.
-
setup I store my code snippets in external files. Doing so allows me to run them to make sure they do what I'm expecting. The snippets are passed through a syntax highlighter while including them on a page. The style classes for each set of tokens are included directly. The approach lets me add the hard coded lines numbers and filter the output to only show the lines I want for a given block.