スクロール、スワイプ時にtableのいちばん左1列だけを固定する方法[position: stickyの活用]

tableの一番左1列だけを固定する方法[position: stickyの活用]
「このテーブルの、アタマの1行だけ固定して!」
というようなオーダーを頂くこと、実際の制作現場では、結構ありますよね。

地味な様ですが、それでいてWeb制作の実務において
結構出てくる頻度が多かったりする「テーブル要素」による表組み。

以前の記事では、そんな時に使用できる、
tableのヘッダーを固定する方法についてご紹介しました。
該当記事:tableのヘッダーを固定する方法2つ[position: stickyの活用とGrid.jsの場合]

↑上記記事では「縦方向の固定」について書きましたが、
今回の記事は、「横方向の固定」についての記事です。tableの一番左1列だけを固定する方法について、書いていきたいと思います。

↑このように、table内のいちばん左の1列を、position: sticky; を使って固定させる方法についての記事です。このサンプルのように position: sticky; は、縦方向の固定だけではなく横方向の固定もできる、という例です。覚えておくと、いろいろ応用が効くかと思います。

まずは結論から。position: sticky; を使用して、tableの一番左1列だけを固定する方法

では早速、その方法です。次の様な構造の、テーブル要素があったとします。
前回の記事同様に「列が4列、行が8行」あって、
縦軸にA B C
横軸に項目01〜07
を比較することができる想定のテーブルです。

前回と異なるのは、このtableの「一番左1列だけを固定する」ということです。そのため少しだけ、タグ構造も変わっています。

<div class="table-container">
  <table class="table-element">
    <tbody class="table-body">
      <tr class="table-row is-header">
        <th class="table-header"></th>
        <td class="table-data">A</td>
        <td class="table-data">B</td>
        <td class="table-data">C</td>
      </tr>
      <tr class="table-row">
        <th class="table-header">項目01</th>
        <td class="table-data"></td>
        <td class="table-data"></td>
        <td class="table-data"></td>
      </tr>
      <tr class="table-row">
        <th class="table-header">項目02</th>
        <td class="table-data"></td>
        <td class="table-data"></td>
        <td class="table-data"></td>
      </tr>
      <tr class="table-row">
        <th class="table-header">項目03</th>
        <td class="table-data"></td>
        <td class="table-data"></td>
        <td class="table-data"></td>
      </tr>
      <tr class="table-row">
        <th class="table-header">項目04</th>
        <td class="table-data"></td>
        <td class="table-data"></td>
        <td class="table-data"></td>
      </tr>
      <tr class="table-row">
        <th class="table-header">項目05</th>
        <td class="table-data"></td>
        <td class="table-data"></td>
        <td class="table-data"></td>
      </tr>
      <tr class="table-row">
        <th class="table-header">項目06</th>
        <td class="table-data"></td>
        <td class="table-data"></td>
        <td class="table-data"></td>
      </tr>
      <tr class="table-row">
        <th class="table-header">項目07</th>
        <td class="table-data"></td>
        <td class="table-data"></td>
        <td class="table-data"></td>
      </tr>
    </tbody>
  </table>
</div>

↑上記の構造のテーブルがあったとして、ここに、次の様なcssを適用してあげると、
「横スクロール時にテーブルの左1行だけ」を固定させることができます。
※ブラウザのデフォルトスタイルをリセットするcssは、既に適用されている前提で書いています。

.table-container {
  border: 1px solid #ebebeb;
  height: fit-content;
  margin: 2rem auto;
  overflow-x: scroll;
  width: 350px;
}
.table-element {
  border-collapse: separate;
  border-spacing: 0;
  font-size: .75rem;
  height: 100%;
  position: relative;
  width: 100%;
}
.table-header-group {
  border-bottom: 1px solid #ebebeb;
  height: 40px;
  top: 0;
  width: 100%;
  z-index: 10;
}
.table-header-group .table-header {
  background: rgba(215, 215, 215, 1);
  height: 40px;
}
.table-body {
  width: 100%;
}
.table-body .table-header {
  background: rgba(215, 215, 215, 1);
  left: 0;
  min-width: 100px;
  position: sticky;
  width: 100px;
}
.table-body .table-header::before {
  background: rgba(215, 215, 215, 1);
  content: '';
  display: block;
  height: 100%;
  position: absolute;
  right: 0;
  top: 0;
  width: 10px;
  z-index: 15;      
}
.table-body .table-header::after {
  box-shadow: 2px 0 8px rgb(0 0 0 / 70%);
  content: '';
  display: block;
  height: 100%;
  position: absolute;
  right: 0;
  top: 0;
  width: 1px;
  z-index: 10;
}
.table-body .table-row:nth-of-type(even) {
  background: rgba(240, 240, 240, 1);
}
.table-row.is-header {
  background: rgba(230, 230, 230, 1);
  font-size: .875rem;
  font-weight: 700;
  text-align: center;
}
.table-row {
  width: 100%;
}
.table-data {
  height: 60px;
  min-width: 200px;
}
.table-header,
.table-data {
  border-bottom: 1px solid #ebebeb;
}
.table-data {
  border-right: 1px solid #ebebeb;
}
.table-body .table-row:last-of-type .table-header {
  border-bottom: none;
}
.table-data:last-of-type {
  border-right: none;
}

↑前回の「縦方向の固定」をベースとしていますが、ポイントとしては、
tableの左端1列となる thead 要素に
34行目で 適用している
position: sticky; と、
それを有効にするために
その親要素達に必要なプロパティを指定している点です。

position: sticky; に関する以前の記事でも書きましたが、position: sticky; を有効にするために必要な確認点としては

親要素にheight, width(今回は横方向なのでwidth)を指定すること
直前の親要素にoverflowが設定されていないこと(全体を包括する親要素には指定する)
position: sticky; を指定した要素に top, left 等の位置指定をしていること(スルーしがちですが、要確認の点です)

などです。

上記のcssの記述で、横スクロール時に、テーブルの左端1列を固定することが可能になります。

左端1列に付いているシャドウについて

なお、テーブルの左端1列には box-shadow による影をつけています。
これの実装方法は他にもアプローチ方法があると思いますが、今回は手っ取り早く
::before, ::after擬似要素を2重に重ねることで、
綺麗に固定の影を見せられるように記述しています。
(cssの、37〜59行目の部分です)

もちろん他にもやり方はあると思うので、手っ取り早く見せるためのサンプルとして、ご参考まで。

擬似要素を使わない場合だと、マイナス方向の box-shadow を駆使して表現する、などが考えられますが、あまり綺麗には描画できない気がしているため、今回は上記の方法を使用しています。)

【Premium特典】コード全体をダウンロード

ここまで、「tableの左一列だけを固定する方法」についての記事をご紹介してきましたが、理解を深めるには
実際に動いている実物を見てみるのが一番早いかと思います。

tedate Premium にご登録いただくと、当記事で扱った内容のサンプルのhtmlファイルをダウンロードいただけます。
こちらのダウンロードファイルでは、冒頭の動画にあるような、「tableの左一列だけが固定」されている実際の状態を確認いただけます。

tedate Premiumとは?

「tedate Premium」 とは、tedate.jp 閲覧時に掲示される
広告を非表示にする事ができたり、会員限定記事が閲覧可能になる、
月額制の会員機能です。

ログイン頂くと、この記事のサンプルデータがダウンロードできます。
ダウンロードするには、tedate Premiumにご登録ください。
登録済みの方のログインページはこちら
tedate Premiumのご説明・新規ご登録は次のリンクよりお進みください。
tedate Premium のご紹介


ダウンロードデータ更新日:2023年1月28日。※随時アップデート予定です。

この記事のまとめ

今回は、以前ご紹介した記事:tableのヘッダーを固定する方法2つ[position: stickyの活用とGrid.jsの場合]
の続編として、
「tableの一番左1列を固定する方法」について、記事を書きました。

ページの中ほどのセクションでご紹介したように、
position: sticky;
での要素の固定は、いろいろな場面で応用が効く手法かと思いますので、地味ながらも覚えておくときっと役に立つと思います。

繰り返しになりますが、position: sticky; を使用する場合は

親要素にheight, width(今回は横方向なのでwidth)を指定すること
直前の親要素にoverflowが設定されていないこと(全体を包括する親要素には指定する)
position: sticky; を指定した要素に top, left 等の位置指定をしていること(スルーしがちですが、要確認の点です)

↑この辺りのチェックをお忘れなく。(意外とハマりやすいので)

この記事が皆さんのより良いWeb制作体験につながれば、嬉しく思います。

※この記事は内容の品質向上を目的に、随時更新を行う場合があります。

この記事をシェアする: