CSS
CSS3

CSSでコードブロックの行番号を表示する

More than 1 year has passed since last update.

Qiita APIから取得した投稿内容を自分のサイトに表示するときコードブロックに行番号を表示させたかったので、JavaScriptを使わず実装する方法を考えた。

APIで取得した内容の一部
<div class="code-frame" data-lang="JavaScript">
<div class="code-lang"><span class="bold">app.js</span></div>
<div class="highlight"><pre><span></span>  <span class="k">for</span><span class="p">(</span><span class="kd">let</span> <span class="nx">url</span> <span class="k">of</span> <span class="nx">urls</span><span class="p">){</span>
    <span class="nx">await</span> <span class="nx">chromy</span><span class="p">.</span><span class="kr">goto</span><span class="p">(</span><span class="nx">url</span><span class="p">)</span>
<span class="line-numbers-rows"><span></span><span></span></span></pre></div>
</div>

目標

  • pre要素の左側に行番号を表示
  • コードをコピーする時に邪魔にならない
  • できればJavaScriptは使いたくない

イメージは下記URLの通り。
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Lists_and_Counters/Using_CSS_counters

実装方法

HTML

HTML
<pre>
    # 1行目
    # 2行目
    # 3行目
    <div class="line-numbers"><span></span><span></span><span></span></div>
</pre>

pre要素の中なので改行や空白がそのまま表示されるので注意。
<div class="line-numbers">内に行数分だけ<span></span>を設置する。あまりスマートでは無いのでJavaScriptかテンプレートエンジンで行数分ループするのがよさそう

Pythonだとこんな感じ
print('<div class="line-numbers">'+'<span></span>'*3+'<div>')

CSS

CSS
pre {
    position: relative;
    padding: 20px 50px;
}

.line-numbers {
    position: absolute;
    top: 0;
    left: 0;
    padding: 20px 5px;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    border-right: 1px solid #999;
    width: 50px;
}

.line-numbers > span {
    float: left;
    display: block;
    counter-increment: linenumber;
    text-align: right;
    width: 100%;
}

.line-numbers > span::after {
    content: counter(linenumber);
}

JavaScriptを使わずに行番号を加算していくのにCSS countersを使って実装した。
counter-increment: linenumber;でlinenumber変数を加算して疑似要素の::afterの中にcontent: counter(linenumber);で表示させる。

表示結果

コード全体

index.html
<html>
<body>


<pre>
    <span># 1行目</span>
    <span># 2行目</span>
    <span># 3行目</span>
    <div class="line-numbers"><span></span><span></span><span></span></div>
</pre>


<style>
body{
    margin:50px;
    background:#ddd;
}
pre {
    position: relative;
    padding: 20px 50px;
}

.line-numbers {
    position: absolute;
    top: 0;
    left: 0;
    padding: 20px 5px;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    border-right: 1px solid #999;
    width: 50px;
}

.line-numbers > span {
    float: left;
    display: block;
    counter-increment: linenumber;
    text-align: right;
    width: 100%;
}

.line-numbers > span::after {
    content: counter(linenumber);
}
</style>


</body>
</html>