CSS

CSSのみで幅可変のヘッダ固定テーブルを実装

More than 1 year has passed since last update.

テーブルのヘッダを固定して中身をスクロールさせたいって事、めちゃくちゃあると思います。
当然既にいろんな対策が練られています。
方法としては、大きく分けてCSSのみで実装する方法と、JQueryでプラグインなどを用いて実装する方法があります。
(参考:http://webnonotes.com/css/table-header/
しかし、CSSだけで実装する方法では、幅を固定しなければいけないというデメリットがあります。

でも…
CSSだけで幅可変のヘッダ固定テーブル、作りたくない?
と思ったのでやってみました。

解決法

結論から言うと、calc()とpaddingを利用します。
まずはテーブルを用意。

HTML
<table class="table-header-fixed">
    <thead>
        <tr>
            <th>#</th><th>ヘッダ2</th><th>ヘッダ3</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>1</td><td>データ</td><td>データデータデータ</td>
        </tr>
            ~~~中略~~~
        <tr>
            <td>12</td><td>データ</td><td>データデータデータ</td>
        </tr>
    </tbody>
</table>

何の変哲もないテーブルです。
次にCSS。

CSS
.table-header-fixed {
    width: 60%;
    min-width: calc(19em + 17px); /* カラム最小幅合計値+スクロールバーの幅+1px(誤差吸収用) */
    height: 300px;
    overflow-y: scroll;
    border-collapse: collapse;
}

.table-header-fixed thead,
.table-header-fixed tbody,
.table-header-fixed tr,
.table-header-fixed th,
.table-header-fixed td {
        display: block;
}

.table-header-fixed thead {
    width: calc(100% - 16px); /* 100% - スクロールバーの幅 */
}

.table-header-fixed tbody {
    height: calc(100% - 2em); /* 100% - ヘッダの高さ */
    overflow-y: scroll;
}

.table-header-fixed tr:after { /* clearfix */
    content: "";
    clear: both;
    display: block;
}

.table-header-fixed th,
.table-header-fixed td {
    float: left;
    height: 2em;
    line-height: 2em;
    overflow: hidden;
    padding: 0 calc((100% - 19em)/6); /* (100% - カラム最小幅合計値)/(カラム数*2) */
    border-bottom: 1px solid #CCC;
    box-sizing: content-box;
}

.table-header-fixed th:first-child,
.table-header-fixed td:first-child{
    width: 3em;    /* カラム1の最小幅 */
    text-align: right;
}
.table-header-fixed th:nth-child(2),
.table-header-fixed td:nth-child(2){
    width: 6em;    /* カラム2の最小幅 */
}
.table-header-fixed th:nth-child(3),
.table-header-fixed td:nth-child(3){
    width: 10em;    /* カラム3の最小幅 */
}

JSFiddleによるサンプル

各カラムのwidthには最小値(min-width)を入れます。
可変分はpaddingで調整するという具合です。
widthに直接足しても良かったのですが、カラム数が増えると全てのカラムに対して書くのが面倒だと思ったのでpaddingで処理しました。
Sassなどを使っているなら関数で処理してやると良いかもしれません。
table自体がカラムのwidthの合計値以下になるとレイアウトが崩れるので、min-widthで指定してやります。
ブラウザによってcalc()で誤差が出る場合があるので、1px分余分に確保しておきます。

問題点

  • calc()対応のブラウザが前提(対応ブラウザ表
  • 結局各カラムにwidthを指定する必要はある
  • 計算が手間

もっと手軽にスマートにできたらいいんですけどねえ。