見出し画像

テーブルのヘッダ部を固定する(簡易的)

HTMLのテーブルでヘッダ部分を固定したいときがあります。
プラグインを利用するのが簡単だとは思うのですが、今回は簡易的なものを自作してみたいと思います。

まずは結果から

CodePenで作成したものを貼り付けました。
走らせてみると、テーブルのヘッダ部分が固定されているかと思います。

ソースと説明

上のCodePenでもソースは見れますが、ソースを紹介しながら説明を行いたいと思います。

HTML

<div class="wrapper">
  <table>
    <thead>
      <tr>
        <th>Column-A</th>
        <th>Column-B</th>
        <th>Column-C</th>
        <th>Column-D</th>
        <th>Column-E</th>
        <th>Column-F</th>
        <th>Column-G</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Cell-A</td>
        <td>Cell-B</td>
        <td>Cell-C</td>
        <td>Cell-D</td>
        <td>Cell-E</td>
        <td>Cell-F</td>
        <td>Cell-G</td>
      </tr>
      <tr>
        <td>Cell-A</td>
        <td>Cell-B</td>
        <td>Cell-C</td>
        <td>Cell-D</td>
        <td>Cell-E</td>
        <td>Cell-F</td>
        <td>Cell-G</td>
      </tr>
        ・
        ・
        ・
      <tr>
        <td>Cell-A</td>
        <td>Cell-B</td>
        <td>Cell-C</td>
        <td>Cell-D</td>
        <td>Cell-E</td>
        <td>Cell-F</td>
        <td>Cell-G</td>
      </tr>
    </tbody>
  </table>
</div>

HTMLの構造はシンプルです。
divタグの中にtableタグがあるだけです。
スクロールする領域はこのdivタグになります。

CSS

.wrapper {
  display: inline-block;
  height: 200px;
  overflow: auto;
  padding: 0;
  border: 1px solid black;
  
  table {
    border-collapse: separate;
    border: none;
    border-spacing: 0;
    
    tr {
      th, td {
        border-right: 1px solid black;
        border-bottom: 1px solid black;
        padding: 4px;
      }
      th:last-child, td:last-child {
        border-right: none;
      }
      th {
        background: #eee;
      }
    }
    tbody {
      tr:last-child {
        th, td {
          border-bottom: none;
        }      
      }
    }
  }
}

SCSSで書いています。それぞれの内容は以下の通りです。

.wrapper (div)

  • display: inline-block
    inline-block にして、widthを設定しないことで、幅がテーブルの幅と同じになるようにしています。

  • height: 200px
    高さを決めています。ここは自由に設定して下さい。

  • overflow: auto
    スクロールするようにしています。

  • padding: 0
    パディングをゼロにすることで、このdivがテーブルと接するようにしています。

  • boder: 1px solid black
    どの位置にスクロールしても外枠が表示されるよう、このdivに枠線を設定しています。

table

  • border-collapse: separate 
    セルの枠線を分けています。separateではなくcollapseにするとヘッダ部を移動させたとき枠線が移動されません。

  • boder: none
    外側のdivに枠線を設定しているので、tableには設定しません。

  • border-spacing: 0
    セルの枠線の間のスペースを0にしています。

th、td (セル)

  • border-right: 1px solid black
    border-bottom: 1px solid black
    tableタグのborder-collapseをseparateにしたため、上下左右に枠線を設定すると隣り合ったセルの接した部分にそれぞれ枠線が表示されて太くなってしまいます。そのため枠線を右と下だけにしています。

th:last-child, td:last-child (右端のセル)

  • border-right: none
    右端のセルの枠線はdivの枠線と接して太くなってしまうので、なしにします。

tbody > tr:last-child > thまたはtd (下端のセル)

  • border-bottom: none
    上記と同様、下端のセルの枠線も、なしにします。

JavaScript

document.querySelectorAll(".wrapper").forEach((elem)=>{
  elem.addEventListener("scroll", function() {
    const head = this.querySelector("thead");
    const y = this.scrollTop;
    head.style.transform = `translateY(${y}px)`;
  });
});

div部分のスクロールしたときのイベントで、テーブルのヘッダ部(theadタグ)部分をスクロールした分移動するようにしているだけです。
head.style.transform = `translateY(${y}px)`
は、CSSで以下を書くのと同じです(数値は例)。
transform: translateY(100px);

さいごに

いかがでしたか。
JavaScriptも短いし、CSSもそんなに多くない(と思う)ですが、ちゃんとヘッダ部が固定するものが書けました。
もしも参考になりましたら幸いです。
では、また。

この記事が参加している募集

この記事が気に入ったらサポートをしてみませんか?