結論

プロは余白を感覚で置かない。まず「8の倍数(8/16/24/32/48…)」をトークン化して全 padding・margin・gap をそれに吸着させ、細部だけ 4px のハーフステップを許す。その上で「内側の余白 ≤ 外側の余白(internal ≤ external)」を絶対ルールにしてグルーピングを成立させ、上に行くほど刻みが粗くなる非線形スケールで目分量を排除する。「なんとなく」が消えるのは、この3点を仕組みにした時だけだ。

01 — 余白を8の倍数トークンに吸着させる

7px・13px・15px・20px のような任意値を都度入力すると、開発者ですら「13px だったか 14px だったか」を再現できず、全体の整合が崩れて安っぽく見える。dimensions / padding / margin / gap を 8・16・24・32・40・48… に限定し、選択肢を減らすことが一貫性の正体だ。Material / Atlassian / InVision が共通で採る業界標準で、root 16px なら 0.5rem = 8px に一致する。

7px
13px
6px
15px
✗ スケール外の任意値を目分量で → 不揃いで再現不能
16px
16px
16px
✓ 8の倍数(16px)に吸着 → 揃って意図が読める

primarySpacing, grids, and layouts — InVision

primarySpacing methods — Material Design

02 — internal ≤ external でグループを成立させる

「曖昧な余白」は素人っぽさの最大要因だ。グループ内の隙間がグループ間より広いと近接の法則が壊れ、どこからどこまでが1つの塊かが読めなくなる。最も典型的なのが、ラベルが「自分の入力欄」より「上のフィールド」に近いフォーム。ある塊の padding(内側)を、その塊を隣から隔てる margin(外側)以下に保つ——この単一ルールだけで近接が成立する。

氏名
メール
✗ ラベルが自分の入力欄より前のフィールドに近い → 塊が読めない
氏名
メール
✓ 内側4px < 外側20px → ラベルが入力欄に属して見える

blogSpacing best practices — Cieden

blogNotes from 'Refactoring UI' — Gist

03 — 非線形スケール+隣接は最低約25%差

4・8・12・16・…・60・64 のように大きい値まで等間隔で刻むと、16→20px は +25% でも 240→256px は +6.7%。大きい値ほど隣接差が知覚できず、無意味なトークンが量産されて決定疲れを生む。正解は数学的等比ではなく、手で選んだ知覚的に均等な値 = 4/8/12/16/24/32/48/64/96/128px。下は細かく、上は粗く。隣り合う2値は約25%以上離す(近すぎると選べない)。

4812162024
✗ 線形(+4等間隔) → 上ほど差が消え冗長
4816244896
✓ 非線形(隣接 ≥ 約25%差) → 各段に意味がある

blogNotes from 'Refactoring UI' — Gist

blogStop Guessing UI Spacing — Lince Mathew

04 — 要素の大小に合わせて余白も変える

見出しも本文も同じ margin、カードもバッジも同じ padding——一律にすると階層が出ない。余白は「関係性」を表すものであり、大きい要素ほど周囲の余白も大きくするのが原則だ。用途別レンジで割り当てる:Small 0–8px=密結合/アイコン↔テキスト、Medium 12–24px=コンテナ内の別要素、Large 32–80px=セクション区切り。関連が近いほど小さく、無関連ほど大きく(Gestalt 近接)。

見出し
本文テキスト
✗ 見出しも本文も同じ高さ・同じ余白 → 階層なし
見出し
本文テキスト
✓ 大きい要素ほど余白も大きく(8→24px) → 階層が立つ

primarySpacing — Atlassian Design

blogStop Guessing UI Spacing — Lince Mathew

05 — vertical rhythm:line-heightを8(または4)の倍数に固定

font-size はデバイスで 14/15/18/21px と変動してよいが、line-height を 8 の倍数(8/16/24/32、許容で 4 の倍数の 20/24/28)に固定すると、テキストブロックの高さが 8px グリッドに乗り、縦のリズムが揃う。タイポ系と余白系が同じ数列で整合するのがポイント。1.45 のような端数倍率はグリッドから外れ、行ごとに微妙にズレる。

見出し

端数のline-heightで
行が赤グリッドから
少しずつズレる

✗ line-height:1.45 等の端数 → 8pxグリッドに乗らない
見出し

line-heightを24pxに
固定すると各行が
グリッド線に乗る

✓ line-height:24px 固定 → 行が赤グリッドに整列

blog8-Point Grid: Typography On The Web — freeCodeCamp

primarySpacing, grids, and layouts — InVision

06 — まず多すぎる余白から入れて削る

Web は構造上どうしても余白不足になりがちだ。詰めた状態から足していくと窮屈なまま固定されてしまう。逆に、最初に過剰なほど余白を入れて満足するまで削る方が、破綻が見えやすく速い。下の例は同じ要素で密度だけを変えたもの——「ケチって始める」より「盛って削る」が正解だ。

行1
行2
行3
✗ under-add:最初から詰める → 窮屈なまま固定される
行1
行2
行3
✓ まず余白を盛り、満足するまで削る → 呼吸できる

blogPrinciples of Design: Negative Space — UX Engineer

実装スニペット

非線形 8px スケールを CSS custom properties で定義する(Refactoring UI 流)。20px や 36px のような中間値はスケールに無い限り使わない。

:root {
  /* 下は細かく、上は粗く(隣接 ≥ 約25%差) */
  --space-1: 4px;   /* 密結合: アイコン↔テキスト */
  --space-2: 8px;   /* 関連要素・コンポーネント内 */
  --space-3: 12px;  /* 4px half-step */
  --space-4: 16px;  /* 標準gap・カードpadding */
  --space-6: 24px;  /* コンテナ内の別要素 */
  --space-8: 32px;  /* セクション区切り */
  --space-12: 48px; /* ページセクション */
  --space-16: 64px; /* heroの余白 */
  --space-24: 96px;
  --space-32: 128px;
}

internal ≤ external を守ったカード+フォーム。内側 4px < 外側 24px で近接が成立する。

.card {
  padding: var(--space-4);       /* 内側=16px */
  margin-bottom: var(--space-8); /* 外側=32px(内側より大) */
}
/* ラベルは自分の入力欄に近づけ、前のフィールド群から離す */
.field { margin-bottom: var(--space-6); }        /* グループ間=24px */
.field label { margin-bottom: var(--space-1); }  /* グループ内=4px */
.field input { display: block; width: 100%; }

vertical rhythm:line-height を 8 の倍数に固定し、余白も 8px で刻む。縦 margin は rem、横 padding は px が原則。

body { font-size: 1rem; }                                            /* 16px */
h2   { font-size: 1.5rem;   line-height: 32px; margin: 48px 0 16px; }
p    { font-size: 1.125rem; line-height: 24px; margin: 0 0 24px; }   /* 18/24 */
small{ font-size: 0.875rem; line-height: 20px; }                     /* 14/20 */

px / rem の使い分け + タッチターゲット最小 48×48px・間隔 8px(Material)。

.btn {
  font-size: 1rem;       /* rem: 文字拡大に追従 */
  min-height: 48px;      /* px: タッチターゲット最小 */
  padding: 12px 24px;    /* 横paddingはpx */
  margin-bottom: 1.5rem; /* 縦marginはrem=24px */
  border: 1px solid;     /* borderはpx */
}
.btn + .btn { margin-left: 8px; } /* 隣接ターゲット間 ≥ 8px */

チェックリスト

  • すべての padding / margin / gap が 8 の倍数(8/16/24/32/48…)に乗っているか。細部の調整だけ 4px ハーフステップに留めているか。
  • 7px・13px・15px・20px などスケール外の任意値が紛れていないか。
  • どの塊も internal ≤ external か(padding ≤ それを隔てる margin)。グループ内 < グループ間になっているか。
  • ラベルが「上のフィールド」より「自分の入力欄」に近いか。
  • スケールは非線形で、隣り合う2値が約25%以上離れているか。大きい値の等間隔トークンを乱発していないか。
  • 大きい要素ほど周囲の余白も大きいか(一律 margin になっていないか)。
  • line-height が 8(許容で 4)の倍数で、テキストブロックが縦グリッドに乗っているか。
  • font-size と縦 margin は rem、横 padding と border は px にしているか。
  • タッチターゲットは最小 48×48px、隣接間 8px 以上あるか。
  • 「ケチって始めて」いないか。まず盛って削ったか。

限界 / 出典

正直な但し書き:「主要解像度が8で割り切れる」という8px採用の根拠は spec.fm の主張で、デバイスが多様化した現在は装飾的理由に近い(本質は選択肢を減らす一貫性)。internal ≤ external のうち「padding ≤ margin」という厳密な不等式は Cieden の定式化で、Refactoring UI の原文は「グループの周囲の余白 > 内側の余白」とより緩い。px vs rem 指針は Josh Comeau 個人の推奨で、固定サイズのバナーでは px 中心で問題ない。NYT 見出し:本文比 2:1 は Medium 記事の引用で一次確認は未取得。25%差・非線形は知覚則であって厳密な閾値ではなく目安。Tailwind 新スケールやトークン命名3方式の一部はブログ/Discussion の提案段階で、一次規格ではない(中核の 8px グリッドと Material/Atlassian/InVision のトークンは一次ソース)。

secondaryNotes from 'Refactoring UI' — GitHub Gist

blogSpacing best practices — Cieden

primaryOverview - Spacing — Atlassian Design

primarySpacing methods — Material Design

primarySpacing, grids, and layouts — Design Systems by InVision

primaryThe Surprising Truth About Pixels and Accessibility — Josh Comeau

secondary8-Point Grid: Typography On The Web — freeCodeCamp

secondary8-Point Grid — spec.fm

blogBasics: Spacing systems & scales in UI design — Designary

blogStop Guessing UI Spacing — Lince Mathew (Medium)

primaryA new default spacing scale · Tailwind Discussion #12263

blogPrinciples of Design: Negative Space — UX Engineer