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に丸投げせず、制約とルールで「意図どおりの95点」を毎回そろえて作るシリーズです。
- セットアップ〜エクスポート — 構文ゼロで作って配る
- Marp と Slidev の使い分け — Git管理起点でどっちを使う
- 実物編(全部入り):移植できるデザインシステムを丸ごと公開 ← まとめ


