レイアウト
このスキルは、どこに何を配置し、どれだけ離し、どれだけの大きさにするかを決定します。同じ順序で同じ判断を行い、結果をレンダリングされたピクセルと照合します。
いかなる判断の前に、product-ui §1(テイストジャーナルと優先順位)と§5(どのスキルが何を担当するか)を適用してください。
この順序で決定する
- シェル 画面の領域に名前を付けます:サイドバー、ツールバー、コンテンツ、インスペクター。各領域は1つのスクロール所有者またはなしです。詳細と幅:shell-and-responsive.md。 理由:シェルは内部レイアウトが生きるすべての幅を固定します。
- 幅と尺度 コンテンツカラムを保持するものによって設定します:フォーム440px、読み物720px(プローズは
type尺度(66ch)で制限)、データ1200px。カラムは画面が広いからといって伸びることはありません。 理由:75文字を超えると行は読み手を失い、伸びたフォームは視線を画面全体に散らせます。 - スペース 以下のスケールのみを使用し、それ以外は使いません。最初にスペースでグループ化し、スペースで伝えられない場合にのみ塗りつぶし、次に線を追加します。spacing-and-density.md。
- 配置 共有するエッジを選び、すべてをその上に配置します。1~4pxのずれはバグです。幾何学的に間違って見える場合は光学的に修正します。spacing-and-density.md。
- サイズ 領域の密度を選択し、次にヒットエリアを選択します。spacing-and-density.md。
- 最悪ケースのデータ 完了と呼ぶ前に、最長、最短、欠落、翻訳済み、ロード中のコンテンツに合わせてボックスのサイズを変更します。stability-and-text.md。
- 適応 構造をデバイスではなくコンテナに応答させます。shell-and-responsive.md。
- 測定 2倍でレンダリングし、ギャップとエッジを測定し、ピクセルが示すものを修正します。measure.md。
スケール
1つのスケール、4pxベース。ステップではないスペーシング値を決して記述しないでください。 理由:個別の値(10px、14px、18px)はリズムを見えなくし、維持できなくします。
| トークン | px | 典型的な使用例 |
|---|---|---|
--space-xs | 4 | ラベルとその説明の間;チップ内のアイコンとラベルの間 |
--space-sm | 8 | グループ内のアイテム間;コントロールのパディングブロック |
--space-md | 12 | 枠線付きコントロール間;コントロールのパディングインライン |
--space-lg | 16 | フィールド間;コンパクトカードのパディング |
--space-20 | 20 | カード内のブロック間 |
--space-xl | 24 | グループ間;コンフォータブルカードのパディング |
--space-2xl | 32 | セクション間 |
--space-3xl | 48 | ページの最初のタイトルの上 |
--space-4xl | 64 | ページの最後のブロックの下 |
光学的配置のための1~2pxの微調整のみ、スケール外の値として許可されます。名前を付けます(--play-nudge: 2px)。
リファレンス不要のルール
- スペースでグループ化する グループ間の区切りは、グループ内のギャップの少なくとも2倍以上にします:内部が8pxなら、間は16px以上にします。どこも同じスペーシングだとグループ化があいまいになり、このあいまいさは機能的なバグです。
- 線を追加する前に線を削除する 最初にスペース、次に塗りつぶし、最後に区切り線、そしてそれは高密度データの場合のみです。 理由:すべての線は、スペースが無料で与える同じ情報に対して、注意を消費します。
- 上下のスペースは等しくする 2つのものの間にあるものは、上と下のスペースが等しくなければなりません。 理由:一方の隣接要素に近いものは、その要素に所有されているように見えます。
- コントロールはコントロールのように見えなければならない ボタン、リンク、トグルには形状、下線、またはツールバーの位置があります。静的テキストはこれらを共有してはいけません。 理由:テキストのようにスタイルされたコントロールは隠れ、コントロールのようにスタイルされたテキストは無駄なクリックを集めます。
- アクションは、操作するデータの上に配置する 決して下ではありません。何かを設定するコントロールは、その隣に配置します。
- プライマリコンテンツは先頭かつ先頭揃えにする 視覚的な順序はDOMの順序と同じにします:コンテンツを並び替えるために
order、row-reverse、またはグリッド配置を決して使用しないでください。 理由:キーボードとスクリーンリーダーの順序はDOMに従います。 - 論理プロパティ(
margin-inline-start、padding-block、inset-inline-end、text-align: start)をミラーリングするものすべてに使用します。 理由:RTLが2つ目のスタイルシートなしで機能するようになります。 - 重要なコントロールをウィンドウやサイドバーの下端に決して配置しない 理由:ユーザーはウィンドウを部分的に画面外に押し出します。
- スクロールは隠れたものを示す 端を超えたコンテンツには、16~32pxのチラ見せまたはフェードアウトという、目に見える手がかりを提供します。
- 何もシフトしない ホバー、選択、フォーカスが要素のサイズを変えることはありません。ロードされたデータは、スケルトンが保持していたボックスを引き継ぎます。
ペア(悪い例と修正例)
| 悪い例 | 修正例 | 理由 |
|---|---|---|
フォーム内でgap: 12px、fieldset間でもgap: 12px | 内部はgap: 8px、間はgap: 24px | グループには少なくとも2倍の区切りが必要 |
padding: 10px 14px | padding: var(--space-sm) var(--space-md) | ステップのみ使用 |
| タイトルがx=24、説明がx=26 | 両方ともx=24 | 1~4pxのずれはミスに見える |
アイコンボタン16×16、padding: 0 | 16pxグリフ、::before { inset: -12px }で40pxターゲット | マウスターゲットは40px |
.row + .row { margin-top: 8px }、行にホバーとクリックあり | .row { padding-block: 4px }、マージンなし | 行間のギャップはデッドゾーンであり、ホバーがちらつく |
.menu { width: 200px } | width: max-content; min-width: 160px; max-width: 320px | メニューは最長のラベルに合わせる |
カードに@media (max-width: 768px) | カードの親に@container (width < 400px) | 狭いサイドバー内のカードは画面幅ではなく、自身の幅が必要 |
サイズ指定なしの<img src>、その後カードがジャンプする | width、height、またはaspect-ratioを設定 | ボックスはバイトより先に存在する必要がある |
| スティッキーヘッダー、アンカーがその下に来る | スクローラーにscroll-padding-block-start: 56px | フォーカスとアンカーがクロームの下に来ない |
終了前に
diffで以下を検索し、確認してください。
| パターン | 修正 |
|---|---|
margin、padding、またはgapにスケール外の値 | 最も近いステップに変更 |
グループ内とグループ間で同じgap値 | グループ内 ≤ グループ間の半分 |
アイコンのみのボタンが24px未満、または::beforeなしで40px未満 | 疑似要素で拡張 |
クリック可能な行やメニュー項目の間のgapまたはmargin | 項目内のパディング |
メニュー、ボタン、テキストボックスに固定のwidth | max-content、min-width、max-widthを使用;テキストにはmin-height |
再利用可能なコンポーネント内の@media (max-width | その親に@container |
シェルにheight: 100vh | 100dvh |
長いテキストを保持する1frトラックまたはフレックス子 | minmax(0, 1fr) または min-width: 0 |
ミラーリングされたUIでのmargin-left、padding-right、left: 0、text-align: left | 論理形式に変更 |
scroll-padding-blockなしのスティッキーヘッダーまたはフッター | クロームの高さに設定 |
| スケルトンの行の高さや列の幅がロード後と異なる | 一致させる |
寸法またはaspect-ratioのない<img> | 追加する |
measure.mdで検証:390pxとシェルの最大幅で2倍レンダリングし、スクリプトを実行し、各候補をクロップしてピクセル数をカウントします。次に、スティッキークロームを配置した状態で画面をTab移動し、最長の文字列をロードします。確認できなかったものは「未確認」として報告してください。