アクセシブルで高速、快適なUIを構築するための簡潔なルールです。意思決定の指針として、MUST(必須)/SHOULD(推奨)/NEVER(禁止)を使用します。
インタラクション
キーボード
- MUST: WAI-ARIA APG に従った完全なキーボードサポート
- MUST: 可視で隠されていないフォーカスリング(
:focus-visible;:focus-withinとグループ化)。スティッキー/固定要素はフォーカスを覆わないこと - MUST: APGパターンに従ったフォーカス管理(トラップ、移動、復帰)
- NEVER: 可視のフォーカス代替がない状態での
outline: none
ターゲットと入力
- MUST: ヒットターゲット ≥24px(モバイル ≥44px)。視覚サイズが24px未満の場合はヒット領域を拡大する
- MUST: モバイル
<input>の font-size ≥16px(iOSのズームを防ぐため) - NEVER: ブラウザのズームを無効にする(
user-scalable=no、maximum-scale=1) - MUST:
touch-action: manipulationでダブルタップズームを防止 - SHOULD:
-webkit-tap-highlight-colorをデザインに合わせて設定
フォーム
- MUST: ハイドレーションセーフな入力(フォーカス/値の喪失なし)
- NEVER:
<input>/<textarea>でのペーストをブロックする - MUST: ローディングボタンはスピナーを表示し、元のラベルを維持する
- MUST: Enterキーでフォーカスされた入力を送信。
<textarea>では、⌘/Ctrl+Enterで送信 - MUST: リクエストが開始されるまで送信ボタンを有効にしておく。開始後はスピナーとともに無効化
- MUST: 自由テキストを受け入れ、後から検証する。タイピングを妨げない
- MUST: 不完全なフォーム送信を許可し、検証エラーを表面化させる
- MUST: エラーはフィールドの横にインラインで表示。送信時に最初のエラーにフォーカス
- MUST:
autocomplete+ 意味のあるname。正しいtypeとinputmode - SHOULD: メールアドレス/コード/ユーザー名のスペルチェックを無効にする
- SHOULD: プレースホルダーは
…で終わり、例のパターンを示す - MUST: 未保存の変更がある場合、ナビゲーション前に警告
- MUST: パスワードマネージャーと2FAとの互換性。コードのペーストを許可
- MUST: テキスト拡張による末尾スペースを処理するため、値をトリムする
- MUST: チェックボックス/ラジオにデッドゾーンがないこと。ラベルとコントロールで1つのヒットターゲットを共有
状態とナビゲーション
- MUST: URLが状態を反映する(ディープリンクフィルター/タブ/ページネーション/展開パネル)
- MUST: 戻る/進むでスクロール位置を復元
- MUST: リンクは
<a>/<Link>を使用してナビゲーション(Cmd/Ctrl/ミドルクリックをサポート) - NEVER: ナビゲーションに
<div onClick>を使用
フィードバック
- SHOULD: 楽観的UI。レスポンス時に調整。失敗時はロールバックまたは元に戻す(Undo)を提供
- MUST: 破壊的なアクションの確認、または元に戻す(Undo)ウィンドウの提供
- MUST: トースト/インライン検証には polite な
aria-liveを使用 - SHOULD: フォローアップを開くオプション(「名前を変更…」)やローディング状態(「読み込み中…」)には省略記号(
…)を使用
タッチとドラッグ
- MUST: 十分なサイズのターゲット、明確なアフォーダンス。繊細なインタラクションを避ける
- MUST: 最初のツールチップは遅延表示。後続の同種ツールチップは即時表示
- MUST: モーダル/ドロワーでは
overscroll-behavior: contain - SHOULD: ページのラバーバンドバウンスを抑制する場合、
@media (pointer: fine)内で<html>にoverscroll-behavior: noneを設定。粗いポインターデバイスのページデフォルトではプル・トゥ・リフレッシュを維持。ハイブリッドタッチ端末でテスト:pointerはプライマリ入力を記述し、noneはスクロールチェーンとネイティブスワイプナビゲーションも無効にする - MUST: ドラッグ中はテキスト選択を無効にし、ドラッグ要素に
inertを設定 - MUST: ドラッグ/スワイプ/ピンチ/パスジェスチャーには、必須でない限り、タップ/クリックとキーボードの代替手段を用意
- MUST: クリック可能に見えるものは、クリック可能でなければならない
オートフォーカス
- SHOULD: デスクトップでは単一のプライマリ入力にオートフォーカス。モバイルでは稀
アニメーション
- MUST:
prefers-reduced-motionを尊重(縮小版を提供するか、無効にする) - SHOULD: CSS > Web Animations API > JSライブラリ の優先順位
- MUST: コンポジターに適したプロパティ(
transform、opacity)のみアニメーション - NEVER: レイアウトプロパティ(
top、left、width、height)をアニメーション - NEVER:
transition: all— プロパティを明示的に列挙 - SHOULD: 原因/効果を明確にするため、または意図的な楽しさを加えるためにのみアニメーション
- SHOULD: 変化(サイズ/距離/トリガー)に合わせたイージングを選択
- MUST: アニメーションは中断可能で、入力駆動型。自動再生はミュートされた非必須ループのみ
- MUST: 他のコンテンツと一緒に5秒を超える自動再生モーションには、一時停止、停止、または非表示コントロールを用意
- MUST: 正しい
transform-origin(モーションは「物理的に」開始されるべき場所から始まる) - MUST: SVGトランスフォームは
transform-box: fill-boxを持つ<g>ラッパーで
レイアウト
- SHOULD: 光学的な位置合わせ。幾何学よりも知覚が優先される場合、±1px調整
- MUST: グリッド/ベースライン/エッジへの意図的な位置合わせ。偶然の配置は不可
- SHOULD: アイコン/テキストのロックアップをバランスよく(ウェイト/サイズ/間隔/色)
- MUST: モバイル、ノートパソコン、ウルトラワイドで確認(ウルトラワイドは50%ズームでシミュレート)
- MUST: セーフエリアを尊重(
env(safe-area-inset-*)) - MUST: 不要なスクロールバーを避け、オーバーフローを修正
- SHOULD: レイアウトにはJS測定よりもFlex/グリッドを優先
コンテンツとアクセシビリティ
- SHOULD: まずインラインヘルプ。ツールチップは最後の手段
- MUST: スケルトンはレイアウトシフトを避けるため、最終コンテンツを反映
- MUST:
<title>が現在のコンテキストと一致 - MUST: 行き止まりなし。常に次のステップ/回復を提供
- MUST: 空/疎/密/エラー状態をデザイン
- SHOULD: カギ括弧を使用 (“ ”)。ウィドウ/オーファンを避ける(
text-wrap: balance) - MUST: 数値比較には
font-variant-numeric: tabular-nums - MUST: 冗長なステータスキュー(色だけに依存しない)。アイコンにはテキストラベル
- MUST: アクセシブルな名前は、ビジュアルがラベルを省略している場合でも存在する
- MUST:
…文字を使用(...ではない) - MUST: 見出しに
scroll-margin-top。「スキップナビゲーション」リンク。階層的な<h1>–<h6> - MUST: ユーザー生成コンテンツに対して堅牢(短い/平均的/非常に長い)
- MUST: ロケールを認識した日付/時刻/数値(
Intl.DateTimeFormat、Intl.NumberFormat) - SHOULD: ブランド名、コードトークン、識別子には
translate="no"を設定し、自動翻訳による文字化けを防止 - MUST: 正確な
aria-label。装飾要素はaria-hidden - MUST: アイコン専用ボタンには説明的な
aria-label - MUST: ARIAよりもネイティブセマンティクス(
button、a、label、table)を優先 - MUST: メディアには該当する場合はキャプション/トランスクリプト/説明。コントロールはキーボード操作可能。装飾メディアは支援技術から隠す
- MUST: 改行しないスペース:
10 MB、⌘ K、ブランド名
コンテンツ処理
- MUST: テキストコンテナは長いコンテンツを処理(
truncate、line-clamp-*、break-words) - MUST: Flexの子要素はトランケーションを可能にするために
min-w-0が必要 - MUST: 空の状態を処理。空文字列/配列でUIが壊れない
パフォーマンス
- SHOULD: iOS Low Power Mode と macOS Safari でテスト
- MUST: 信頼性の高い測定(ランタイムを歪める拡張機能を無効にする)
- MUST: 再レンダリングを追跡し最小化(React DevTools/React Scan)
- MUST: CPU/ネットワークスロットリングでプロファイリング
- MUST: レイアウトの読み取り/書き込みをバッチ処理。リフロー/再描画を避ける
- MUST: ミューテーション(
POST/PATCH/DELETE)は <500ms を目標 - SHOULD: 非制御入力(uncontrolled inputs)を優先。制御入力(controlled inputs)はキーストロークごとに安価であること
- MUST: 大規模リスト(>50項目)は仮想化
- MUST: アバブ・ザ・フォールド画像は事前読み込み。残りは遅延読み込み
- MUST: CLSを防止(明示的な画像寸法)
- SHOULD: CDNドメインには
<link rel="preconnect"> - SHOULD: 重要なフォント:
<link rel="preload" as="font">とfont-display: swap - SHOULD: アニメーションGIFの代わりに
<video autoplay muted loop playsinline>。静止画/縮小モーションの代替を提供 - SHOULD: 短い非必須ループには、Safari H.264 MP4
<picture>ソース、prefers-reduced-motionメディアクエリ、および静止画フォールバックを含める
ダークモードとテーマ設定
- MUST: ダークテーマでは
<html>にcolor-scheme: dark - SHOULD:
<meta name="theme-color">がページ背景と一致 - MUST: ネイティブ
<select>:明示的なbackground-colorとcolor(Windows向け修正)
ハイドレーション
- MUST:
valueを持つ入力にはonChangeが必要(またはdefaultValueを使用) - SHOULD: ハイドレーションの不一致を防ぐため、日付/時刻のレンダリングをガード
デザイン
- SHOULD: レイヤー化されたシャドウ(環境光 + 直接光)
- SHOULD: 半透明の境界線とシャドウによる鮮明なエッジ
- SHOULD: ネストされた角丸:子 ≤ 親。同心円状
- SHOULD: 色相の一貫性:境界線/シャドウ/テキストを背景色相に近づける
- MUST: アクセシブルなチャート(色覚障害者に優しいパレット)
- MUST: コントラストを満たす。WCAG 2よりもAPCAを優先
- MUST:
:hover/:active/:focusでコントラストを上げる - SHOULD: ブラウザUIを背景に合わせる
- SHOULD: 暗い色のグラデーションバンディングを避ける(必要な場合は背景画像を使用)