Posted at

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>