Bloggerでコードブロックをスタイリング

<img src="https://blogger.googleusercontent.com/img/a/AVvXsEhW5FrsFa04OpRn1lpB3JG85ZqeIouSeTCmPbhgBagN6FbY1oLzPqRPh7jdUNk72vpcl59ZvSwFPA0gAHXebzR-DST_8Z78BfRpI9RIupWd1BVL4mcmoR9oOBnb5f8vf7raqsdNW4fkHbKRMRgdgmopxIA1T0qhTV6Pzc9kYbpHG_KjC9eAWNk0YyQTxy8Z" alt="js" width="80">    
<img src="https://blogger.googleusercontent.com/img/a/AVvXsEjZxzsnxskxQDI0P0yc-ZgrHazNEwF4flifH4ppG3DfSopVyyjh7qj6Viqqo0Wxyaq0oxYo6gf99TdyIB9pz1ehUsT3otZ0RY_Y2V7z00fjheuZpCJBUTpUWxJY0RGuDRIR6h5Lni0QLqqT6i7dcPTfTwSemPQbdC34mBGU8S9FZVND2s7Ve_uvcs_c2l8U" alt="css" width="80">

highlight.jsを使ってbloggerでいい感じにコードブロックをスタイリングする。
highlight.jsはhtmlの`<pre><code>`コードブロックに内包される言語を解析して、スタイリングしてくれるポリフィルだ。
## 導入

[公式 | Usage / CDN](https://highlightjs.org/#usage)のエントリー向けコードスニペット

```html: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](https://highlightjs.org/download)
  - `hljs.highlightAll();`でポリフィルを実行する。

```html:html
これが
<pre><code>{ コード部 }</code></pre>

hljs.highlightAll();でこうなる
<pre><code data-highlighted="yes" class="hljs language-php">{ コード部 }</code></pre>
```

- スタイルシート`default.min.css`はそのclass名のスタイルシートだ。[demo]([Demo](https://highlightjs.org/demo))から好みのスタイルを探して`default`部分を置き換えてスタイルを適応することができる。

## 好みのスタイルにする

[demo]([Demo](https://highlightjs.org/demo))からスタイルを吟味して使いなれた`vscode`と思しき`vs2015.min.css`をセレクト。

```html: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">&lt;?=</span> ClassName<span class="token punctuation">:</span><span class="token punctuation">:</span>constant_field_name <span class="token delimiter important">?&gt;</span></span>
</code></pre>
```

vs2015.min.cssではこのようにスタイリングされる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/417736/476d08b3-7da5-8b9b-6c2b-acaded81ded5.png)

## ファイルタイプを付記する

![image 2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/417736/6de0a741-4f25-984a-321c-1fddc81b974c.png)

`highlight.min.js`解析スクリプトはラベルまで面倒見てくれないので[HEXOとhighlight.jsでシンタックスハイライトし、ついでにファイル名も表示する](https://blog.87oui.com/highlightjs-filename/)様を参考にJSでファイルタイプのラベルを補完する。

highlightjsで当てられたスタイルクラス`langage-php`のハイフンをセパレータにしてファイルタイプをラベリングするJS実装を入れる。

```javascript: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: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;
}
```