最終更新日:
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を使ってみてください!
最後まで読んでいただきありがとうございました。