highlight.jsを使ってbloggerでいい感じにコードブロックをスタイリングする。
highlight.jsはhtmlの<pre><code>
コードブロックに内包される言語を解析して、スタイリングしてくれるポリフィルだ。
導入
公式 | Usage / CDNのエントリー向けコードスニペット
html
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
<!-- and it's easy to individually load additional languages -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/go.min.js"></script>
<script>hljs.highlightAll();</script>
- スクリプト
highlight.min.js
は<code>
コードブロックに含まれる言語を解析して、結果を<code>
ブロックのクラスにclass="language-bash hljs"
のように付記してくれる。highlight.min.js
にはメジャーどころの言語の解析実装が含まれている。 - 未対応の言語は
go.min.js(GoLangの場合)
など必要に応じて追加の言語をインクルードして拡張できる。- 対応言語をカスタマイズして静的ファイルとしてダウンロードできるので、自ホストからホスティングもできる。Download a Custom Build
-
hljs.highlightAll();
でポリフィルを実行する。
html
これが
<pre><code>{ コード部 }</code></pre>
hljs.highlightAll();でこうなる
<pre><code data-highlighted="yes" class="hljs language-php">{ コード部 }</code></pre>
- スタイルシート
default.min.css
はそのclass名のスタイルシートだ。demoから好みのスタイルを探してdefault
部分を置き換えてスタイルを適応することができる。
好みのスタイルにする
demoからスタイルを吟味して使いなれたvscode
と思しきvs2015.min.css
をセレクト。
html
<link href='https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/vs2015.min.css' rel='stylesheet'/>
<!-- stackeditでマークダウンをhtmlにエクスポートしたやつ -->
<pre class="language-php"><code class="language-php"><span class="token php language-php"><span class="token delimiter important"><?=</span> ClassName<span class="token punctuation">:</span><span class="token punctuation">:</span>constant_field_name <span class="token delimiter important">?></span></span>
</code></pre>
vs2015.min.cssではこのようにスタイリングされる
ファイルタイプを付記する
highlight.min.js
解析スクリプトはラベルまで面倒見てくれないのでHEXOとhighlight.jsでシンタックスハイライトし、ついでにファイル名も表示する様を参考にJSでファイルタイプのラベルを補完する。
highlightjsで当てられたスタイルクラスlangage-php
のハイフンをセパレータにしてファイルタイプをラベリングするJS実装を入れる。
javascript
document.addEventListener('DOMContentLoaded', () => {
// highlightjsがpre codeブロックにスタイルクラスをあてる
hljs.highlightAll();
// コードブロック解析
Array.prototype.slice.call(document.querySelectorAll('pre code')).forEach( code => {
// highlightjsが適用したスタイルクラス(language-{filetype})をもとに{filetype}をdata属性に補完
Array.prototype.slice.call(code.classList).forEach( className => {
const asFileType = className.split('language-')[1];
if (asFileType) code.setAttribute('data-filename', asFileType);
});
// コードボディ部を折り返しなしでオーバーフロースクロールなコンテナでラップする
const wrapperDiv = document.createElement('div');
wrapperDiv.classList.add('code-wrapper');
wrapperDiv.innerHTML = code.innerHTML;
code.innerHTML = '';
code.appendChild(wrapperDiv);
});
// ついでにインラインコードブロックにスタイルクラスを当てる
let allCodeTags = document.querySelectorAll('code');
let filteredCodeTags = Array.from(allCodeTags).filter(el => el.parentElement.tagName.toLowerCase() !== 'pre');
filteredCodeTags.forEach(el => {
el.classList.add('inline-code');
});
});
ラベルの表示とコードブロックのスタイリング
css
/* 疑似要素でコードブロックにファイルタイプをディスプレイ */
pre code.hljs[data-filename]::before {
content: attr(data-filename);
padding: 0.3em 1em;
color: #fff;
font-size: 0.9em;
background-color: rgba(255, 255, 255, 0.2);
border-bottom-right-radius: 8px;
}
/* コードブロックのスタイルを好みに調整 */
pre code.hljs {
/* ラベルはコードブロックの外辺に沿わせたいのでhljsスタイルクラスを上書いてパディングを無効化 */
padding: 0 !important;
/* コードブロックは丸みをもたせてフォントサイズは標準に引き上げ */
border-radius: 8px;
font-size: 1em;
}
/* ラップしたコード部 */
pre code.hljs .code-wrapper {
padding: 1em;
overflow-x: scroll;
}
/* インラインコードブロック */
.inline-code {
border: none;
background-color: #eee;
border-radius: 4px;
vertical-align: middle;
padding: 4px 8px;
margin: 0 4px;
}