テーブルセルの幅制御
問題
テキスト列と画像列、ステータスバッジ、アクションボタンが混在するテーブルは、幅が予測しにくいレンダリングになりがちです。ブラウザの自動テーブルレイアウトアルゴリズムはコンテンツに基づいてスペースを配分するため、テキストが多い列は利用可能なスペースを埋めるように広がり、画像列は必要以上のスペースを取ってしまいます。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 はレンダリングが速い(ブラウザがすべての行をスキャンする必要がない)一方で、すべての列を明示的にサイズ指定しなければなりません。サイズ未指定の列は残りのスペースを均等に分け合います。
コード例
コンテンツ幅に縮小する列
最も一般的なパターンです。画像、ステータス、アクションなどの特定の列をコンテンツ幅に縮小し、テキスト列が残りのスペースを取るようにします。
Avatar 列と Status 列はそれぞれの内容(画像とバッジ)にぴったり縮小され、Name 列と Description 列が残りのスペースを自然に分け合っています。
インナー要素で最小幅を確保
名前列のように常に 180px 以上の幅を保って読みやすくしたい場合など、最小幅を保証したい列には、固定幅を持つインナー <div> を使います。
Product 列は(ヘッダーの cell-sizer div によって設定された)常に 180px 以上の幅を保ち、Price 列と Image 列はコンテンツ幅に縮小されます。Description 列は残りのスペースを埋めます。
組み合わせパターン: 固定幅 + 縮小 + 可変幅
すべてのテクニックを組み合わせた現実的なデータテーブルです。固定幅の ID 列、アバターとアクション用の縮小列、可変のテキスト列を含んでいます。
table-layout: fixed を使った代替手法
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
- 厳密な制御が必要な多列のデータテーブル
- 長いテキストを切り詰めるべきテーブル
- 何百行もあってパフォーマンスが重要なテーブル(固定レイアウトはレンダリングが速い)
- コンテンツに関係なく列幅を変えたくないダッシュボードのテーブル