Slidev で日本語スライドを作ると、本文、コードブロック、Mermaid 図、PDF 出力でフォントの見え方がずれることがあります。
この記事では、Slidev で日本語を扱うときに自分が入れているフォント設定をまとめます。
何が問題になるのか
日本語 Slidev でよく困るのは、次のような点です。
| 困ること | 起きる場所 |
|---|---|
| 日本語と英数字のバランスが悪い | 本文、表、見出し |
| コードブロックの日本語が読みにくい | Shiki / Monaco |
| Mermaid 図のラベルだけフォントが変わる | Mermaid |
| PDF 出力するとフォントが変わる | slidev export |
| 絵文字フォントが本文に干渉する | CSS font stack |
本文、コード、Mermaid、絵文字を分けて考えるのが基本方針です。
フォントファイルをpublicに置く
たとえば、次のように public/fonts/ にフォントファイルを置きます。
decks/
├── style.css
└── public/
└── fonts/
├── YuGothicUI-Regular.ttf
├── YuGothicUI-Semibold.ttf
├── YuGothicUI-Bold.ttf
├── NotoSansJP-Regular.ttf
├── NotoSansJP-Bold.ttf
├── PlemolJPConsole-Regular.ttf
├── PlemolJPConsole-Bold.ttf
└── NotoColorEmoji.ttf
style.css からは /fonts/... で参照できます。
@font-faceを定義する
本文用、コード用、Mermaid 用、絵文字用のフォントを分けて定義します。
@font-face {
font-family: 'Deck JP Sans';
src: url('/fonts/YuGothicUI-Regular.ttf') format('truetype');
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'PlemolJP Console';
src: url('/fonts/PlemolJPConsole-Regular.ttf') format('truetype');
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Deck Mermaid JP';
src: url('/fonts/NotoSansJP-Regular.ttf') format('truetype');
font-weight: 400;
font-style: normal;
font-display: swap;
}
太字を使うなら、font-weight: 700 のフォントも別途定義しておきます。
本文フォントを指定する
Slidev の default テーマは .slidev-layout * でフォントを指定しているため、単純な body 指定だけでは負けることがあります。
html body,
html body #app,
html body #page-root,
.slidev-layout,
.slidev-layout *,
.slidev-slide-content,
.slidev-slide-content * {
font-family: "Nunito Sans", "Deck JP Sans", "Deck Emoji", sans-serif !important;
overflow-wrap: anywhere !important;
word-break: keep-all !important;
line-break: strict !important;
}
Slidev のテーマ CSS に勝つため、フォント指定では !important が必要になることがあります。
特に default テーマは広いセレクタで font-family を指定するため、本文全体に確実に適用したい場合は詳細度だけで調整するより明示的に上書きする方が安定しました。
コードブロック用フォントを分ける
本文フォントとコードフォントは分けた方が読みやすいです。
:root {
--slidev-code-font-family: "PlemolJP Console", monospace !important;
}
.slidev-layout code,
.slidev-layout pre,
.slidev-layout code *,
.slidev-layout pre *,
.slidev-slide-content code,
.slidev-slide-content pre,
.slidev-slide-content code *,
.slidev-slide-content pre *,
.shiki,
.shiki code,
.shiki span,
.slidev-code,
.slidev-code code,
.slidev-code span,
.slidev-monaco {
font-family: "PlemolJP Console", monospace !important;
}
コードブロックの font-size は、pre や .shiki などのコンテナにだけ指定する方がよいです。
code や span にも em 指定すると、Shiki が生成するネストした <span> に多重で縮小がかかり、文字が極端に小さくなることがあります。
.slidev-layout pre,
.slidev-slide-content pre,
.shiki,
.slidev-code,
.slidev-monaco {
font-size: 0.95em !important;
}
Mermaidのフォントを別にする
Mermaid 図は本文とは別のフォントにすると、ラベルの見え方を調整しやすいです。
setup/mermaid.ts にフォント設定を書きます。
export default () => ({
htmlLabels: false,
fontFamily: '"Deck Mermaid Latin", "Deck Mermaid JP", sans-serif',
altFontFamily: '"Deck Mermaid Latin", "Deck Mermaid JP", sans-serif',
themeVariables: {
fontFamily: '"Deck Mermaid Latin", "Deck Mermaid JP", sans-serif',
},
themeCSS: `
.label,
.nodeLabel,
.edgeLabel,
.cluster-label,
.label text,
.nodeLabel text,
.edgeLabel text,
.cluster-label text {
font-family: "Deck Mermaid Latin", "Deck Mermaid JP", sans-serif !important;
line-height: 1.4 !important;
}
`,
})
Mermaid の htmlLabels は false にする方がフォントを制御しやすいです。
true の場合、ラベルが <foreignObject> 内の HTML として描画されます。この方式では Mermaid 側のインライン CSS が強く、外側の CSS でフォントを上書きしにくくなります。
絵文字フォントはunicode-rangeで絞る
絵文字フォントはサイズが大きく、本文フォントに干渉することもあります。
@font-face {
font-family: 'Deck Emoji';
src: url('/fonts/NotoColorEmoji.ttf') format('truetype');
font-weight: 400;
font-style: normal;
font-display: swap;
unicode-range: U+2600-27FF, U+2B00-2BFF, U+1F300-1FAFF, U+FE0F;
}
unicode-range を指定すると、対象文字が使われたときだけフォントを読み込ませやすくなります。また、ラテン文字や日本語に絵文字フォントが当たる事故も避けやすくなります。
PDF出力ではwaitを入れる
PDF 出力では、フォントの読み込み前にキャプチャされることがあります。
npm run export -- decks/intro.md --output exports/intro.pdf --wait 3000
日本語フォントや独自フォントを使うなら、PDF 出力時の --wait は入れておく方が安定します。
まとめ
Slidev の日本語フォント対応では、次のように役割を分けると管理しやすいです。
| 用途 | 方針 |
|---|---|
| 本文 | 日本語を含む読みやすい sans-serif |
| コード | 日本語対応の等幅フォント |
| Mermaid | 図中ラベル用に別スタック |
| 絵文字 |
unicode-range で適用範囲を絞る |
--wait でフォント読み込みを待つ |
一度設定しておくと、複数 deck でも同じ style.css を流用できるため、かなり運用が楽になります。