I want to show source code with line numbers, in such a way that:
I've tried the following approaches.
<style type="text/css">
ol.code > li {
white-space: pre-wrap;
}
</style>
...
<ol class="code">
<li>first line</li>
<li> indented line followed by empty line</li>
<li></li>
<li>the following line consists of one single space</li>
<li> </li>
<li>this line has a space at the end </li>
<li>	and one leading and ending tab	</li>
<li>fill to</li>
<li>ten</li>
<li>lines</li>
</ol>
This works for the most part, but when copying and pasting, the leading spaces and tabs in the lines are not copied in my browser (Iceweasel). So #1 fails with this approach.
<style type="text/css">
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) ". ";
width: 8em; /* doesn't work */
padding-left: auto; /* doesn't work */
margin-left: auto; /* doesn't work */
text-align: right; /* doesn't work */
}
</style>
...
<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>
This almost works, but #2 fails. It has an additional problem that wrapped lines continue under the line number (next to the left margin), not under the line start (tabulated).
This was a suggestion I found in https://www.sitepoint.com/best-practice-for-code-examples/ but it explicitly says that line wrapping must be disabled, therefore #3 fails. It also makes me very uneasy, as I've seen these blocks break in some sites.
Is there a way to do this without JavaScript?
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.
Add line numbers to a section or to multiple sectionsClick Line Numbering Options, and then click the Layout tab. In the Apply to list, click Selected sections. Click Line Numbers. Select the Add line numbering check box, and then select the options that you want.
For multi-line (“block”) code presentation, the most common approach is to use the <pre> element, and then put the <code> element inside that.
The <hr> tag defines a thematic break in an HTML page (e.g. a shift of topic). The <hr> element is most often displayed as a horizontal rule that is used to separate content (or define a change) in an HTML page.
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:
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"
});
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