このページの内容

デザインガイドライン

ranui を実際の画面に使う方法です。役割と状態を選び、値はトークンに任せます。

ルールそのものは 2 か所にあり、このページは中身を繰り返さずにそちらへリンクします。どのプロダクトにも通じる方法はデザインガイドに、ranui のトークン・階層・コンポーネントのルールは ranui 実装アダプターにあります。どちらも node_modules/ranui/docs/DESIGN.md に同梱されています。すべてのトークンとその値はデザインシステムに、実行時の上書きはテーマに、ページの構造は情報アーキテクチャにあります。

こんなときに:<r-*> 要素で作る画面の色、余白、文字、奥行き、モーションを選ぶとき。

原則

  1. 個性より明快さを。 まず、主たるタスクと主たるアクションを疑いようのないものにします。
  2. 既存のコントロールを再利用する。 r-button、r-input、r-select、r-modal はフォーム・キーボード・アクセシビリティの動作をすでに備えています。作り直さず、スタイルを変えてください。
  3. 役割と状態で決める。 「このテキストは何か」には答えがありますが、「どの大きさが良く見えるか」には答えがありません。役割に対応するトークンが値を決め、その値はテーマにも追随します。
  4. たどり着けるすべての状態を設計し、結果を見る。 既定の状態は 8 つのうちのひとつにすぎず、誰にも見えない影はブラウザーで見て初めてわかります。

これらは出発点です。画面が良くなるなら外れてもかまいません。そのときは理由を書いてください。

色の選び方

ホバーとアクティブの見た目ははしごがすでに決めています。あなたの仕事は役割に名前を付けることです。

この要素は… 使うもの
ページや面の背景 --ran-color-bg / -bg-subtle / -bg-elevated / -bg-muted
ポインターの下/押されている --ran-color-bg-hover / -bg-active
テキスト --ran-color-text / -text-secondary / -text-disabled
境界線 --ran-color-border / -hover / -active
この画面が存在する理由のアクション --ran-color-primary(その上に --ran-color-primary-text)
状態 --ran-color-success / -warning / -danger
リンク --ran-color-link

アクセントの意味はひとつずつ。 プライマリはモノクロなので、青はリンクとフォーカスリングのために残してあります。緑は成功、琥珀は警告、赤は危険です。強調に赤を使うと、あとで「危険」を伝える色がなくなります。

生の 16 進数、テーマに合わせて切り替わらないフォールバック、存在しないトークンを指すフォールバックは、ダークモードで気づかないうちに崩れるか、宣言全体を無効にします。それぞれの理由はアダプターの色のルールが説明しており、ranui 自身のソースでは verify:design がこれらを検出します。

余白とリズム

余白は 4px スケールから取り、距離に意味を持たせてください。

  • グループ内の要素どうしは 8px。
  • グループどうしは 16px。
  • 領域どうしは 24〜32px。

余白が小さいほど関係が近いことを表すので、スケールから外れた余白がひとつあるだけでリズムが崩れます。それぞれの余白の持ち主はひとつにしてください。子のマージンと親のパディングを数えてから、そのあいだに 3 つ目の余白を足すかどうかを決めます。

文字の選び方

そのテキストが担う役割(見出し、ラベル、本文、ボタン、等幅)を問えば、フォント・大きさ・太さ・行間はタイプスケールから決まります。動画上のジェスチャー表示のように本当に一度きりのテキストは、いちばん近い役割に押し込むより、専用のコンポーネントトークンを持たせたほうがうまくいきます。

奥行き:影と重なり

影の段階は、その要素が何であるかで選びます。流れの中の面か、浮かぶオーバーレイか、操作を遮るダイアログか。カードの段階にフォールバックしたオーバーレイは、ページに貼り付いて見えます。

自分の外枠に ranui のオーバーレイを埋め込むとき。 z-index のはしごは 1000 から始まるので、ポータルされたオーバーレイは普通のページの外枠を自力で越えます。ただし自分のシャドウ DOM の中に留まる position: fixed のオーバーレイ(r-modal のダイアログ)は、いちばん近い祖先のスタッキングコンテキストまでしか抜け出せません。埋め込んだ内容をスタッキングコンテキストを作るもの(isolation、opacity < 1、transform、filter、will-change)で包む場合は、オーバーレイが実際に開いているあいだだけ、その包みを引き上げてください。

.embed {
  isolation: isolate; /* cheap: no z-index of its own, so nothing is promoted */
}
/* Escalate only while a real overlay is open — never "just in case" */
.embed:has(r-modal[open]),
.embed:has(r-modal[closing]) {
  position: relative;
  z-index: 100;
}

包みに常時 z-index を付けると、静的な内容も含めた中身すべてが、スクロールしているあいだずっとスティッキーヘッダーの上に重なります。このサイトでも一度そのまま公開してしまいました。open だけでなく closing にも一致させてください。マスクは閉じるトランジションのあいだも描画され続けます。

モーション

頻繁なフィードバック(ホバー、フォーカス、押下)は即時です。モーションで変化を説明するときは、フィードバックは 0〜100ms、入るときは 250〜400ms で減速し、出るときは 150〜200ms で加速します。中断できるようにし、prefers-reduced-motion を尊重してください。

色のプロパティを決してトランジションさせないこと。 CSS は色がなぜ変わったのかを知りません。だから background-color、color、border-color、box-shadow、fill、stroke に付けた transition はテーマが切り替わったときにも発火し、ページはもう切り替わっているのに、各要素がそれぞれのペースでフェードします。代わりに transform と opacity をアニメーションさせてください。transition: all や素の transition: 0.2s も色を含みます。

状態と文言

たどり着けるすべての状態がデザインの一部です。ホバー、アクティブ、フォーカス、無効、読み込み中、空、エラー。ホバーは bg-hover / border-hover、アクティブは bg-active、フォーカスはフォーカスリングに対応します。クリックできないものをクリックできるように見せないでください。r-card がホバーに反応するのは hoverable があるときだけです。

文言もシステムの一部です。

  • ボタンは結果を示し、文脈で対象がわからなければ対象も書きます。「メンバーを削除」。対象がはっきりしたダイアログなら「削除」で十分です。汎用的な「OK」は避けます。
  • エラーは何が起きたかを述べ、次にどう直すかを述べます。✅「ビルドに失敗しました。バンドルがサイズ上限を超えています。減らすか、上限を引き上げてください。」❌「操作に失敗しました。もう一度お試しください。」
  • 確認の通知は成功ではなく変化を伝え、変化が確定してから表示します。✅「プロジェクトを削除しました」❌「操作に成功しました」。
  • 文脈に冗長さを取り除かせてください。「プロジェクトを削除」というタイトルのダイアログに、「プロジェクトを永久に、完全に削除する」というボタンは要りません。

アクセシビリティ

  • テキストと背景のコントラストは WCAG AA を満たすこと。
  • 状態を色だけで示さないこと。 アイコン、ラベル、テキストと組み合わせます。
  • すべての操作できる要素は見えるフォーカスリングを保つこと(--ran-focus-ring、または outline: 2px solid var(--ran-color-focus); outline-offset: 2px)。
  • すべてキーボードで到達できること。
  • prefers-reduced-motion と prefers-color-scheme を尊重すること。

マウスとタッチ、狭い画面と広い画面

入力方式もビューポートも、どちらかが二の次ということはありません。

  • ドラッグ、スライダー、ジェスチャーは Pointer Events を使い、ドラッグする面そのものに touch-action: none を付けます。ポインターのハンドラーを伴わない touch-action: none は壊れたコントロールです。
  • ホバーでしか現れない手がかりには、タップの代替が要ります。 r-select や r-popover の trigger="hover" はタッチデバイスではクリックになります。自分で作るものも同じようにしてください。
  • ブレークポイントを発明するより、ビューポート相対の寸法(min(560px, calc(100vw - 32px))、clamp())を選んでください。ranui にはブレークポイントのトークンがないので、決め打ちのブレークポイントはどれも、誰かが保守し続ける数字になります。
  • モバイルで、それをする唯一の方法を隠さないこと。 代わりに回り込ませます。
  • 測った位置が正しいのは、次のリフローまでです。 getBoundingClientRect() から導いたものは、リサイズで、コンテナのリフローで、そして(ポータルされたパネルなら)スクロールで古くなります。狭い幅でページを読み込んでも、その幅へリサイズすることは試せていません。壊れるのはそこです。

ライブラリが機械的に強制していること

pnpm -F ranui verify:design は ranui 自身のソースで 9 つのルールを確かめます。テーマに合わせて切り替わらない色のフォールバック、生の色リテラル、余白と寸法のスケール、マウス専用のドラッグ、hidden を壊す :host の規則、宣言されていないトークンを指すフォールバック、自分のシャドウツリーを探すコンポーネント、コンストラクターの外で作られたシャドウツリーです。意図してルールを破る行には design-ok: <rule> <reason> と書きます。チェックの対象は設定されたソースのルートだけです。ranui を使うアプリは自分でチェックを走らせ、自分のページを見て確かめてください。

デザインの図解

ranui の基本トークンで描いた模式図で、実際のコンポーネントではありません。

行の位置を揃える

ある行に内容が増えても、テキストの開始位置と操作ボタンの列を他の行と揃えます。

行の位置を揃えるある行に内容が増えても、テキストの開始位置と操作ボタンの列を他の行と揃えます。

内外の角丸を揃える

内外の境界が必要な場合は、外側の半径から内側への余白を引きます:16 − 4 = 12。円弧の中心が揃い、間隔が均一に見えます。

--ran-radius-lg − --ran-space-1 = --ran-radius-md
内外の角丸を揃える内外の境界が必要な場合は、外側の半径から内側への余白を引きます:16 − 4 = 12。円弧の中心が揃い、間隔が均一に見えます。 16 − 4 = 12

小さなアイコンを押しやすくする

16px のアイコンに 32px のクリック領域を設け、押しやすくします。領域の大きさはマウスやタッチなどの入力方法に合わせ、隣の領域との間隔を確保します。

--ran-size-1 · --ran-size-7
小さなアイコンを押しやすくする16px のアイコンに 32px のクリック領域を設け、押しやすくします。領域の大きさはマウスやタッチなどの入力方法に合わせ、隣の領域との間隔を確保します。 16px 32px

証拠と受け入れ

実際のブラウザーで何を確かめ、何を報告するかは、ガイドの変更を検証するにあります。観察したこと、推測しただけのこと、確かめられなかったことを分けて報告します。agent のレビューはユーザーの受け入れではありません。