Edited at

CSSのみで行・列ヘッダ固定テーブルを実装(Firefox / Chrome / Safari)


Introduction

モダンブラウザにおいてposition: stickywidth: max-contentの対応が進んだことで、CSSのみで行・列ヘッダ固定テーブルを容易に実装できるようになりました。

なお、各ブラウザの対応状況が異なるため、現状ではセルの横幅(場合によっては高さも)を明示する課題を残してはいますが、保守性は大幅に向上されました。


Goal

20170907-225500_capture.gif

StickyTable | CodePen


Support

本実装での各ブラウザの対応状況です。

ブラウザ
バージョン
対応状況

Chrome
v.60

Firefox
v.55

Safari
v.10.1

Edge
v.15
×


How to


HTML

<table class="sticky_table">

<thead>
<tr>
<th class="blank">&nbsp;</th>
<th>head</th>
<th>head</th>
<!-- ... -->
</tr>
<!-- ... -->
</thead>
<tbody>
<tr>
<th>left</th>
<td>data</td>
<td>data</td>
<!-- ... -->
</tr>
<!-- ... -->
</tbody>
</table>

HTMLはシンプルなテーブルの記述です。

ヘッダ固定テーブルを実装するために以下を行います。


  • tableタグにsticky_tableクラスを付与する。

  • theadのtrの1列目(固定列と固定行の交差部分)にblankクラスを付与する。


CSS


tableタグ

.sticky_table {

display: block;
position: relative;
overflow: scroll;
width: calc(100vw - 3.0rem);
height: calc(75vh);
border-collapse: collapse;
font-size: 0;
}

tableタグは幅と高さを決め、子要素がはみ出した際にスクロールするようにします。

position: relativeは、子要素の位置が相対指定となった際の基準として明記します。

font-size: 0は後述のinline-block要素を横並びにした際に生じる隙間を回避するために指定します。


thead, tbodyタグ

.sticky_table thead,

.sticky_table tbody {
display: block;
width: -webkit-max-content;
width: -moz-max-content;
width: max-content;
}

theadとtbodyタグは幅を子要素のとりうる最大の横幅となるようwidth: max-contentを指定します。

なお、max-contentはブラウザによって対応状況が異なります。

Intrinsic & Extrinsic Sizing | Can I use...


th, tdタグ

.sticky_table th,

.sticky_table td {
display: inline-block;
width: 8.0rem;
background: #fff;
font-size: 1.0rem;
}

thとtdタグはdisplay: inline-blockとし、横並びに整列させ、widthで横幅を固定します。

backgroundはスクロールした際、固定要素と文字が重なるのを回避するため指定します。


列ヘッダの固定

.sticky_table tbody th {

position: -webkit-sticky;
position: sticky;
left: 0;
z-index: 1;
}

列はtbodyの子要素thに対しposition: stickyを指定します。スクロールの際に左側に吸着するようleft: 0を指定します。


行ヘッダの固定

.sticky_table thead {

position: -webkit-sticky;
position: sticky;
top: 0;
z-index: 2;
}

行はtheadに対しposition: stickyを指定します。スクロールの際に上側に吸着するようtop: 0を指定します。


行・列ヘッダの交差部分の固定

.sticky_table thead th.blank {

position: -webkit-sticky;
position: sticky;
top: 0;
left: 0;
z-index: 3;
}

行・列ヘッダの交差部分はtheadのblankクラスを指定したthに対しposition: stickyを指定します。スクロールの際に左上に吸着するようtop: 0; left: 0を指定します。


ヘッダ固定テーブルの実装は以上です。

あとはCSSでデザインを行えば完成ですが、ここではヘッダ固定テーブルの実装について記すことが主旨のため、デザイン関連のコードは割愛させていただきます。Codepenをご参照ください。


Conclusion

CSSのみでヘッダ固定テーブルが実装できましたがこれで完成ではありません。

当初目的としていたものは、position: stickyの指定のみでtheadとtbody>thを固定する事でした。しかしながら各ブラウザの対応状況が異なるため、display属性をブロック要素にして対処しています。

ブロック要素を横並びにするためwidth: max-contentが必要になります。ブラウザの対応状況が進み、table部品にもposition: stickyが適用できるようになれば不要となり、より容易にヘッダ固定テーブルを実装することができるようになるでしょう。


Reference

CSS position: sticky | Can I use...

Intrinsic & Extrinsic Sizing | Can I use...