【highlight.js】シンタックスハイライトの導入と設定方法まとめ

【highlight.js】シンタックスハイライトの導入と設定方法まとめ JavaScript

highlight.js は、コードブロックに自動で色付けを行う軽量なライブラリです。CDN から 1 ファイル読み込むだけでも動作し、必要に応じて言語の個別読み込みやテーマ切り替え、行番号の付与などを柔軟にカスタマイズできます。ここでは導入から実運用で使う初期化方法、テーマ変更、パフォーマンスやアクセシビリティの配慮までを一通りまとめます。

最短導入(CDN)で今すぐハイライトする

HTML に CSS と JS を読み込み、ページ読み込み時に自動初期化を有効化します。コードブロックは <pre><code> で囲み、言語クラスを付けるか自動判定に任せます。

<!-- テーマ(スタイル) -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.min.css">

<!-- 本体 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>

<!-- 自動初期化 -->
<script>hljs.highlightAll();</script>

<!-- 例:言語を明示したコードブロック -->
<pre><code class="language-javascript">
const hello = (name) => console.log(`Hello, ${name}`);
hello('world');
</code></pre>

言語の個別読み込みで軽量化する

すべての言語を含むビルドは簡単ですがファイルサイズが大きくなります。対象言語が限られる場合は本体に加えて必要な言語のみ追加読み込みします。

<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/javascript.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/php.min.js"></script>
<script>hljs.highlightAll();</script>

自動判定を使う場合でも、判定候補に読み込まれていない言語は対象になりません。サイトの投稿内容に合わせて最小構成にすると描画が速くなります。

npm で導入してビルドに組み込む

フロントエンドのビルド環境に統合する場合は npm を使います。必要言語だけを登録し、テーマ CSS もパッケージから読み込みます。

npm i highlight.js
// main.js
import hljs from 'highlight.js/lib/core';
import javascript from 'highlight.js/lib/languages/javascript';
import php from 'highlight.js/lib/languages/php';
import 'highlight.js/styles/github.css';

hljs.registerLanguage('javascript', javascript);
hljs.registerLanguage('php', php);
hljs.highlightAll();

言語指定と自動判定の使い分け

クラスで言語を指定すれば誤判定を防げます。複数言語が混在する記事では明示を基本にし、未指定のコードだけ自動判定に任せる構成が安定します。

<pre><code class="language-css">
.button{ background:#0aa; color:#fff; }
</code></pre>

テーマの切り替えとダークモード対応

highlight.js は多数のテーマを同梱しています。OS のダークモードに合わせて自動切り替えしたい場合は prefers-color-scheme を使います。

<link id="hl-theme" rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.min.css">
<link rel="stylesheet" media="(prefers-color-scheme: dark)"
      href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css">

手動でトグルするならリンク要素の href を差し替えれば即時反映されます。

行番号を付けたいときの実装例

highlight.js 本体には行番号機能は含まれていないため、軽量な CSS だけで擬似的に行番号を付与する方法を示します。生成系プラグインを使わず、連番は CSS のカウンタで描画します。

pre.hljs {
  position: relative;
  padding-left: 3.5em;
  counter-reset: ln;
}
pre.hljs code { display: block; }
pre.hljs code span { counter-increment: ln; display: block; }
pre.hljs code span::before {
  content: counter(ln);
  position: absolute;
  left: 0.8em;
  color: #9aa;
  width: 2.2em;
  text-align: right;
}
// 各行を <span> でラップして行番号を出す最小スクリプト
document.querySelectorAll('pre code').forEach(block => {
  const html = block.innerHTML.trim().split('\n')
    .map(line => `<span>${line || ' '}</span>`).join('\n');
  block.innerHTML = html;
});

大規模サイトやパフォーマンス重視の環境では、ビルド時に行番号を埋め込むか、既存の行番号プラグインを採用すると描画コストを抑えられます。

コピー用ボタンを後付けする

読者がコードをコピーしやすいように、各ブロックにボタンを動的に追加します。クリップボード API を使うと数行で実装できます。

document.querySelectorAll('pre').forEach(pre => {
  const btn = document.createElement('button');
  btn.className = 'copy-btn';
  btn.type = 'button';
  btn.textContent = 'Copy';
  btn.addEventListener('click', async () => {
    const code = pre.querySelector('code')?.innerText ?? '';
    try {
      await navigator.clipboard.writeText(code);
      btn.textContent = 'Copied!';
      setTimeout(() => (btn.textContent = 'Copy'), 1500);
    } catch { btn.textContent = 'Error'; }
  });
  pre.style.position = 'relative';
  btn.style.position = 'absolute';
  btn.style.top = '8px';
  btn.style.right = '8px';
  pre.appendChild(btn);
});

遅延読み込みで描画ブロックを避ける

初回表示を速くしたい場合は、CSS は先に読み込み、JS は defer で遅延し、フォールド下の長文記事ではインタラクション後に初期化する方法も有効です。

<link rel="stylesheet" href=".../styles/github.min.css">
<script defer src=".../highlight.min.js"></script>
<script>
  window.addEventListener('load', () => hljs.highlightAll());
</script>

WordPress での設置ポイントと競合回避

テーマに直書きする場合は wp_enqueue_scripts で CSS と JS を登録します。すでにプラグインが別ライブラリ(Prism など)を読み込んでいると二重ハイライトになるため、どちらか片方に統一します。

<?php
add_action('wp_enqueue_scripts', function () {
  wp_enqueue_style('hljs-theme',
    'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.min.css',
    [], null);
  wp_enqueue_script('hljs-core',
    'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js',
    [], null, true);
  wp_add_inline_script('hljs-core', 'hljs.highlightAll();');
});

アクセシビリティとセキュリティの注意点

テーマによってはコントラストが不足します。暗色背景のテーマでは文字色と背景のコントラスト比をチェックし、必要に応じて CSS で補正します。ユーザー生成コンテンツに対しては必ずサーバー側でエスケープしてから出力し、ハイライト用のライブラリに任せてスクリプトを実行させない設計にします。

トラブルシューティングの要点

色が付かないときは初期化関数の呼び出し漏れ、言語の未読み込み、クラス名の違いが典型です。動的に挿入したコードが無色のままなら、挿入後に hljs.highlightElement(element) を個別に呼び出します。表示が崩れる場合はテーマ CSS とサイト側のコードブロック CSS の競合を疑い、precode のフォントや余白を整えます。

// Ajax 等で後から追加した要素を個別にハイライト
const el = document.querySelector('#ajax-code code');
hljs.highlightElement(el);

まとめ

highlight.js は CDN の 3 行で導入でき、言語の個別登録やテーマ切り替え、行番号やコピー機能の追加まで段階的に拡張できます。小さく始めて必要な分だけ読み込みを増やし、WordPress では enqueue に集約して競合を避けると、運用負荷を抑えつつ読みやすい技術記事を安定して提供できます。