html: How to add line numbers to a source code block
You need to add display: inline-block
to your ::before
pseudo-element:
eg.
pre.code code::before {
content: counter(listing) ". ";
display: inline-block;
width: 8em;
padding-left: auto;
margin-left: auto;
text-align: right;
}
Then all your other styles will work.
Explanation: By default, ::before
and ::after
pseudo-elements have a display
style of inline
.
You need to explicitly declare a display
style of block
or inline-block
if you want to start setting width
, text-align
etc.
Example:
pre.code {
white-space: pre-wrap;
}
pre.code::before {
counter-reset: listing;
}
pre.code code {
counter-increment: listing;
}
pre.code code::before {
content: counter(listing) ". ";
display: inline-block;
width: 8em; /* now works */
padding-left: auto; /* now works */
margin-left: auto; /* now works */
text-align: right; /* now works */
}
<pre class="code">
<code>first line</code>
<code> indented line followed by empty line</code>
<code></code>
<code>the following line consists of one single space</code>
<code> </code>
<code>this line has a space at the end </code>
<code>	and one leading and ending tab	</code>
<code>fill to</code>
<code>ten</code>
<code>lines</code>
</pre>
Added: An alternative CSS approach using floats
and clears
which means that when lines wrap, they do not wrap underneath the line number:
pre.code {
white-space: pre-wrap;
margin-left: 8em;
}
pre.code::before {
counter-reset: listing;
}
pre.code code {
counter-increment: listing;
text-align: left;
float: left;
clear: left;
}
pre.code code::before {
content: counter(listing) ". ";
display: inline-block;
float: left;
height: 3em;
padding-left: auto;
margin-left: auto;
text-align: right;
}
While technically my question is already answered by Rounin (thanks), truth is I was not fully satisfied with the result, because I didn't state a couple other requisites that I felt were important after posting the question, and they fail with that solution:
- When a line wraps around, it should go underneath the above line, not underneath the line numbers.
- Both the numbers and the text columns should be style-able (notably, the background of the whole column should be easily changeable).
I tried a solution with another inline-block
, but it failed #5, and had problems with adjusting to any width.
<OL>
was quite close, but not quite there. An alternative to <OL>
that I knew wouldn't fly was to use a table. It wouldn't fly, because the browser needs a <PRE>
element in order to copy/paste spaces and tabs properly.
Then all of a sudden, a solution clicked in my head. Forcing an element that is not a table to behave as if it was a table, is the exact purpose of the table-xxxx
display values!
So here we go. Tested in Iceweasel 24.7.0 and Chromium 35.0.1916.153. The demo includes extra styling as an example of the versatility of the method.
The CSS:
/* Bare bones style for the desired effect */
pre.code {
display: table;
table-layout: fixed;
width: 100%; /* anything but auto, otherwise fixed layout not guaranteed */
white-space: pre-wrap;
}
pre.code::before {
counter-reset: linenum;
}
pre.code span.tr {
display: table-row;
counter-increment: linenum;
}
pre.code span.th { /* used for line numbers */
display: table-cell;
user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
}
pre.code span.th::before {
content: counter(linenum);
text-align: right;
display: block;
}
pre.code span.th {
width: 4em; /* or whatever the desired width of the numbers column is */
}
pre.code code {
display: table-cell;
}
And the HTML:
<pre class="code">
<span class="tr first-row"><span class="th"></span><code> indented line</code></span>
<span class="tr"><span class="th"></span><code>unindented line</code></span>
<span class="tr"><span class="th"></span><code>	line starting and ending with tab	</code></span>
<span class="tr"><span class="th"></span><code></code></span>
<span class="tr"><span class="th"></span><code>the above line should be empty</code></span>
<span class="tr"><span class="th"></span><code>overlong line that wraps around or so I hope because it's really long and should overflow the right sided margin of the web page in your browser</code></span>
<span class="tr"><span class="th"></span><code>fill up to ten</code></span>
<span class="tr"><span class="th"></span><code>lines to check</code></span>
<span class="tr"><span class="th"></span><code>alignment</code></span>
<span class="tr"><span class="th"></span><code>of numbers</code></span>
</pre>
Demo with extra styling
Update: Since I posted the question, learned that the GeSHi syntax highlighter has an option to use the following schema, which also meets all requisites and may be more acceptable to those that are allergic to tables:
<ol>
<li><pre>code</pre></li>
<li><pre>code</pre></li>
<li><pre>...</pre></li>
</ol>
I'd recommend using codemirror to do this instead of writing it yourself.
You get the functionality you describe for free and lots of other great stuff:
https://codemirror.net/doc/manual.html#usage
CodeMirror.fromTextArea(document.getElementById("myDiv"), {
lineNumbers: true,
mode: "htmlmixed"
});