最終更新日:

cssのみでtableの項目を固定(ロック)する

cssのみでtableの項目を固定(ロック)する

こんにちは。五平餅くんです。

先日とある案件で、「表の一番上の列(項目)を固定してほしい」という依頼が入りました。

最初tableでそんなことはできないと思っていたのでお断りしていましたが、「どうしてもやってほしい」と言われ泣く泣くチャレンジ。

position: fixedとJavaScriptでなんとかしようと思いましたが何もかも撃沈…。

一日中調べていると、新しいcssプロパティの値である「position: sticky」が、表の一番上の列を固定してくれることを発見!!

今回はその嬉しさを共有したいので、もしよろしければ読んでいただきたいです。

position: stickyとは?

position: stickyの説明は以下が詳しいので、引用しておきます。

粘着位置指定された要素は、指定したしきい値に達するまでは相対位置指定として、しきい値に達したら固定位置指定として扱われます

参考:https://developer.mozilla.org/ja/docs/Web/CSS/position#Sticky_positioning

つまり、指定した要素の位置にスクロールするまでは変化せず、要素の位置までスクロールしたときposition: fixedと同じ挙動になります。

例えば、このブログのサイドバーの一番下の、「五平餅くんとは?」です。

ここにはこのような指定をしています。

position: sticky;
top: 30px;

この要素を見ると、スクロール位置がこの要素に来るまでは良い子に大人しくしていますが、この要素に到着すると上が30pxの位置に画面固定されます。

確認してみてください。右下の「>」ボタンをクリックすると一番上までスクロールされ、サイドバーの「五平餅くんとは?」も元々の位置に戻るはずです。

 

position: fixedだと常に画面固定で表示されてしまいますが、position: stickyを使うと要素の位置までは通常表示で、スクロール位置が要素の位置に到達すると画面固定で表示されます。

ちなみに、このposition: stickyはIEには対応していないので、IEでは諦めましょう。

※「Polyfill」というプラグインを使えばIEでも使えるようになるという情報もありましたので、どうしても使いたい方はお調べください。

tableでの使用

それでは本題です。

表を<table>タグで作ったとき、すごくたくさん行がある場合はスクロールしていくと画面上から一番上の項目が消え、「今見ているデータはどこの項目のどの列か?」がわからなくなる事態が発生してしまいます。

デザイナー的にいうなら、そのままだとユーザビリティが悪いです。

例えばこんな場合です。

完全に見失ってしまいますね。。

こんな問題も、一番上の行(項目)を固定で表示できれば解決できます。

さて、そこで使えるのが、先ほどのposition: stickyです。

使い方は簡単。

表の一番上の項目にposition: stickyとtop: 0を指定すれば良いだけです。

早速作っていきましょう!

まずはhtmlでtableを適当に作ります(すみません少し長いです!)

<div id="content">
  <div class="inner">
    <table class="sticky-table">
      <thead>
        <tr>
          <th>
            項目1
          </th>
          <th>
            項目2
          </th>
          <th>
            項目3
          </th>
          <th>
            項目4
          </th>
          <th>
            項目5
          </th>
          <th>
            項目6
          </th>
          <th>
            項目7
          </th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>
            テキストテキスト
          </td>
          <td>
            テキストテキストテキストテキストテキストテキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキストテキストテキストテキスト
          </td>
          <td>
            テ
          </td>
          <td>
            テキストテキストテキストテキストテキストテキスト
          </td>
          <td>
            テキストテキスト
          </td>
        </tr>
        <tr>
          <td>
            テキストテキスト
          </td>
          <td>
            テキストテキスト
          </td>
          <td>
            テキストテキストテキストテキストテキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキストテキストテキストテキストテキスト
          </td>
          <td>
            テキストテキストテキストテキストテキストテキストテキスト
          </td>
          <td>
            テキストテキスト
          </td>
        </tr>
        <tr>
          <td>
            ー
          </td>
          <td>
            テキストテキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキストテキストテキストテキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキストテキスト
          </td>
        </tr>
        <tr>
          <td>
            テキ
          </td>
          <td>
            テキストテキストテキストテキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキストテキストテキストテキストテキストテキスト
          </td>
          <td>
            テキストテキスト
          </td>
          <td>
            テキストテキスト
          </td>
        </tr>
        <tr>
          <td>
            テキストテキスト
          </td>
          <td>
            テキストテキストテキストテキストテキストテキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキストテキスト
          </td>
          <td>
            ー
          </td>
          <td>
            ー
          </td>
          <td>
            テキスト
          </td>
        </tr>
        <tr>
          <td>
            テキストテキストテキストテキストテキストテキスト
          </td>
          <td>
            ー
          </td>
          <td>
             
          </td>
          <td>
             
          </td>
          <td>
            テキストテキスト
          </td>
          <td>
            テキストテキストテキストテキスト
          </td>
          <td>
            テキスト
          </td>
        </tr>
        <tr>
          <td>
            ー
          </td>
          <td>
            テキストテキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキストテキストテキストテキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキストテキスト
          </td>
        </tr>
        <tr>
          <td>
            テキストテキストテキストテキストテキストテキスト
          </td>
          <td>
            ー
          </td>
          <td>
             
          </td>
          <td>
             
          </td>
          <td>
            テキストテキスト
          </td>
          <td>
            テキストテキストテキストテキスト
          </td>
          <td>
            テキスト
          </td>
        </tr>
        <tr>
          <td>
            テキストテキスト
          </td>
          <td>
            テキストテキスト
          </td>
          <td>
            テキストテキストテキストテキストテキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキストテキストテキストテキストテキスト
          </td>
          <td>
            テキストテキストテキストテキストテキストテキストテキスト
          </td>
          <td>
            テキストテキスト
          </td>
        </tr>
        <tr>
          <td>
            テキストテキスト
          </td>
          <td>
            テキストテキストテキストテキストテキストテキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキストテキストテキストテキスト
          </td>
          <td>
            テ
          </td>
          <td>
            テキストテキストテキストテキストテキストテキスト
          </td>
          <td>
            テキストテキスト
          </td>
        </tr>
        <tr>
          <td>
            テキストテキスト
          </td>
          <td>
            テキストテキスト
          </td>
          <td>
            テキストテキストテキストテキストテキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキストテキストテキストテキストテキスト
          </td>
          <td>
            テキストテキストテキストテキストテキストテキストテキスト
          </td>
          <td>
            テキストテキスト
          </td>
        </tr>
        <tr>
          <td>
            テキストテキスト
          </td>
          <td>
            テキストテキスト
          </td>
          <td>
            テキストテキストテキストテキストテキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキストテキストテキストテキストテキスト
          </td>
          <td>
            テキストテキストテキストテキストテキストテキストテキスト
          </td>
          <td>
            テキストテキスト
          </td>
        </tr>
        <tr>
          <td>
            ー
          </td>
          <td>
            テキストテキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキストテキストテキストテキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキストテキスト
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</div>

なんの変哲もないtableでございます。

そして、重要なのがcss。早速書いていきます。

.inner {
  max-width: 1500px;
  width: 97%;
  margin: 0 auto;
}

.sticky-table {
  width: 100%;
  min-width: 450px;
  overflow-x: scroll;
  border: 1px solid #888;
  border-collapse: collapse;
}

.sticky-table th, .sticky-table td {
  padding: 10px;
  font-size: 16px;
  border: 1px solid #888;
}

.sticky-table th {
  background: #f5f5f5;
}

これだけで、ひとまず表のスタイルは整ったかと思います。

ただし、まだ表の一番上の行(項目)は固定されていません。

最後に、表の一番上の項目にposition: stickyとtop: 0を指定すれば完成です。

.sticky-table th {
  background: #f5f5f5;
  /* 以下追加部分。表の項目を固定する */
  position: sticky;
  top: 0;
  left: 0;
  z-index: 99999;
}

下のボタンからデモ表示できます。

スクロールしていくと、表の一番上の列(項目)が画面固定されていることが確認できたでしょうか。

こちら便利なのでぜひ使ってみてください。

おまけ:下線がついてこない・・・

さて、ひとまずこれで表の一番上の行(項目)を固定することには成功しました。

しかし問題が。

固定されたあと、下線が消える、、、

気にしなければ良いのかもしれませんが、どうしても気になってしまうのが我々コーダー です。

安心してください。解決方は簡単です。

先ほどの項目部分の下に、以下のcssを追加してください。

/*おまけ*/
.sticky-table th::before {
  content: '';
  position : absolute ;
  top : 0;
  left : 0;
  width : 100%;
  height : 100%;
  border-bottom: 1px solid #888;
}

以下のボタンからデモ表示できます。

解説すると、項目一つにつき擬似要素を作り、border-bottomで線をつけています。

擬似要素についてはサルワカさんのブログが分かりやすいです。↓

CSSの疑似要素とは?beforeとafterの使い方まとめ

最終的なコード

ここは最終的なコードを載せているだけなので、飛ばしても構いません。

<div id="content">
  <div class="inner">
    <table class="sticky-table">
      <thead>
        <tr>
          <th>
            項目1
          </th>
          <th>
            項目2
          </th>
          <th>
            項目3
          </th>
          <th>
            項目4
          </th>
          <th>
            項目5
          </th>
          <th>
            項目6
          </th>
          <th>
            項目7
          </th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>
            テキストテキスト
          </td>
          <td>
            テキストテキストテキストテキストテキストテキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキストテキストテキストテキスト
          </td>
          <td>
            テ
          </td>
          <td>
            テキストテキストテキストテキストテキストテキスト
          </td>
          <td>
            テキストテキスト
          </td>
        </tr>
        <tr>
          <td>
            テキストテキスト
          </td>
          <td>
            テキストテキスト
          </td>
          <td>
            テキストテキストテキストテキストテキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキストテキストテキストテキストテキスト
          </td>
          <td>
            テキストテキストテキストテキストテキストテキストテキスト
          </td>
          <td>
            テキストテキスト
          </td>
        </tr>
        <tr>
          <td>
            ー
          </td>
          <td>
            テキストテキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキストテキストテキストテキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキストテキスト
          </td>
        </tr>
        <tr>
          <td>
            テキ
          </td>
          <td>
            テキストテキストテキストテキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキストテキストテキストテキストテキストテキスト
          </td>
          <td>
            テキストテキスト
          </td>
          <td>
            テキストテキスト
          </td>
        </tr>
        <tr>
          <td>
            テキストテキスト
          </td>
          <td>
            テキストテキストテキストテキストテキストテキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキストテキスト
          </td>
          <td>
            ー
          </td>
          <td>
            ー
          </td>
          <td>
            テキスト
          </td>
        </tr>
        <tr>
          <td>
            テキストテキストテキストテキストテキストテキスト
          </td>
          <td>
            ー
          </td>
          <td>
             
          </td>
          <td>
             
          </td>
          <td>
            テキストテキスト
          </td>
          <td>
            テキストテキストテキストテキスト
          </td>
          <td>
            テキスト
          </td>
        </tr>
        <tr>
          <td>
            ー
          </td>
          <td>
            テキストテキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキストテキストテキストテキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキストテキスト
          </td>
        </tr>
        <tr>
          <td>
            テキストテキストテキストテキストテキストテキスト
          </td>
          <td>
            ー
          </td>
          <td>
             
          </td>
          <td>
             
          </td>
          <td>
            テキストテキスト
          </td>
          <td>
            テキストテキストテキストテキスト
          </td>
          <td>
            テキスト
          </td>
        </tr>
        <tr>
          <td>
            テキストテキスト
          </td>
          <td>
            テキストテキスト
          </td>
          <td>
            テキストテキストテキストテキストテキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキストテキストテキストテキストテキスト
          </td>
          <td>
            テキストテキストテキストテキストテキストテキストテキスト
          </td>
          <td>
            テキストテキスト
          </td>
        </tr>
        <tr>
          <td>
            テキストテキスト
          </td>
          <td>
            テキストテキストテキストテキストテキストテキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキストテキストテキストテキスト
          </td>
          <td>
            テ
          </td>
          <td>
            テキストテキストテキストテキストテキストテキスト
          </td>
          <td>
            テキストテキスト
          </td>
        </tr>
        <tr>
          <td>
            テキストテキスト
          </td>
          <td>
            テキストテキスト
          </td>
          <td>
            テキストテキストテキストテキストテキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキストテキストテキストテキストテキスト
          </td>
          <td>
            テキストテキストテキストテキストテキストテキストテキスト
          </td>
          <td>
            テキストテキスト
          </td>
        </tr>
        <tr>
          <td>
            テキストテキスト
          </td>
          <td>
            テキストテキスト
          </td>
          <td>
            テキストテキストテキストテキストテキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキストテキストテキストテキストテキスト
          </td>
          <td>
            テキストテキストテキストテキストテキストテキストテキスト
          </td>
          <td>
            テキストテキスト
          </td>
        </tr>
        <tr>
          <td>
            ー
          </td>
          <td>
            テキストテキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキストテキストテキストテキスト
          </td>
          <td>
            テキスト
          </td>
          <td>
            テキストテキスト
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</div>
.inner {
  max-width: 1500px;
  width: 97%;
  margin: 0 auto;
}

.sticky-table {
  width: 100%;
  min-width: 450px;
  overflow-x: scroll;
  border: 1px solid #888;
  border-collapse: collapse;
}

.sticky-table th, .sticky-table td {
  padding: 10px;
  font-size: 16px;
  border: 1px solid #888;
}

.sticky-table th {
  background: #f5f5f5;
  /* 以下追加部分。表の項目を固定する */
  position: sticky;
  top: 0;
  left: 0;
  z-index: 99999;
}

/*おまけ*/
.sticky-table th::before {
  content: '';
  position : absolute ;
  top : 0;
  left : 0;
  width : 100%;
  height : 100%;
  border-bottom: 1px solid #888;
}

まとめ:position: stickyは最高

というわけで今回は「position: sticky」で表の一番上の列を固定する方法について解説させて頂きました。

どうやら2017年にできた新しいプロパティの値のようで、IEには対応していませんが、主要ブラウザのほとんどには対応しています。

長ーーーい表を作成する機会があったら、ぜひposition: stickyを使ってみてください!

最後まで読んでいただきありがとうございました。

関連記事

人気記事