目次

highlight.jsに行番号を追加する方法

シンタックス・ハイライト・ライブラリhighlight.jsに簡単に行番号を追加する方法をご紹介します。自作プラグインで楽々実装


PREPARATION


想定する読者と前提条件

基本的なパソコン操作ができること。HTML及びJavaScriptの基礎程度の知識が必要です。


START


highlight.jsのとは?

highlight.jsは、ブログ等でプログラムコードを掲載する場合、予約語などのキーワードを 色分けし、視認性を高めるライブラリです。今回はこのライブラリに行番号を追加し視認性を向上させてみましょう。 最終的には以下のようなものを作成いたします。

2022年3月3日現在最新バージョン:11.4.0です。

<div class="row text-center mb-2 mt-5 justify-content-center">
<div class="col-8 col-md-4 mx-auto">
    <h2 class="cairo c-r h3 d-inline-block">
        <img decoding="async" class="ai" alt="" src="/img/ai/ai2.png"><br>
        COMPLATE</h2>
    <hr class=" ai-border">
</div>
</div>

highlight.jsの設置

下記公式サイトにアクセスし、最新の設置方法を確認してください。最も簡単な方法はcdnjsを利用します。

<link rel="stylesheet"
      href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.4.0/styles/default.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.4.0/highlight.min.js"></script>

highlightjs公式サイト

プラグインを作ろう!

ここでは、highlight.jsの機能拡張を行い、行番号を表示させてみましょう。 highlight.jsに機能を追加ためには、addPluginを利用することで、簡単なプラグインを作ることができます。プラグインの最も簡単な作り方は以下の通りです。

after:highlightBlockは非推奨となりました。after:highlightElementを使用してください。 result.valueでは書き換え不可になりました。el.innerHTMLを書き換える必要があります。

hljs.addPlugin( {
  'after:highlightElement': ({el, result}) => {
    //ここに処理を書く
    .... 
    }
});

プラグインの作り方

行番号追加機能を作ろう

ここからが本題です。プラグインの雛形がわかりましたが、resultやelといった値が何を 意味しているのか、知ることから始めましょう。

after:highlightElement({el, result})

after:highlightElementは、highlightjsによって整形が完了した後(画面に表示する前)に実行され、以下の3つのオブジェクトが渡されます。

el

強調表示を行うHTML要素(つまりcode要素)

result

highlightjsによって強調表示された結果オブジェクト

result.valueには、強調表示されたHTMLが格納されています。

整形後のHTMLを書き換える方法

elオブジェクトのinnerHTMLには、強調表示されたHTML要素がそのまま格納されています。 このinnerHTMLを書き換えることで、highlightjsによって強調表示されたHTMLの結果を変更することができます。

実際にel.innerHTMLどのような値が格納されているのか見てみましょう。キーワードがspan要素で囲まれ、1行1行の区切りは改行で表現されています。

    <span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">&quot;en&quot;</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">&quot;UTF-8&quot;</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;viewport&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;width=device-width, initial-scale=1.0&quot;</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Document<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;stylesheet&quot;</span>
    <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.4.0/styles/default.min.css&quot;</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.4.0/highlight.min.js&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span>hljs.initHighlightingOnLoad();<span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">pre</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">code</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;html&quot;</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">code</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">pre</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>

ここまで分かればやることは簡単ですね。各行の先頭に行番号を表示する要素(span)を追加すれば良いだけです。実際に作ってみましょう。

プラグインの完成


hljs.addPlugin({
    'after:highlightElement': ({ el, result}) => {
        el.innerHTML = result.value.replace(/^/gm,'<span class="row-number"></span>');
    }
});

行番号をCSSで表示しよう

各行の先頭に<span class="row-number">要素を追加していますので、 この要素に擬似要素を追加し行番号を表示させてみましょう。疑似要素で作成することで、行番号は文字選択から排除されます。 CSSで連番を振るには、countersを用いることで簡単に行えます。複数のコードを追加することも考え、pre要素でカウンターリセットも忘れずに!

pre{
    counter-reset: rowNumber;
}
pre span.row-number{
    counter-increment: rowNumber;
}
pre span.row-number::before { 
    content:counter(rowNumber);
    /* 以下少しだけ装飾 */
    width: 2rem;
    display: inline-block;
    color: #aaa;
}


QUESTION


  • このページの行番号表示も同様のコードで動いているわ。

    行番号の表示については、賛否があるでしょうけど、もし必要と感じたら表示してみて。

    avatar
  • avatar
    行番号が横スクロールで見えなくなるだが?

    横スクロールしても行番号を左に固定表示できるかい?

  • 簡単よ。

    CSSに少しだけ手を加えてみましょう。位置の調整と背景色は入れたほうがいいわね。

    avatar

行番号左固定バージョン

pre{
    counter-reset: rowNumber;
}
pre code{
    padding-left:2rem !important;/* 行番号表示用余白 */
}
pre span.row-number{
    counter-increment: rowNumber;
}
pre span.row-number::before { 
    content:counter(rowNumber);
    /* 以下少しだけ装飾 */
    width: 2rem;
    display: inline-block;
    color: #aaa;
    position:absolute;
    left:0; 
    padding-left:4px;/* 文字位置の調整 */
    background:#f0f0f0;/* 背景色は設定しましょう */
}


COMPLETE


  • avatar
    お疲れ様でした!

    今回はほんの少しのコードで行番号を追加してみました。外部プラグインなども不要で簡単に実装できましたね! コード量も少なく非常に経済的な実装になりました。

HTML全体

<!DOCTYPE html>
<html lang="ja-JP">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.4.0/styles/default.min.css">
    <script src="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.4.0/highlight.min.js"></script>
    <script>hljs.highlightAll();</script>
    <style>
        pre{
            counter-reset: rowNumber;
        }
        pre span.row-number{
            counter-increment: rowNumber;
            
        }
        pre span.row-number::before { 
            content:counter(rowNumber);
            width: 2rem;
            display: inline-block;
            color: #aaa;
        }
    </style>
</head>
<body>
<script>
    hljs.addPlugin({
        'after:highlightElement': ({ el, result }) => {
            el.innerHTML = result.value.replace(/^/gm,'<span class="row-number"></span>');
        }
    });
</script>
</body>
</html>


関連記事



コメント