結論

プロは「数字が揃わない」を CSS の font-variant-numeric: tabular-nums(OpenType の tnum)で解く。全桁を同一 advance width にして列の縦揃えとインプレース更新のレイアウトシフトを同時に潰すのが中核だ。揃え方は「数値は右揃え/小数桁が不揃いなら小数点揃え、中央揃えは禁止」、価格は通貨記号も含めて等幅化し、階層はサイズ+色で作る——monospace への逃げと擬似上付きが安っぽさの典型である。

01 — 等幅数字は font-variant-numeric で指定する

既定の数字(proportional, pnum)は桁ごとに字幅が違う。1 は細く 0 は太いため、テーブルやカウンタで列がガタつく。高レベルプロパティ font-variant-numeric: tabular-nums が OpenType tnum にマップし、全桁を同一字幅に揃える。font-feature-settings: "tnum" 1 でも同じトグルだが、同一要素の他の OpenType 機能を上書き(clobber)してしまうので非推奨。Inter / Roboto / SF / Lato / Open Sans は tnum 対応。

項目金額
小計1,118
送料990
合計12,408
✗ proportional のまま → 桁が左右にずれて列が揃わない
項目金額
小計1,118
送料990
合計12,408
✓ tabular-nums → 全桁が同一字幅で縦に揃う

primaryfont-variant-numeric — MDN Web Docs

blogTabular Numbers in CSS — Authon Blog

02 — カウンタ/タイマーのガタつきは tnum で止める(monospace に逃げない)

ストップウォッチやカウントアップは値が更新されるたび桁の字幅差で横にジッタする。これを「揃わないから」と全体を monospace / コードフォントに差し替えるのは過剰な逃げ——質感が丸ごとコード風に変わり、字幅も無駄に広い。既存フォントのまま font-variant-numeric: tabular-nums をかければ、字幅は固定され見た目はそのままだ。

00:01:11
monospace に差し替え
✗ monospace へ逃げる → 質感がコード風、字幅も無駄に広い
00:01:11
既存フォント+tabular-nums
✓ 既存フォントのまま等幅化 → 更新してもガタつかない

blogTabular numbers — Sebastian De Deyne

03 — 数値は右揃え、テキストは左揃え。中央揃えは禁止

数値は右から(一の位→十の位→百の位)読んで比較するため、右揃えだと桁が縦に並んで比較が一瞬で済む。中央揃えは ragged edge(ギザギザの端)を生み、桁ぞろえを破壊してスキャンを阻害する。ヘッダもデータと揃え(数値ヘッダは右、テキストヘッダは左)。本文中の数字は逆に proportional(既定)のままが読みやすく、揃え目的でない箇所に tnum を撒くと窮屈になる。

商品在庫
A7
B340
C28
✗ 中央揃え → 端がギザギザで桁が比較できない
商品在庫
A7
B340
C28
✓ テキスト左/数値右 → 桁が縦に揃いスキャンできる

blogDesign Better Data Tables — Matthew Ström

blogTabular numbers — Sebastian De Deyne

04 — 小数桁が不揃いなら小数点揃えにする

単位が同じでも小数桁がバラバラな列は、右揃えだと桁(magnitude)がずれて 112.75 が誤って隣り合う。小数点で揃えれば多様なデータでも桁が比較できる。CSS Text L4 の text-align: "." right は仕様にあるが2024時点で実装ブラウザは皆無。aria-hidden のダミー span に不可視の小数を足し、visibility:hiddendisplay:none は不可、幅を保持できない)で物理的に桁を揃える。スクリーンリーダは実数だけ読む。

11.512.75340
✗ 右揃えのみ → 小数点の位置がバラバラで桁がずれる
1 1.5 12.75 340
✓ aria-hidden ダミーで小数点揃え → 桁が一列に

blogCharacter-based alignment — CSSence.com

secondaryWeb Typography: Designing Tables to be Read — A List Apart

05 — 価格の通貨記号も等幅にし、階層はサイズ+色で作る

価格を揃えるには数字を lining-nums tabular-nums にするだけでなく、通貨記号も等幅でないと揃いが崩れる。記号は cap height 基準で lining 数字と並ぶよう設計されている。階層は「ウェイトを軽くする」ではなくサイズ+色で作るのが正解——記号のストローク太さは数字のウェイトに合わせ、セントは小さいサイズ+同系色相の低彩度色(灰色にしない)で弱める。通貨記号をエディタの上付きボタンで縮小する擬似 superscript は、人工的に縮小された lining 記号が細く軽く見えて安っぽい。

$1,234.56
✗ 擬似上付きの記号+軽いウェイトのセント → 重さがちぐはぐ
$1,234.56
✓ 記号は同じ太さでサイズ調整、セントはサイズ+低彩度色で従属

primaryCharacter design standards: Figures — Microsoft Typography

secondaryManual: Currency Symbols — type.today

blogBook summary: Refactoring UI — sglavoie.com

06 — 通貨フォーマットはロケール駆動、フィールド幅は全変種に合わせる

記号位置・区切り・小数桁数はロケール固有だ。US は $10.20、仏は 10,00 $ USD(カンマ小数・右記号)、日本/韓国は ¥10,000(小数無)、一部中東通貨は小数3桁。フィールド幅はこの全変種に合わせて設計する。表記規約も押さえる——4桁以上はカンマ、大きな額は K/M/B で略す、負は記号の前にマイナス(-$25)、機密数字は1文字1ドットでマスク(●●●●1234)。すべて tabular-nums で等幅化して列を揃える。

$10.20¥10000-251234.5
✗ proportional・桁区切り無し・負号バラバラ → 列も規約も崩壊
$10.20¥10,000-$25.00$1,234.50
✓ ロケール準拠+カンマ+負は記号前+tabular で全幅統一

blogThe UX of Currency Display — Workday Design

secondaryNumbers — Intuit Content Design

実装スニペット

/* テーブル数値列: 等幅 + 右揃え */
.num-cell {
  font-variant-numeric: lining-nums tabular-nums;
  text-align: right;
  font-feature-settings: normal; /* clobber回避: tnumを直接書かない */
}
/* レガシー(古いブラウザ)フォールバック */
@supports not (font-variant-numeric: tabular-nums) {
  .num-cell { font-feature-settings: "lnum", "tnum"; }
}
/* アニメカウンタ/タイマーのガタつき防止 */
.counter, .timer {
  font-variant-numeric: tabular-nums;
  /* monospaceフォントに替えない: 既存フォントのまま等幅化 */
}
/* 小数点揃え(text-align decimal 未実装の疑似実装) */
td {
  font-variant-numeric: lining-nums tabular-nums;
  text-align: right;
}
td [aria-hidden] { visibility: hidden; } /* display:none不可・幅を保持 */

/* HTML: 整数値に不可視の小数ダミーを足して桁を揃える
   <td>1<span aria-hidden="true">.00</span></td>
   <td>12<span aria-hidden="true">.75</span></td> */
/* 価格の階層(サイズ+色、通貨記号も等幅) */
.price {
  font-variant-numeric: lining-nums tabular-nums; /* 記号も含め等幅 */
  display: inline-flex;
  align-items: baseline;
}
.price__symbol { font-size: 0.7em; }        /* 上付きボタンでなくサイズ調整 */
.price__cents  {
  font-size: 0.6em;
  color: hsl(220 30% 55%);                  /* 同系色相・低彩度で弱める(灰色にしない) */
}

/* HTML: $1,234.56 / 末尾ゼロは通貨では保持
   <span class="price"><span class="price__symbol">$</span>1,234<span class="price__cents">.56</span></span> */

チェックリスト

  • テーブル列・価格・タイマー・カウンタに font-variant-numeric: tabular-nums を指定したか
  • 本文中の数字には tnum を撒かず proportional(既定)のままにしたか
  • font-feature-settings: "tnum" 1 を避け、高レベルプロパティを使ったか
  • 数値列は右揃え、テキスト列は左揃え、中央揃えを使っていないか
  • ヘッダもデータと揃えたか(数値ヘッダ右/テキストヘッダ左)
  • 小数桁が不揃いな列は小数点揃え(aria-hidden ダミー span)にしたか
  • 価格の通貨記号も等幅化し、擬似上付きで縮小していないか
  • 価格の階層をサイズ+色で作り、記号の太さを数字のウェイトに合わせたか
  • カンマ区切り・負号の位置・ロケール別小数桁を全変種のフィールド幅で吸収したか
  • 採用フォントが実機で tnum/lnum グリフを持つか確認したか

限界 / 出典

注意:CSS は要求に過ぎず、フォント側に tnum/lnum グリフが無ければ効かない。Inter / Roboto / SF / Lato / Open Sans 等は対応するが、採用フォントの数字機能を実機で確認すること。小数点揃えのネイティブ構文 text-align: "." right は2024時点で実装ブラウザ皆無で、aria-hidden ダミー span はあくまで疑似実装——生成/編集ワークフローに不可視 span 混入の手間が残る。価格の記号:数字のサイズ比(0.7em/0.6em)は一般的な出発値で、フォントごとに目視調整が必要。ロケール別フォーマットは代表例であり、個別通貨は別途検証推奨。色での弱め方など一部原則は単一ブログ由来。

primaryfont-variant-numeric — MDN Web Docs

blogTabular numbers — Sebastian De Deyne

blogTabular Numbers in CSS — font-variant-numeric vs monospace hacks — Authon Blog

blogDesign Better Data Tables — Matthew Ström (Mission Log)

secondaryWeb Typography: Designing Tables to be Read, Not Looked At — A List Apart

blogCharacter-based alignment — CSSence.com

secondaryBest Practices in Table Design — Science Editor

primaryCharacter design standards: Figures for Latin 1 — Microsoft Typography

secondaryManual: Currency Symbols — type.today

blogBook summary: Refactoring UI — sglavoie.com

blogThe UX of Currency Display — What's in a $ Sign? — Workday Design

secondaryNumbers — Intuit Content Design

primaryfont-variant-numeric — Tailwind CSS