surface について
surface は、ライト/ダークテーマにおける UI の色、面、奥行きを設計するスキルです。プロダクト画面向けに、意味的トークン、コントラスト、アクセント、テーマ切り替えを案内します。
主な機能
- 01意味に基づくカラートークンを定義
- 02ライト・ダークの配色を構成
- 03面の奥行きと境界線を設定
- 04コントラストと状態色を指針化
- 05テーマ切り替えとフォーカス表示を設定
活用シーン
- 01ライト・ダーク対応の配色体系を作成
- 02テキストやコントロールのコントラストを確認
- 03カードやポップオーバーの表面を統一
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ paragonhq/ stealth-skills --skill surfaceインストール後、Claude Code で/surfaceを入力して読み込まれたか確認します。
詳細
表面
インターフェースの色は、ほとんどの場合、色がないことを意味します。ニュートラルカラーとエレベーションを適切に整えれば、あとはアクセントカラーひとつで十分です。
まずはトークンから
色は値ではなく役割で命名します。両方のテーマで使えるパレットは、概ね次のような構成です。
| トークン | 役割 |
|---|---|
--page | アプリのフレームの背後にある、最も外側の背景 |
--frame | アプリの表面 |
--raised | カード、ポップオーバーなど、一段高く配置されるもの |
--hover | 行や項目にホバーしたときの塗りつぶし |
--line | 標準の境界線 |
--line-2 | より強い境界線、フォーカスリング、見える必要のある区切り線 |
--fg | メインのテキストとアイコン |
--fg-2 | セカンダリテキスト |
--fg-3 | ターシャリ、メタ情報、プレースホルダー |
--fg-4 | 薄い色:装飾、無効状態、テキスト内の区切り線 |
--accent | ひとつだけ。主要なアクションとフォーカスに使い、それ以外には使いません |
--ok、--warn、--danger | 状態表示用。彩度を抑え、それぞれテキストに使えるバリエーションを用意します |
それ以外はすべて派生させます。コンポーネントが直接参照するのは16進数の色ではなく、トークンです。ダークモードは、同じトークンに対する2組目の値であり、2組目のコンポーネントではありません。
ニュートラルカラー
黒に近い色と白に近い色を、わずかに暖色または寒色に揃えて使います。純粋な #000 と #fff は強すぎます。背景が #080808 でテキストが #ededed のダークテーマは、#000/#fff の組み合わせが未設定のように見えるのに対し、意図を感じさせます。
実用的なダークカラーセット:
page #080808 · frame #0d0d0d · raised #141414 · hover #161616
line #1c1c1c · line-2 #262626
fg #ededed · fg-2 #9b9b9b · fg-3 #6b6b6b · fg-4 #454545
ライトカラーセット:
page #f2f2f0 · frame #fbfbfa · raised #ffffff · hover #f1f1ef
line #ebebe8 · line-2 #dcdcd8
fg #151515 · fg-2 #5f5f5c · fg-3 #8d8d89 · fg-4 #b8b8b3
意図的に、色の段階ごとの差は小さくします。表面間の明度差は2~4%で十分です。これなら、縞模様のようにならずに目で区別できます。スクリーンショットを撮って目を細めて見てみましょう。パッチワークではなく、構造が見えるはずです。
ニュートラルカラーを生成するときは、OKLCH で作成します。そうすれば、明度を変えても色相を一定に保ちながら、知覚上均等な段階を作れます。
ダークモードはライトモードの反転ではありません
- ライトモードでは、影で要素を浮き上がらせます。ダークモードでは、より明るい表面と境界線で浮き上がらせます。
#0d0d0d上の影は見えません。 - ダークな表面には、上から光が当たっているように見せるため、白を4%にした1pxの内側上部ハイライトを加えます:
box-shadow: 0 1px 0 rgba(255,255,255,.04) inset。 - 彩度の高い色は、ダークモードでは光って見えます。ダークモードではアクセントカラーの彩度を10~20%下げ、明度も下げます。
- 真っ黒に純白のテキストを置くと、ちらついて見えます。両方とも強さを抑えます。
- 画像やイラストは、わずかに暗くする(
opacity: .9)か、ダークモード用のバリエーションが必要な場合があります。 - フォームコントロール、スクロールバー、ブラウザー UI の色を揃えるため、ルート要素に
color-scheme: darkを指定します。
境界線と影
| テーマ | カード/ポップオーバーの縁 |
|---|---|
| ダーク | border: 1px solid var(--line-2) と内側のハイライト。浮遊するレイヤーに限り、柔らかな外側の影を使用します:0 12px 40px -12px rgba(0,0,0,.9) |
| ライト | box-shadow: 0 1px 0 rgba(255,255,255,.9) inset, 0 12px 32px -14px rgba(0,0,0,.18)。表面が同じ色の上にある場合に限り、境界線を使います |
影は、ぼかしを弱め、負のスプレッドを使い、単一の光源の方向に向けた1層だけにします。0 0 20px のようなグローは使いません。ぼかしを複数重ねたり、プロダクト UI に色付きの影を使ったりすることも避けます。
境界線は1pxです。0.5pxは使いません(描画が一定しないため)。フォーカスリングでない限り、2pxも使いません。
アルファ
背景色が不明な場合のオーバーレイ、ホバー時の塗りつぶし、区切り線にはアルファを使います。そうすることで、どの表面でも機能します。
- ホバー時の塗りつぶし:前景色を4~6%
- 押下時の塗りつぶし:前景色を8~10%
- 区切り線:前景色を8~12%
- ダイアログ背後のバックドロップ:ページの色を60~70%にし、
backdrop-filter: blur(4px)は最大でもこの程度にします - ガラス状の表面(
backdrop-filter)はコストが高いため、1画面につき1つだけにします。アニメーションさせず、入れ子にもできません
アクセントカラー
色相はひとつだけです。主要なボタン、ニュートラルなリングでは弱すぎる場合のフォーカスリング、本文中のリンク、コントロールのアクティブ状態に使います。アイコン、見出し、境界線、背景、バッジには使いません。
すべてがアクセントカラーなら、何もアクセントではありません。画面上のアクセントカラーの要素を数えてください。3つを超える場合は、いくつか取り除きます。
状態色は彩度を抑え(信号機のような色ではなく、彩度が約55%の緑など)、必ず単語またはアイコンと組み合わせます。色だけを唯一の手がかりにすることはありません。
コントラスト
- 本文とセカンダリテキスト:背景とのコントラスト比を4.5:1にします。
- 大きなテキスト(18px以上、または14px以上の太字)とUIの境界(アイコン、入力欄の枠線):3:1にします。
- 第三階層のテキストは、インターフェースの利用に必要でない場合に限り、3:1でもかまいません。
- 薄い色(
--fg-4)は装飾用です。情報を載せてはいけません。 - 両方のテーマで確認します。白の上で合格するグレーも、
#0d0d0dの上では不合格になります。
プレースホルダーが唯一のラベルとして機能する場合、テキストとして扱われるため、コントラスト基準を満たす必要があります。常に表示されるラベルを付けるのが望ましいです。
グラデーション、ノイズ、テクスチャ
プロダクトUI:なし、またはページに光源感を与えるため、ヒーロー領域の背後に不透明度2%のごく控えめな放射状グラデーションを1つだけ使います。マーケティング用途では使用できますが、こちらも1つだけにします。
グラデーションにノイズやディザを重ねると、バンディングを隠し、素材感を加えられます。不透明度は3~6%に抑え、大きなPNGではなく小さなSVGをタイル状に使います。
背景のパターン(グリッド、目盛り、ドット)は、--lineの濃さでフレームの背後に配置し、その端で止めます。コンテンツの下には決して敷きません。
選択、フォーカス、スクロールバー
::selection { background: var(--fg); color: var(--frame); }
:focus-visible { outline: 1px solid var(--fg-2); outline-offset: 2px; }
* { scrollbar-width: thin; scrollbar-color: var(--line-2) transparent; }
この3行が、テーマを適用しただけのページと、テーマになじんだアプリとの違いを生みます。
テーマの切り替え
- 初回描画の前に、ストレージと
prefers-color-schemeを読み取るインラインスクリプトでテーマを決めます。間違ったテーマが一瞬表示されるのはバグです。 - 選択を保存し、選択がない場合はシステム設定に従います。
- 切り替えがストロボのようにならないよう、ルートの
background-colorを約400msかけてトランジションさせます。または、トグルから新しいテーマを表示するView Transitionを使います。どちらの場合も、動きを抑える設定では即時に切り替えます。 - どちらのテーマも同等に扱います。チームがダークテーマしか見なければライトテーマは劣化し、その逆も同じです。両方で確認します。
安っぽい表面の兆候
| 兆候 | 修正 |
|---|---|
#000のページに#fffのテキスト | #080808 / #ededed |
| 枠線、影、異なる背景色のすべてが付いたカード | 3つのうち1つ、最大でも2つにする |
光彩の影(0 0 24px accent) | 柔らかな方向性のある影にするか、影をなくす |
| カードごとに異なる色合い | サーフェストークンを1つにする |
| アイコンと見出しにアクセントカラー | ニュートラルカラーにし、アクセントカラーは1つのアクションに使う |
| 「明るく見えるから」という理由でコントラスト比2.5:1のグレーのテキスト | 基準を満たす--fg-2を使い、サイズと太さで階層を表す |
| グラデーションボタン | フラットな塗りつぶし、枠線のみのセカンダリ、ゴーストの第三階層にする |
| ライトテーマと同じ影を使うダークモード | 枠線と内側のハイライトを使う |
カタログから
- Radix Colors — 両方のテーマで、役割ごとに定義されたステップを持つスケールです。
- Open Props — 影とニュートラルカラーの、使いやすいデフォルト値を提供します。
- Realtime Colors — パレットを決める前に、実際のレイアウトで確認できます。
- コントラストチェッカー — 誰かに指摘される前に確認しましょう。
- Dark Mode Design — ダークテーマをうまく取り入れたサイトです。
- fffuel — SVGのノイズや粒状感を生成できます。
- そのほかのリソースはstealth.pm/assetsをご覧ください。