tableの見出しを固定してスクロールする方法

HTMLの<table>で作成した表の見出し部分だけを固定して、内容部分をスクロールできるようにする方法の備忘録です。

上の見出しを固定

表の上部分の見出しを固定して、内容部分を上下にスクロールする方法です。

見出し1 見出し2 見出し3 見出し4 見出し5 見出し6 見出し7
セル セル セル セル セル セル セル
セル セル セル セル セル セル セル
セル セル セル セル セル セル セル
セル セル セル セル セル セル セル
セル セル セル セル セル セル セル
セル セル セル セル セル セル セル
セル セル セル セル セル セル セル
セル セル セル セル セル セル セル
セル セル セル セル セル セル セル
セル セル セル セル セル セル セル
セル セル セル セル セル セル セル
セル セル セル セル セル セル セル
セル セル セル セル セル セル セル
セル セル セル セル セル セル セル
セル セル セル セル セル セル セル

サンプルの表示では、overflow: scroll;をつけた<div>タグで囲うことで、グレーの枠の中でスクロールさせています。<table>のまま使用すると、表示している画面の一番上で見出しが固定されます。

HTML

<table>
  <tbody>
    <tr>
      <th>見出し1</th>
      <th>見出し2</th>
      <th>見出し3</th>
      <th>見出し4</th>
      <th>見出し5</th>
      <th>見出し6</th>
      <th>見出し7</th>
    </tr>
    <tr>
      <td>セル</td>
      <td>セル</td>

… 省略 …

      <td>セル</td>
      <td>セル</td>
    </tr>
  </tbody>
</table>

1行目の<tr>に、<th>で固定する見出しを入れています。

CSS

table {
  width: 100%;
  position: relative;
}
th, td {
  border: none;
  white-space: nowrap;
}
th {
  font-weight: bold;
  color: #fff;
  background: #333;
  position: sticky;
  top: 0;
  left: 0;
  z-index: 1;
}
tr:nth-child(odd) td {
  background: #f3f5f5;
}

余白やデザインに関わる一部のコードは割愛しています。

親要素となるtableにposition: relative;を設定して、見出し部分のthにposition: sticky;を設定することで表示位置を固定します。

見出しの固定位置はtop: 0;left: 0;で表の上部に設定します。さらに、z-index: 1;を指定して内容部分の上に重ねます。

枠線のあるtableの場合

borderで枠線をつけた<table>の場合、そのままでは見出し部分の線がスクロール時に消えてしまうので、border-collapse: separate;を指定してセルごとにborderを設定します。

見出し1 見出し2 見出し3 見出し4 見出し5 見出し6 見出し7
セル セル セル セル セル セル セル
セル セル セル セル セル セル セル
セル セル セル セル セル セル セル
セル セル セル セル セル セル セル
セル セル セル セル セル セル セル
セル セル セル セル セル セル セル
セル セル セル セル セル セル セル
セル セル セル セル セル セル セル
セル セル セル セル セル セル セル
セル セル セル セル セル セル セル
セル セル セル セル セル セル セル
セル セル セル セル セル セル セル
セル セル セル セル セル セル セル
セル セル セル セル セル セル セル
セル セル セル セル セル セル セル

CSS

table {
  border-collapse: separate;
  border-spacing: 0;
  width: 100%;
  position: relative;
}
th, td {
  border-right: 1px solid #333;
  border-bottom: 1px solid #333;
  white-space: nowrap;
}
tr:first-child th,
tr:first-child td {
  border-top: 1px solid #333;
}
th:first-child,
td:first-child {
  border-left: 1px solid #333;
}
th {
  position: sticky;
  top: 0;
  left: 0;
  z-index: 1;
}

<table>にborder-collapse: separate;border-spacing: 0;を設定して、各セルにborder-rightborder-bottomで枠線をつけます。さらに:first-childを活用して外側の該当するセルにborder-topborder-leftを設定して枠線のある表を作成します。

左の見出しを固定

上下のスクロールと同様に表の左部分の見出しを固定して、内容部分を左右にスクロールできます。

見出し1 セル セル セル セル セル セル セル セル セル セル セル セル セル セル
見出し2 セル セル セル セル セル セル セル セル セル セル セル セル セル セル
見出し3 セル セル セル セル セル セル セル セル セル セル セル セル セル セル
見出し4 セル セル セル セル セル セル セル セル セル セル セル セル セル セル
見出し5 セル セル セル セル セル セル セル セル セル セル セル セル セル セル

HTML

<table>
  <tbody>
    <tr>
      <th>見出し1</th>
      <td>セル</td>
      <td>セル</td>
      …
      <td>セル</td>
      <td>セル</td>
    </tr>

… 省略 …

    <tr>
      <th>見出し5</th>
      <td>セル</td>
      <td>セル</td>
      …
      <td>セル</td>
      <td>セル</td>
    </tr>
  </tbody>
</table>

各行の先頭の<th>を見出しとして固定します。

CSS

table {
  width: 100%;
  position: relative;
}
th, td {
  border: none;
  white-space: nowrap;
}
th {
  font-weight: bold;
  color: #fff;
  background: #333;
  position: sticky;
  top: 0;
  left: 0;
  z-index: 1;
}
tr:nth-child(odd) td {
  background: #f3f5f5;
}
th {
  position: sticky;
  left: 0;
  z-index: 1;
}

左右のスクロールの場合はposition: sticky;left: 0;だけを指定します。

セルのテキストが意図せぬ位置で改行しないようにwhite-space: nowrap;を指定するかwidthで横幅を指定します。

縦横の見出しを固定

縦横の見出しを固定する方法です。縦スクロールの時は上の見出しを固定して、横スクロールの時は左の見出しを固定します。

見出し/行 見出し1 見出し2 見出し3 見出し4 見出し5 見出し6 見出し7 見出し8 見出し9 見出し10 見出し11 見出し12 見出し13 見出し14
行1 セル セル セル セル セル セル セル セル セル セル セル セル セル セル
行2 セル セル セル セル セル セル セル セル セル セル セル セル セル セル
行3 セル セル セル セル セル セル セル セル セル セル セル セル セル セル
行4 セル セル セル セル セル セル セル セル セル セル セル セル セル セル
行5 セル セル セル セル セル セル セル セル セル セル セル セル セル セル
行6 セル セル セル セル セル セル セル セル セル セル セル セル セル セル
行7 セル セル セル セル セル セル セル セル セル セル セル セル セル セル
行8 セル セル セル セル セル セル セル セル セル セル セル セル セル セル
行9 セル セル セル セル セル セル セル セル セル セル セル セル セル セル
行10 セル セル セル セル セル セル セル セル セル セル セル セル セル セル
行11 セル セル セル セル セル セル セル セル セル セル セル セル セル セル
行12 セル セル セル セル セル セル セル セル セル セル セル セル セル セル
行13 セル セル セル セル セル セル セル セル セル セル セル セル セル セル
行14 セル セル セル セル セル セル セル セル セル セル セル セル セル セル
行15 セル セル セル セル セル セル セル セル セル セル セル セル セル セル

HTML

<table>
  <thead>
    <tr>
      <th>見出し/行</th>
      <th>見出し1</th>
      <th>見出し2</th>
      <th>見出し3</th>
… 省略 …
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>行1</th>
      <td>セル</td>
      <td>セル</td>
      …
      <td>セル</td>
      <td>セル</td>
    </tr>

… 省略 …

    <tr>
      <th>行15</th>
      <td>セル</td>
      <td>セル</td>
      …
      <td>セル</td>
      <td>セル</td>
    </tr>
  </tbody>
</table>

上部の見出しは<thead>タグ内の<th>で作成します。横の見出しは<tbody>タグ内の各行の先頭<th>で作成します。

CSS

table {
  width: 100%;
  position: relative;
}
th, td {
  border: none;
  white-space: nowrap;
}
th {
  font-weight: bold;
  color: #fff;
  background: #333;
  position: sticky;
  top: 0;
  left: 0;
  z-index: 1;
}
tr:nth-child(odd) td {
  background: #f3f5f5;
}
thead th {
  color: #fff;
  background: #333;
  position: sticky;
  top: 0;
  z-index: 1;
}
thead th:first-child {
  position: sticky;
  top: 0;
  left: 0;
  z-index: 2;
}
tbody th {
  color: #fff;
  background: #333;
  position: sticky;
  left: 0;
  z-index: 1;
}

<thead>、<tbody>の各<th>をposition: sticky;で位置固定します。

さらに、左上のセルがどのスクロールでも動かないようにth:first-childで固定してz-index: 2;で一番上に重ねます。

Share on Twitter
関連記事
CSSを簡単に生成できる便利なジェネレーターまとめ
CSSを簡単に生成できる便利なジェネレーターまとめ
iOSのSafariで background-attachment: fixed; の表示崩れたときの解決策
iOSのSafariで background-attachment: fixed; の表示崩れたときの解決策
CSSでストライプなどの背景パターンを作る方法
CSSでストライプなどの背景パターンを作る方法