[Astro] Markdownのコードハイライトを Shiki でライト/ダーク両対応にする

Tech
[Astro] Markdownのコードハイライトを Shiki でライト/ダーク両対応にする

技術ブログだとコードブロックの見た目は地味に大事です。Astro は Shiki を標準で内蔵していて、設定だけで Markdown のコードハイライトが効きます。さらに、ライトモードとダークモードで配色を切り替えることもできるので、その設定をまとめます。

デュアルテーマを指定する

astro.config.mjsmarkdown.shikiConfig.themes に、light / dark それぞれのテーマを指定します。追加パッケージは不要(Shiki は Astro 同梱)。

// astro.config.mjs
import { defineConfig } from 'astro/config';

export default defineConfig({
  markdown: {
    shikiConfig: {
      themes: {
        light: 'github-light',
        dark: 'github-dark',
      },
    },
  },
});

theme(単数)ではなく themes(複数) で light/dark を渡すのがデュアルテーマのキモです。

CSS でダーク配色を有効化する

デュアルテーマにすると、Shiki は各トークンにライト用の色 + --shiki-dark というCSS変数を一緒に出力します。デフォルトのままだとライト配色しか効かないので、ダーク時に --shiki-dark を使うよう CSS を1つ足します。

/* src/styles/global.css */
@media (prefers-color-scheme: dark) {
  .astro-code,
  .astro-code span {
    color: var(--shiki-dark) !important;
    background-color: var(--shiki-dark-bg) !important;
  }
}

Shiki が出力するコードブロックは .astro-code というクラスを持っています。ダークモード時にこのクラス(と中の span)の色を --shiki-dark / --shiki-dark-bg に差し替えることで、配色が切り替わります。

ここでは OS 設定に追従する prefers-color-scheme で切り替えていますが、クラス(.dark など)で手動トグルしたい場合は、メディアクエリの代わりにそのクラスをセレクタに使えば OK です。

ついでに見た目を整える

.astro-code に角丸やパディングを足しておくと、prose の中でも馴染みます。

.astro-code {
  border-radius: 0.5rem;
  padding: 1.25rem;
  font-size: 0.875rem;
  line-height: 1.7;
}

確認

適当な Markdown にコードブロックを書いて、OS のダークモードを切り替えてみます。

```js
const hello = 'world';
console.log(hello);
```

ライト時は github-light、ダーク時は github-dark の配色に切り替われば成功です。設定2か所(config の themes と CSS の --shiki-dark)だけで両対応になるので、コストの割に効果が大きいカスタマイズでした。

Astro, Shiki, Markdown