Novi UI

Raster

ミニマル / スイス系。面は平らに保ち、余白と 1px の線と明度差で階層を作ります。 角丸は控えめな3段だけ、影は浮いている層だけ。 ごまかしの道具を最小限に絞ってあるぶん、余白と整列の精度がそのまま出ます。

すべて数値で決まっています

「ミニマル」を感覚で運用すると必ずブレます。目分量で近い値を書かず、この値を使ってください。

controlHeights
sm: 32 / md: 40 / lg: 48
radii
none: 0px / sm: 6px / md: 8px / lg: 12px / full: 9999px
text
xs: 12px / sm: 14px / base: 16px / lg: 20px / xl: 24px / 2xl: 30px / 3xl: 36px
motion
duration-fast: 120ms / duration-base: 120ms / duration-slow: 120ms / ease-standard: cubic-bezier(0.2, 0, 0, 1) / ease-emphasized: cubic-bezier(0.2, 0, 0, 1)

角丸は3段だけ

小さな部品は sm、ボタンや入力は md、メニューやダイアログなど浮く面は lg が既定です。 これ以上丸くすると「丸い」が主張になり、ミニマルの範囲を出ます(ADR-R8)。

Raster の角丸トークン
CSS 変数値
--novi-radius-none0px
--novi-radius-sm6px
--novi-radius-md8px
--novi-radius-lg12px
--novi-radius-full9999px

影は浮いている層だけ

カードや入力といった面は平らなままで、境界線と背景色の差で階層を作ります。 影を持つのはメニュー・ポップオーバー・ ダイアログ・トーストといった浮いている層だけです。低い不透明度の柔らかい影が「浮いている」という事実だけを伝え、 装飾としては働きません。

Raster の影トークン
CSS 変数値
--novi-shadow-nonenone
--novi-shadow-sm0 1px 2px oklch(15% 0 0 / 0.06)
--novi-shadow-md0 4px 12px oklch(15% 0 0 / 0.1), 0 1px 3px oklch(15% 0 0 / 0.06)
--novi-shadow-lg0 16px 40px oklch(15% 0 0 / 0.16), 0 4px 12px oklch(15% 0 0 / 0.08)

色は明度だけで階層を作ります

中立色は彩度を持ちません。面と文字の階層は明るさの差だけで作ります。 彩度を持つのは意味のある色(primary / success / warning / danger)だけです。

色は `--novi-color-*` の CSS 変数経由でのみ指定する。リテラルの色値は書かない。中立色の chroma は 0 に固定し、面と文字の階層は明度だけで作る。
bg
subtle
border
muted
fg

書いてはいけないクラス

テーマを触る場合の規律です。CI が機械的に検査しているため、違反するとビルドが落ちます。 この一覧は検査スクリプトと同じ定義から作られています。

  • shadow-*(shadow-none とトークン shadow-[var(--novi-shadow-*)] は可)影はトークン経由で、浮いている層だけに使う。面は境界線と背景色の差で表す
  • rounded-md / lg / xl / 2xl / 3xl と任意値の角丸角丸はトークン経由。Raster は sm=6 / md=8 / lg=12px の3段
  • border-2 以上境界線は 1px のみ。面の分割は線の太さでなく余白で行う
  • scale-* / scale-x-* / scale-y-*動きで飾らない。モーションは opacity と translate のみ
  • rotate-* / animate-spin同上。回転は Spinner のみ例外(ADR-R2)
  • リテラルの色値(#fff / rgb() / hsl() / oklch())色は必ず --novi-color-* を経由する。リテラル値を書かない
  • duration-*(--novi-duration-* の任意値を除く)モーションの時間はトークン経由にする
  • 8px 以上の生の余白ユーティリティ(p/px/py/pt/pb/pl/pr/gap-2 以上)余白はトークン経由(--novi-pad-* / --novi-gap-*)。余白がテーマの所有物でないと、各コンポーネントが各自の判断で数値を書き、3モデルが同じ密度に潰れる。8px 未満の微小インセットは部品の位置合わせなので生値を許す

例外

  • spinner.styles.ts は rotate のみ許可 — ローディング表現の代替(点滅・バー往復)は視認性か情報量で劣る(ADR-R2)
  • raster-tokens.ts は literal-color, duration, radius, shadow のみ許可 — トークンの値そのものを定義する唯一の場所。ここだけは「使用」ではなく「定義」
  • color-set.ts は literal-color のみ許可 — カラーセット Print Inks の値を定義する場所(specs/06-tones-and-colors)。raster-tokens.ts と同じ「定義」側
  • textarea.styles.ts は raw-spacing のみ許可 — 縦 padding が入力欄の実効の高さを作っており、Input の h-8 / h-10 / h-12 に対応させてある。pad 語彙に control-y は無く、面の縦余白(16px)を当てると1行入力との高さの連続性が壊れる
  • tabs.styles.ts は raw-spacing のみ許可 — 同上。タブの縦 padding はタブバーの行の高さそのもので、面の縦余白を当てると見出しの帯が本文より重くなる
  • badge.styles.ts は raw-spacing のみ許可 — Badge の左右は文字を囲む最小のインセット。高さ 20〜28px の部品には最小の control-x-sm(12px)でも過大で、pad 語彙のどれにも当てはまらない

動きで飾りません

モーションは opacity と translate だけです。拡大・回転は使いません(Spinner の回転だけが例外です)。 速度は1つに固定してあり、prefers-reduced-motion が有効なときはアニメーションを行いません。

Raster のモーショントークン
CSS 変数値
--novi-duration-fast120ms
--novi-duration-base120ms
--novi-duration-slow120ms
--novi-ease-standardcubic-bezier(0.2, 0, 0, 1)
--novi-ease-emphasizedcubic-bezier(0.2, 0, 0, 1)

値を変えたいとき

ここにある値はすべて CSS 変数です。上書きの方法は テーマの調整にあります。