結論
プロは境界を「線」ではなく「余白」で表現し、線は最後の手段として扱う。どうしても線が必要なら 1px・不透明度 12%(rgba(0,0,0,0.12))のヘアラインに抑え、ベタの濃いグレーや太線は使わない。安っぽさの正体は「線が濃すぎる・太すぎる・多すぎる」の3点で、Material Design と Refactoring UI が別角度から同じ結論に到達している。
01 — 線は 1px × 不透明度12% のヘアラインに
安っぽさの第一原因は、線が画面で一番目立ってしまうこと。#888 や #ccc のベタ線はコンテンツより前に出る。Material Design の divider 仕様は厚み 1dp、色は黒12%不透明(rgba(0,0,0,0.12))。CSS に border-opacity は無いので、rgba の低 alpha で低コントラストを作るのが正解。
primaryDividers - Material Design (M1)
02 — 余白ファースト:線は最後の手段
要素を分離するとき、まず余白・box-shadow・2色の背景差を試す。それでも分離できないときだけ divider を足す。余白で足りる場面に線を引くのが「安っぽい」典型例。カードは枠線よりも薄い影で面を持ち上げ、交互セクションは背景色差で区切ると線がゼロで済む。
月額 ¥980
3ユーザーまで
月額 ¥980
3ユーザーまで
blogNotes from Refactoring UI (gist)
primaryCards - Material Design 3
03 — 線を引かず「背景色差」でセクションを区切る
セクション間に毎回フルブリードの線を引くと、Material の言う「visual noise」になり divider の意味が薄れる。独立したセクションは、線ではなく2色の背景差(#fff ↔ #f7f7f8)で分けるとノイズが減って情報の階層が読める。
primaryDividers - Material Design (M2)
04 — 外側余白 > 内側余白でグルーピング
グループは「内側より外側の余白が広い」ときに、線なしでも"まとまり"として読める。この関係が崩れると、線で無理に補おうとして divider が増えていく。まず外側余白を広げ、それで足りない場合だけ最弱(0.08)の線を足す。
blogNotes from Refactoring UI (gist)
05 — 太さと不透明度:細く・薄くが品
divider の標準は 1px のヘアライン。2px 以上の線は装飾過多に見える。色も同様で、不透明な黒のベタは線そのものを浮き上がらせる。「細く・薄く」が上品さの条件。下のスウォッチで黒ベタ(左)と黒12%(右)の差は一目瞭然。
primaryReact Divider component - Material UI
06 — ダーク/トークン対応で 1変数に寄せる
固定の #ccc 系はダークモードで浮く。rgba(0,0,0,0.12) ↔ rgba(255,255,255,0.12) を切り替えれば自然に追従する。デザインシステムなら、divider 色は 4.5:1 を要する outline ではなく低コントラスト専用の outline-variant トークンへ割り当てるのが M3 標準。
primaryColor roles - Material Design 3
実装スニペット
/* 上品なヘアライン divider(Material 12%準拠) */
.divider {
border: 0;
border-top: 1px solid rgba(0, 0, 0, 0.12); /* ライト: 黒12% */
margin: 24px 0;
}
@media (prefers-color-scheme: dark) {
.divider { border-top-color: rgba(255, 255, 255, 0.12); } /* ダーク: 白12% */
}
/* 線なしで分離(box-shadow + 背景色差) */
.card {
background: #fff;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06), 0 1px 1px rgba(0, 0, 0, 0.04);
border-radius: 12px;
}
.section--alt {
background: #f7f7f8; /* 2色の背景差でセクションを区切る(線ゼロ) */
}
/* 余白でグルーピング(外側 > 内側) */
.group {
display: flex;
flex-direction: column;
gap: 8px; /* 内側の余白は狭く */
margin-bottom: 40px; /* 外側の余白は広く=線なしで分離 */
}
.group + .group { /* 線が必要な場合のみ最弱の divider */
border-top: 1px solid rgba(0, 0, 0, 0.08);
}
/* 真のヘアライン(Retina 0.5px) */
.hairline {
height: 1px;
background: rgba(0, 0, 0, 0.12);
}
@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 2dppx) {
.hairline { transform: scaleY(0.5); transform-origin: top; }
}
/* 代替: box-shadow 方式 */
.hairline-shadow { box-shadow: 0 0 0 0.5px rgba(0, 0, 0, 0.12); }
チェックリスト
- その境界、余白・box-shadow・背景色差で代替できないか先に試したか
- 線の色は
rgba(0,0,0,0.12)前後の半透明か(#ccc/#000のベタを使っていないか) - 線の太さは 1px か(2px 以上の rule を装飾で使っていないか)
- 1画面に線が多すぎないか(フルブリード線の乱用=visual noise)
- グループは「外側余白 > 内側余白」になっているか
- 分離強度に応じて full-bleed / inset / middle を使い分けたか
- ダークモードで線が消えていないか(白12%へ反転しているか)
- Retina で 1px が太って見えないか(必要なら 0.5px ヘアライン)
- 入力欄など「操作可能要素の境界」は 12% では不足していないか(3:1 目安を確保)
限界 / 出典
primaryDividers - Material Design (M1)
primaryDividers - Material Design (M2)
primaryColor roles - Material Design 3
primaryCards - Material Design 3
primarymaterial-web divider docs
primaryReact Divider component - Material UI
blogNotes from Refactoring UI (gist)
blog7 Practical Tips for Cheating at Design - Refactoring UI
blog1px Borders CSS