本ブログでも使っている、Syntax Highlighter Shiki
をはてなブログに導入する方法をここに記します。
Shiki | 式
Shiki
とは TypeScript 製の Syntax Highlighter で、対応言語やテーマの数が豊富なことからとても人気があります。(筆者の主観)
markdown-it
や VitePress
などの Integration が提供されていたり Astro
に組み込まれていたりと、触れたことがある人も多いのではないでしょうか。
はてなブログ
さて、はてなブログの Syntax Highlighter を変更するといっても既存のものを止める訳ではありません。
今のところ、HTML のレンダリングに介入することは出来ないので...
置き換える
はてなブログではヘッダに任意の HTML を挿入することができるので、HTML 読み込み時に既存のコードブロック要素を Shiki
でレンダリングしたものに後から置き換えることにします。
(ここでブラウザをリロードしてみると、コードブロックが置き換わる様子が見えるでしょう)
ドキュメントにあるブラウザ向けの CDN を利用して、はてなブログの HTML 上にあるコードブロックを置き換える処理を実装します。
<script type="module"> import { codeToHtml } from "https://esm.sh/shiki@1.12.0" const pres = document.querySelectorAll("pre.code") pres.forEach((pre) => { const lang = pre.dataset.lang const rawCode = pre.textContent ;(async () => { const code = await codeToHtml(rawCode, { theme: "github-dark", lang: lang, }) const dummy = document.createElement("div") dummy.innerHTML = code pre.replaceWith(dummy.firstChild) })() }) </script>
あとは、ブログの 設定 > 詳細設定 > head内タグ > <head>要素にメタデータを追加
から上記のスクリプトを張り付ければ完成です。
ブログのテーマによっては、CLS(Cumulative Layout Shift)の原因となるので元のコードブロックのフォントサイズなどを揃えておきましょう。
HTML 編集モード
HTML 編集モードでは、はてなブログで生成されるコードブロックの HTML に合わせて <pre>
タグに code
classと、data-lang
attribute に言語を指定してください。
<pre class="code" data-lang="javascript"> console.log("Hello, World!") </pre>
設定
Themes
Shiki
には次のテーマが指定可能です。
prefers-color-scheme
Light/Dark Dual Themes | Shiki
端末のダークモードに追従させることもできます。
- theme: "github-dark", + themes: { + light: 'github-light', + dark: 'github-dark', + },
上記のようにテーマを設定した後、以下のスタイルをブログの 設定から <head>要素
に追加してください。
<style> @media (prefers-color-scheme: dark) { .shiki, .shiki span { color: var(--shiki-dark) !important; background-color: var(--shiki-dark-bg) !important; /* Optional, if you also want font styles */ font-style: var(--shiki-dark-font-style) !important; font-weight: var(--shiki-dark-font-weight) !important; text-decoration: var(--shiki-dark-text-decoration) !important; } } </style>
おまけ
Shiki
は v1 から ESM となりました。
つまり、JavaScript モジュールで使う必要があります。
もしも、あなたが過去を生きるユーザーも救いたいということであれば、以下に古いバージョンのコードを用意したのでお使いください。
<script defer src="https://unpkg.com/shiki@0.14.6"></script> <script> window.addEventListener("DOMContentLoaded", function () { const pres = document.querySelectorAll("pre.code") const langs = [] for (const pre of pres) { const lang = pre.dataset.lang langs.push(lang) } shiki.getHighlighter({ theme: 'github-dark', langs: langs, }).then(highlighter => { pres.forEach(pre => { const lang = pre.dataset.lang const rawCode = pre.textContent const code = highlighter.codeToHtml(rawCode, { lang: lang }) const dummy = document.createElement('div') dummy.innerHTML = code pre.replaceWith(dummy.firstChild) }) }) }) </script>
inline スクリプトに defer 使いたいナ