【CSS】テーブルの先頭行と先頭列を固定してスクロール可能にする方法

【CSS】テーブルの先頭行と先頭列を固定してスクロール可能にする方法 HTML/CSS

表が横にも縦にも長い場合、ヘッダー行や先頭列がスクロールで隠れてしまい見づらくなります。これを解決するには、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 thtop: 0 で固定し、tbody thleft: 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-collapsez-index の設定を工夫して、罫線が消えたり背景が透けたりしないように調整しましょう。