Claude Code×Slidev:AIスライドが“毎回揃わない”を解決するデザイントークン

Hero banner with large Japanese headline 'Allに書かせるとスライドが崩壊する。', teal brand marks top-left, and 'SIOS Tech.Lab' logo top-right on a pale beige background.

AIは結構ちゃんと作る。でも“揃わない”し、たまに事故る

ども!Slidev と Claude Code でスライドを量産してる龍ちゃんです。

念のため前提だけ。Slidev は Markdown でスライドを書けるツールで、この連載の話は全部その上に乗ってます。今回のトークンも、Slidev プロジェクトの style.css に置く前提です。Slidev 自体のセットアップは第1部に。

前回(第2部)で「部品化して育てるなら Slidev」って話をして、最後に予告したやつですね。今回はその一番効く処方箋、デザイントークンの話です。

まず、ちょっと煽りっぽい見出しと逆のことを正直に言います。最近のAI(Claude)、放っておいても結構ちゃんとしたスライドを作ります。色を聞かなくても CSS変数化までしてくるし、強調も1〜2色に抑えてくる。「AIに任せると色が虹色に暴走する」って身構えてたんですけど、少なくとも僕が試した範囲では、そこまで荒れない。地力、高いんですよ。

じゃあトークンなんて要らないの? っていうと、要ります。ただ理由が「色の暴走を止める」じゃなくて、別の2つなんですよね。

  • 揃わない
    1回ごとに“それっぽいけど毎回ちょっと違う”トーンが出てくる。今日作ったデッキと来週のデッキ、自分のとチームの人ので、揃う保証がない。AIは悪気なく、毎回ちょっとずつ違う判断をするので
  • たまに“惜しい”事故を踏む
    放っておくと本文が 0.6〜0.8rem まで縮むことがあって、投影や配信で潰れると読めない。あと絵文字を入れてきて、本番のエクスポートで消える/豆腐(□)化する(これは後で詳しく)

要するに、AIは80点はくれる。でも“毎回同じ80点”の保証はないし、下限(読めるサイズ・消えないアイコン)は守ってくれない。そこを埋めるのがトークンです。やることは、「使っていい色・最低サイズ・使うアイコン」を先に1回決めて“枠”にするだけ。そうすると、毎回そこに揃うし、下限が保証される。色の話も「暴走を止める」というより、毎回・誰がやっても同じ色に乗せるための枠、と捉えるのが正確ですね。

百聞は一見ということで、「枠なし(左)」と「枠で揃えた(右)」を並べてみました。(左はわざと散らかした極端な例です。実際の素のAIはここまで荒れません。でも“毎回同じトーンに揃える”と右側になる、のイメージとして見てください)

同じ内容のスライドなんですよ。なのにこの安定感の差。効いてるのは選択肢を絞ったことです。色なんて1670万色から自由に選べるんだから、毎回バラつくのは当たり前。だから先に「使っていい色はこれだけ」って枠を渡す。これだけです。

色・サイズ・余白を CSS変数で縛る

やることはシンプルで、スライドプロジェクトの style.css の先頭に、使っていい値を CSS変数(デザイントークン)として全部宣言しておくだけです。

/* style.css — :root に「使える値」を先に並べておく */
:root {
  /* 色:使っていいのはこれだけ。AIはこの中から選ぶ */
  --bg-white:       #FFFFFF;   /* 背景(白地) */
  --navy-900:       #0B1F3A;   /* 見出し・濃い地に使うネイビー */
  --text-primary:   #1E293B;   /* 本文 */
  --text-secondary: #475569;
  --accent:         #C2410C;   /* 強調はこの抑えた朱の1色だけ */
  --accent-soft:    rgba(194, 65, 12, 0.10);
  /* 「注意」「成功」みたいな“意味を持つ色”は、強調とは別腹で持つ */
  --warning:        #B45309;
  --success:        #15803D;
}

色は「背景・本文・強調」くらいに絞るのがコツです。ブランドの強調は、いっそ1色に決め打ちしちゃう(僕はこの抑えた朱だけ)。それだけで「ちゃんとデザインされてる感」が出るし、どこが大事かが一発で伝わる。「注意」「成功」みたいな“意味を持つ色”は別腹で足していいですが、それも含めて多くても3色まで。逆に強調色が5色6色あると、もう何が大事なのか分からなくなるんですよね。

サイズと余白も同じ発想で、変数にしてしまいます。

:root {
  /* フォントサイズ:最小ラインを決めて、その倍数で刻む */
  --font-body:    20px;   /* 本文。19px は下回らない */
  --font-heading: 35px;   /* 見出し */
  --font-lead:    24px;   /* リード文 */

  /* 余白:刻みを固定(4の倍数だけ使う、みたいに揃える) */
  --space-sm: 8px;
  --space-md: 16px;
  --space-lg: 24px;
  /* ※ Slidev は UnoCSS(Tailwind 互換)が標準同梱。
     余白は p-2=8px / gap-4=16px…、フォントは text-lg / text-xl… と
     既製スケールが最初からあるので、--space-* や --font-* を自作せず
     そのまま乗ってもいい。
     ただし色は bg-blue-500 等のデフォルト色が何百色と開けっ放しなので、
     使う色だけは別途 theme で絞る必要がある(詳細は下の本文で) */
}

ポイントは「最小フォントサイズを決める」こと。スライドは投影したり配信で画質が落ちたりするので、本文は最低でも 19〜24px は欲しい。ここを変数で固定しておくと、AIが調子に乗って「ここは情報多いから小さくしますね」って 14px とかにするのを防げます。このへんの下限は経験則でいいので、いったん決めて書き出しておくと後がラクですよ。ちなみにこの“本文サイズ”、放っておくとAIが実際にいちばん縮めてくる“惜しい躓き”の代表格なんですよ。トークンが一番ハッキリ効くのが、この下限です。

ここまで「自前で CSS変数を宣言する」前提で書いてきましたけど、Slidev は UnoCSS(Tailwind 互換)が標準で入ってるんですよね(さっきの余白のコメントもそれです)。なので余白やフォントサイズは、--space-* を自作しなくても Tailwind のスケール(text-lg / gap-4…)にそのまま乗れます。「本文は text-xl(=20px)以上しか使わない」って縛り方でもアリですね(text-lg は18pxで、さっき決めた19px下限を割るので避ける)。

ただ、色だけは Tailwind を入れても開けっ放しですbg-red-500 bg-blue-500…って何百色も用意されてるんで、結局”生hexで好き勝手”と変わらないんですよ。だから色に関しては、Tailwind を使うときでも「使っていいのはこの色だけ」と自分で絞る ── さっきの色トークンの話は、Tailwind でもそのまま効きます。サイズ・余白はスケールに乗ってラクして、色はちゃんと締める。これが僕の落としどころですね。

そして、定義したトークンは全スライドの”地”に1回当てておくと、共通のベースになります。当て先は .slidev-layout ── 組み込みレイアウトが持ってる「スライドの土台」クラスです(この性質は後の「どこに書くか」で詳しく)。ここに当てておけば、以降どの型からでも同じフォント・色で始められます。

/* style.css::root のトークンを、全スライドの土台 .slidev-layout に当てておく */
.slidev-layout {
  background: var(--bg-white);
  color: var(--text-primary);
  font-size: var(--font-body);
  font-family: 'Noto Sans JP', sans-serif;
}

(Tailwind 派なら .slidev-layout { --uno: bg-... text-... } でも同じことができます)

アイコンも「枠」で縛る:絵文字は本番で消える

縛るのは色とサイズだけじゃないんですよ。アイコンもです。AIにスライドを書かせると、これまた放っておくと 🚀✨🎯✅ みたいな絵文字を勝手に散りばめてくる。そして絵文字は、放っておくと素のAIが実際に踏む“惜しい躓き”の代表格です。で、絵文字がやっかいなのは、見た目がAIっぽくなるだけじゃないんですよ。書き出すと消えるんです。(たまに全力で SVG を作り込んできたりしますねw)

Slidev の PNG/PDF エクスポートは裏で Playwright(ヘッドレス Chromium)が動くんですけど、この環境には絵文字フォントが入ってないことがある。なので dev サーバーのプレビューでは 📦 や ✅ がちゃんと出てるのに、エクスポートした PNG では真っ白な空白になったり、□(豆腐)になったりする。本番で初めて気づくやつです、ヒヤッとします。

対策は色トークンと同じ発想で、「使っていいアイコンの供給源」を style.css で1つに固定すること。僕は Material Icons(Web フォント)に統一してます。Web フォントなので、エクスポート環境でも確実に描画されます。

/* style.css の先頭で読み込む。これで絵文字を追放してアイコンを一本化 */
@import url('https://fonts.googleapis.com/icon?family=Material+Icons');
<!-- 絵文字 🚀 をやめて、Material Icons の名前で呼ぶ -->
<span class="material-icons">rocket_launch</span> ローンチ
<span class="material-icons">check_circle</span> 完了
<span class="material-icons">warning</span> 注意

絵文字を「テキストの一部」だと思ってると見落としがちなんですけど、あれも立派な視覚要素。色と同じで「使っていいのはこれ」と供給源を絞ると、AIの出力が揃うし、本番で消える事故も消えます。

肝は「先に宣言して、プロンプトに制約として組み込む」

で、ここが一番大事なんですけど、style.css に変数を置いただけでは、AIは縛られません

これ、人間の感覚だと「CSS 見れば使っていい色わかるでしょ」って思うんですよ。でもAIはこっちが言わない限り、変数があることなんてお構いなしに、平気で style 属性に生の #ff5577 を書いてくる。「この変数の中から選んでね」って、わざわざ宣言してあげないと使ってくれないんですよね。ここが人間相手との一番の違いです。

だから順番が肝で、先に枠を宣言して、それをプロンプト(コンテキスト)の中に”制約”として組み込んでおく。具体的には、プロジェクトの CLAUDE.md なり最初の依頼文なりに、こう書いておくんです。

# スライド作成の制約(Slidev / CSS変数)

- 色は style.css の :root で定義した CSS変数(--accent など)だけを使う。ブランド強調は朱(--accent)1色、意味の色を入れても3色まで。
- フォントサイズは --font-* 変数を使う。本文は --font-body を使う。
- 余白は --space-* 変数を使う。
- 色・サイズ・余白はすべて変数経由(var(--xxx))で指定する。
- アイコンは Material Icons(<span class="material-icons">名前</span>)を使う。

Tailwind(UnoCSS)を標準で使うスタイルなら、同じ制約をユーティリティ向けに言い換えるだけ。中身は一緒で、「変数で縛る」が「クラスで縛る」に変わるだけですね。

# スライド作成の制約(Slidev / Tailwind 標準)

- 色は style.css の theme に定義した色クラス(text-accent / bg-accent など)だけを使う。ブランド強調は朱1色、意味の色を入れても3色まで。
- フォントサイズは text-xl 以上のクラスを使う(text-lg は18pxで19px下限割れ)。
- 余白は決めた刻みのクラス(gap-4 / p-4 など)を使う。
- 色・サイズ・余白はすべてユーティリティクラスで指定する。
- アイコンは Material Icons(<span class="material-icons">名前</span>)を使う。

ポイントは「あとから直す」んじゃなくて「先に縛る」こと。CLAUDE.md に一度書いておけば、それ以降のスライド生成は全部この制約の中で走るんですよ。毎回「色そろえて」「文字大きくして」って言い直さなくても、最初から枠の内側で出てくる。人間が後追いで矯正するんじゃなくて、AIが最初から枠の中で考えるようにする。これがトークンを”AIに効かせる”ための一手です。

これだけで、生hexを直書きしてたところが、こうなります。

<!-- 縛ったあと。色もサイズも変数経由で、必ず揃う -->
<h2 style="font-size: var(--font-heading); color: var(--navy-900)">重要なポイント</h2>
<p>ここが <span style="color: var(--accent)">超重要</span> です</p>

AIが選べる色が決め打ちされてるから、毎回・誰がやっても同じ色に乗る。色がバラつかないんですよ。

「どこに書くか」も枠で決める

ここまで全部 style.css に書いてきましたけど、「何でもかんでも style.css でいいの?」というと違って、書く場所にも線引きがあります。判断は1つだけで、「どのスライドでも必ず効いてほしいか?」です。

  • 全スライド共通で効かせたい土台(トークン、ベースのフォント・文字色・背景)→ style.css に置く。どの型を使っても必ず効いてほしいやつ。
  • その型・その部品の中だけで効けばいい見た目style.css に書かず、そのレイアウト/コンポーネントの中に閉じ込める。特定の型でしか使わない構造や、ある部品の中だけの装飾はこっち。

で、style.css に共通で書くときの作法もひとつ。Slidev は素のセレクタ(h1 { … })で書くとスライドだけじゃなく発表者モードのUIにまで効いちゃうんですよ。なので公式は、スライドの中身に付く .slidev-layout クラスの配下に書くことを推奨してます。.slidev-layout は、Slidev の組み込みレイアウトが自分のテンプレートに書いてるクラスです(フレームワークが自動で全スライドに付けてるわけじゃない)。クラス自体は Slidev 由来でも、そこに乗せる見た目は自分で書く、って関係ですね。default や two-cols みたいな組み込みを使ってる限りは付いてるので、共通スタイルがちゃんと効きます。ただ、ここが地味に大事で ── 自分でレイアウトを自作したときは、.slidev-layout を自分で付けないと、style.css に書いた共通スタイルがそのレイアウトにだけ効かないんですよ。組み込みが付けてくれてた分を、自作するなら自分で付ける必要がある、ってことですね(公式のレイアウト作成ガイドの例も、wrapper の <div>class="slidev-layout" を書いてます)。逆に「この1枚だけ」なら、そのスライドの中に <style> を書けば常に scoped(そのスライド限定)で、他のスライドには漏れません。

/* style.css:全スライド共通の見た目は .slidev-layout の配下に書く */
.slidev-layout h1 { font-size: var(--font-heading); }
/* ✗ h1 { … } だけだと発表者モードのUIにも漏れる */
<!-- このスライドだけ、なら slides.md のそのページに <style>。常に scoped で他に漏れない -->
<style> h1 { color: red; } </style>

ここを混ぜると地味に事故ります。「この1枚だけ」のつもりの CSS を .slidev-layout 配下や <style> に閉じず style.css にベタ書きすると、別のスライドや発表者モードまで巻き込んで崩れる。共通にしたいものだけ、狙って書く。 それだけで「なんでこのスライドまで変わった?」が消えます。
これが発見されるパターンとしては、componentやlayoutで定義した内容が効かなくて !importantで回避したときですね。個人的意見としては !importantは使わないのがきれいなプロジェクトだと思います。

制約が速さを生む

ここで一番伝えたいのは、自由にさせない方が、結果的に速いってことです。

自由に書かせると、出力は毎回それっぽいけど毎回ちょっと違う。だから「色を揃えて」「サイズ揃えて」っていう手戻りが延々と発生する。でも、トークンで枠を作っておくと、AIの出力は最初から揃ってる状態で出てくる。レビューで見るべきは「内容が合ってるか」だけになって、「色がバラバラ問題」が議題から消える。

色なんて特にそうで。トークン化する前は、AI が HEX の微妙な色違いを60種類くらいばらまいてきたことがあったんですよ。で、後からテーマ色を変えようとしたら、その色が全ファイルに散らばってて、全部のファイルを読みに行かないと直せない。案の定、直し漏れも出ました。これがトークンで縛ってあれば、変えるのは変数1か所=検索して置換するだけ。後からの作り替えが、グッとラクになるんですよね。

注意:これは”枠”であって”完成”じゃない

ここは正直に書いておきます。トークンを定義しただけでは、完璧な見た目にはなりません。

トークンは「使っていい絵の具」を決めただけ。その絵の具をどう配置するか(レイアウト・コンポーネント)は別の話で、それは次回の第4部(デザインシステム編)でやります。

そして、このトークンを土台に型・部品・ルールまで全部組み上げた“動くデッキ一式”そのものは、実物編(全部入り)CLAUDE.md 全文つきで公開しています。

で、もうひとつ大事な注意。「style.css に書いた=そう表示されてる」とは限らないんですよ。CSS はカスケードで上書きが起きるし(よくある自作 CSS のミスで簡単に効かなくなる)、さっきの絵文字みたいにエクスポートで初めて崩れることもある。トークンを定義して安心してても、画面では別物、というのは普通に起きます。

だから最後は必ずPNG にエクスポートして、その画像を目で見て確認する。CSS に書いた気になって満足すると、本番で「アレ?効いてない」ってなるやつなんですよね。「こう書いた」じゃなくて「画面でどう出てるか」で判断する。地味だけど、ここを飛ばすと普通に事故ります。

この「画像を見て直す」を仕組みにする話は、それだけで一本になるテーマ。トークンで枠を作る → システムに育てる → 画像で品質を回す、の最初の一歩が今回でした。

まとめ

  • AIは放っておいても8割方は作れる。でも毎回トーンが揃わない/本文が小さくなる/絵文字が本番で消える
  • 色・サイズ・余白を CSS変数(デザイントークン)として style.css に先に定義し、「使える色はこれだけ」とAIを縛る
  • アイコンも枠で縛る。絵文字はエクスポートで消える(豆腐化する)ので、Material Icons に一本化する
  • 制約が手戻りを消して速さになる。自由度より、選択肢を絞るほうが安定する
  • ただしトークンは”枠”であって”完成”じゃない。最後は書き出した画像を見て確認する

次回(第4部)は、このトークンを起点に、レイアウトやコンポーネントまで束ねて「自分のデザインシステム」に育てる話です。揃えた資産が、次のスライドの速さになるやつ。お楽しみに。

ほなまた〜

シリーズ:AI×スライドづくり

AIに丸投げせず、制約とルールで「意図どおりの95点」を毎回そろえて作るシリーズです。

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。
エンジニア募集中!

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です