メインコンテンツまでスキップ
  • Created:
  • Updated:
  • Author:
    Takeshi Takatsudo

テーブルセルの幅制御

問題

テキスト列と画像列、ステータスバッジ、アクションボタンが混在するテーブルは、幅が予測しにくいレンダリングになりがちです。ブラウザの自動テーブルレイアウトアルゴリズムはコンテンツに基づいてスペースを配分するため、テキストが多い列は利用可能なスペースを埋めるように広がり、画像列は必要以上のスペースを取ってしまいます。AI エージェントはこれを <td> 要素に width を設定して修正しようとしますが、ブラウザはそれをあくまで「目安」として扱い、頻繁に無視します。結果として、列が広すぎたり狭すぎたりし、「この列はコンテンツ幅ぴったりにしたい」「最低でも 200px、でも最大はそれ以上不要」といったことを確実に指定する手段がなくなってしまいます。

解決方法

テーブルの列幅を精密に制御するために、互いに補完し合う 2 つのテクニックがあります。

テクニック 1: width: 0 でコンテンツ幅に縮小するトリック

セルの幅を 0(または 1px / 0.1%)に設定すると、ブラウザに「この列をできるだけ狭くしてほしい」と伝えます。すると列はコンテンツにぴったり合わせて縮小されます。画像、アイコン、バッジ、アクションボタンなど、余白をなくしたいコンテンツに最適です。

/* 列がコンテンツ幅にぴったり縮小される */
td.shrink {
width: 0;
white-space: nowrap; /* コンテンツの折り返しをなくしてさらなる縮小を防ぐ */
}

テクニック 2: 最小幅を確保するインナー要素

最小幅を強制したい場合は、セル内に固定 width を持つ <div> を配置します。セル自体の width: 0 と組み合わせることで「最小幅」の効果が生まれます。列はインナーの <div> の幅以上になりますが、コンテンツが必要とする幅を超えて広がることはありません。

/* セルはできるだけ小さくなろうとする */
td.min-width-cell {
width: 0;
}

/* インナー div が最小幅を強制する */
td.min-width-cell .cell-inner {
width: 200px; /* 列は最低でも 200px になる */
}

テクニック 3: 完全な制御のための table-layout: fixed

最大限の制御が必要な場合は table-layout: fixed を使います。このプロパティを指定すると、ブラウザは最初の行のみから列幅を決定し(後続の行のコンテンツは無視)、セルや <col> 要素に設定した明示的な width の値を尊重します。

table {
table-layout: fixed;
width: 100%;
}

トレードオフとして、table-layout: fixed はレンダリングが速い(ブラウザがすべての行をスキャンする必要がない)一方で、すべての列を明示的にサイズ指定しなければなりません。サイズ未指定の列は残りのスペースを均等に分け合います。

コード例

コンテンツ幅に縮小する列

最も一般的なパターンです。画像、ステータス、アクションなどの特定の列をコンテンツ幅に縮小し、テキスト列が残りのスペースを取るようにします。

width: 0 — 列をコンテンツ幅に縮小

Avatar 列と Status 列はそれぞれの内容(画像とバッジ)にぴったり縮小され、Name 列と Description 列が残りのスペースを自然に分け合っています。

インナー要素で最小幅を確保

名前列のように常に 180px 以上の幅を保って読みやすくしたい場合など、最小幅を保証したい列には、固定幅を持つインナー <div> を使います。

インナー div — 最小列幅の強制

Product 列は(ヘッダーの cell-sizer div によって設定された)常に 180px 以上の幅を保ち、Price 列と Image 列はコンテンツ幅に縮小されます。Description 列は残りのスペースを埋めます。

組み合わせパターン: 固定幅 + 縮小 + 可変幅

すべてのテクニックを組み合わせた現実的なデータテーブルです。固定幅の ID 列、アバターとアクション用の縮小列、可変のテキスト列を含んでいます。

組み合わせ — 固定幅・縮小・可変幅列

table-layout: fixed を使った代替手法

table-layout: fixed を使うとすべての列を完全に制御できますが、すべての列のサイズを指定する必要があります。<col> 要素を使って幅を宣言的に設定します。

table-layout: fixed と <col> 要素

table-layout: fixed を使うと、Description 列の長いテキストは text-overflow: ellipsis で切り詰められます。列幅は厳格に適用されます。

適切なアプローチの選び方

アプローチ使うべき場面トレードオフ
セルに width: 0列をコンテンツ幅に縮小する(画像、バッジ、ボタン)コンテンツが折り返さないようにするか、white-space: nowrap を追加する必要がある
固定幅の インナー <div>縮小しつつも最小幅を確保したい追加のマークアップが必要
table-layout: fixed + <col>すべての列を完全に制御したいすべての列のサイズを指定する必要がある。長いコンテンツは切り詰められる
table-layout: auto(デフォルト)ブラウザにコンテンツに基づいて判断させる予測しにくく、制御が難しい

AIがよくやるミス

  • <td>width: 200px を設定して適用されることを期待する — table-layout: auto(デフォルト)では、ブラウザはこれをルールではなく目安として扱う
  • テーブルセルに min-width を使って期待通りに動くと思う — min-width はほとんどのブラウザで <td> 要素には効果が薄い。代わりにインナー <div> のテクニックを使う
  • テーブル自体に width を設定せずに table-layout: fixed を適用する — テーブル自体に明示的な幅がないと table-layout: fixed は効果がない
  • 縮小列に white-space: nowrap を忘れる — これがないとセルのコンテンツが折り返してさらに幅が狭くなり、目的が達成できない
  • 列にパーセント幅を使ってそれらが正しく合算されると期待する — パーセント幅はテーブル幅に対する相対値であり、固定幅の列と組み合わせると予期しない結果になることがある
  • 固定レイアウトの列に overflow: hidden; text-overflow: ellipsis を追加しない — これがないとコンテンツがセルの境界からはみ出たり、水平スクロールが発生したりする

使い分け

width: 0 でコンテンツ幅に縮小

  • 画像・アバター列
  • ステータスバッジやタグの列
  • アクションボタン列
  • アイコン列
  • コンテンツが自然な固定サイズを持つ列全般

インナー div で最小幅を確保

  • 読みやすい最小幅が必要な名前・ラベル列
  • コンテンツ長がばらつくが最小幅を保証したい列
  • 一定のサイズに揃えたい ID 列

table-layout: fixed

  • 厳密な制御が必要な多列のデータテーブル
  • 長いテキストを切り詰めるべきテーブル
  • 何百行もあってパフォーマンスが重要なテーブル(固定レイアウトはレンダリングが速い)
  • コンテンツに関係なく列幅を変えたくないダッシュボードのテーブル

参考リンク