Milk+ea

Weblog Is My Hobby.

CSSだけで要素に行番号を強引に付ける

f:id:totora0155:20140803073600p:plain

前からはてなブログなどの<pre>なんかで使いたいと思ってました。
結果、こんな感じで作れました。

See the Pen Line number by nju33 (@nju33) on CodePen.

詳しくは続きから。


<pre>では次のプロパティが重要です。
position: reltiveとすることで行番号を配置する基準位置を、この<pre>の左上に設定しています。
paddingでは行番号と重ならないに、左側に3emの余白を取っています。

.pre {
  /* 略 */
  position: relative;
  padding: 1em 1em 1em 3em;
}

行番号は、擬似要素:beforeを内側へ作成しそこへ記述します。 上で見せたCODEPENのモノはSassで書いていてちょっと違いますが、アレをCSSで書くとこうなります。

.pre:before {
  content: "  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20";
  display: block;
  height: 86%;
  width: 2em;
  position: absolute;
  left: 0;
  word-wrap: break-word;
  overflow: hidden;
}

まず、contentへ行番号となる数値の文字列を書きます。
width: 2emword-wrap: break-wordによってcontentを数値ごとに改行させて表示させます。
:beforeはインライン要素なのでそのままではwidthを設定できません。display: blockでブロック要素にします。

これで数値の文字列を縦に並ばすことができました。次に、適切な位置に配置させます。
position: absoluteleft: 0で、<pre>で設定した基準位置の一番左側へ行番号を配置します。

最後に、heightで行番号の高さを調整します。
今回のコードでは<pre>で下にpaddingをかけた結果、height: 100%では12行目まで表示されるようになってしまいました。「うわ、なんか下にだけ余白がない感じになってる・・・」ってことで、最後の一行分がはみ出るよう高さを調整。はみ出た行番号は、overflowで隠すことで下にもちゃんとpaddingが設定されてるようにできました。


CODEPENの例では、contentの文字列を書くのは面倒たったので、SassのMixinを使い作成しています。コレを使えば、999までは1~999まで手打ちするとかいう面倒なことはせずに済みます!(すんごい長いコードになりそうですが)

=line-number($num)
  $result: "  1"
  $pre: ""
  @for $i from 2 through $num
    $pre: ""
    @if $i < 10
      $pre: "  "
    @else if $i < 100
      $pre: " "
    $result: $result + "#{$pre}#{$i}"


  content: $result

// +line-number(20)

行間や色、背景色はお好みで設定です。