表が横にも縦にも長い場合、ヘッダー行や先頭列がスクロールで隠れてしまい見づらくなります。これを解決するには、position: sticky
を活用して「先頭行」「先頭列」を固定する方法が便利です。JavaScript を使わなくても純粋な CSS で実装でき、横方向・縦方向の両方に対応できます。
基本構造
まずはスクロール可能にするために、テーブルをラッパー要素で囲みます。
<div class="table-scroll">
<table class="fixed-table">
<thead>
<tr>
<th>項目</th>
<th>1月</th>
<th>2月</th>
<th>3月</th>
</tr>
</thead>
<tbody>
<tr><th>商品A</th><td>100</td><td>120</td><td>90</td></tr>
<tr><th>商品B</th><td>80</td><td>95</td><td>110</td></tr>
<tr><th>商品C</th><td>60</td><td>70</td><td>65</td></tr>
</tbody>
</table>
</div>
CSS で先頭行・先頭列を固定
thead th
を top: 0
で固定し、tbody th
を left: 0
で固定します。交差する左上セルは z-index
を高めに設定するのがポイントです。
.table-scroll {
overflow: auto;
max-height: 300px; /* 高さ制限を付けて縦スクロール可能に */
}
.fixed-table {
border-collapse: separate; /* collapse は sticky と相性が悪いため separate */
border-spacing: 0;
min-width: 600px; /* 横スクロールを確認できるように幅指定 */
}
.fixed-table th,
.fixed-table td {
border: 1px solid #ccc;
padding: 8px 12px;
background: #fff;
white-space: nowrap; /* 折り返しを防止して横スクロールに対応 */
}
/* 先頭行(ヘッダー)を固定 */
.fixed-table thead th {
position: sticky;
top: 0;
background: #f9f9f9;
z-index: 2;
}
/* 先頭列を固定 */
.fixed-table tbody th {
position: sticky;
left: 0;
background: #f9f9f9;
z-index: 1;
}
/* 左上セル(交差部分)はさらに z-index を上げる */
.fixed-table thead th:first-child {
left: 0;
z-index: 3;
}
ポイント
border-collapse: collapse;
は sticky と相性が悪く罫線が消えることがあるため、border-collapse: separate;
とborder-spacing: 0;
を使うのがおすすめ- 背景色を必ず指定しないと、スクロール時に下のセルが透けて見える
z-index
を調整して、行と列の交差セルが正しく重なるようにする
まとめ
CSS の position: sticky
を使えば、テーブルの先頭行と先頭列を簡単に固定できます。横スクロール・縦スクロールの両方に対応できるため、大量のデータを扱う表でも見やすさを保てます。実装時には border-collapse
や z-index
の設定を工夫して、罫線が消えたり背景が透けたりしないように調整しましょう。