Ajax系ライブラリによくあるtableのヘッダ固定の仕組みを調べてみた

更新履歴

2010-01-21
下記エントリでヘッダ、フッタを固定させる簡単なプラグインのソースを記載してます。
tableのヘッダ部分を固定表示するには?

2001年頃のIE5.0時代、はじめてwebシステムを作った頃、初心者向け言語のJavascriptを駆使して何とかできないかといろいろ調べた記憶があります。で思いついたのがこちらの小飼さん方式と同じ方法。

詳しくは末尾のソースをご覧頂くとして、要点をまとめると、

  1. 本来一つのtableで表示するところを、三つのtableに分ける
  2. table一つ一つをdivで囲む
  3. 上下のdivには、thead,tfootに対応するtableをおく
  4. 真ん中のdivに、tbodyに対応するtableを置き、scrollの設定はdivで行う
  5. 上中下の各table内のtd,thは、一番右の要素を除いてwidthを指定する

この「一番右の要素を除いて」というところがミソです。
それにしても、CSSJavaScript以上にブラウザー依存が激しくて大変です。デザイナーのみなさんはほんとすごいと思います。

スクロール可能なテーブル - 404 blog not found

ただこのやり方だとCSSの先生方から「許せない」とか言われてしまうようです。

404 Blog Not Found:CSS - スクロール可能なテーブル w/o JavaScript
そのHTMLは許せないので試行錯誤してみた。

tbodyをスクロール可能に - Sybianの日記

Sybianの日記 - tbodyをスクロール可能にのきっかけになった 404 Blog Not Found:CSS - スクロール可能なテーブル w/o JavaScriptも、さらにそのきっかけになったスクロール可能なテーブルを作成するJavaScriptライブラリ「ScrollableTable」:phpspot開発日誌も、 ( さらにはおおもとの Scrollable HTML table も ) やたらと遠回りなことをしているなあという印象。

CSS で tbody 要素を一定の高さにして、 overflow: auto でスクロール表示にする - hxxk.jp

と言っても他に(IE6での)解決方法がないんじゃしょうがないかと思っていたのですが、近頃、はてブの人気記事にヘッダ固定のAjaxライブラリを見かけるようになりました。

基本的にWebシステムでヘッダ固定はできないという認識はエンドユーザにもあるようで、要求仕様の打合せなどしてると「ここの見出しのところは固定表示できないんだよね?」とか言ってきたりします。外注業者さんの中にも「ウェブではヘッダの固定はできませんので・・・」とか言う人もいます。今内作で担当してるシステムでもヘッダ固定の要望がでそうなので、固定ヘッダAjaxライブラリのソースを調べてみました。(そういえばTeedaのScaffoldもテーブルヘッダ固定されてるなぁ。)

tableヘッダ固定を実現するAjaxライブラリのソースを調べた

調べたのは、Scrollable HTML table plugin for jQueryです。中身を見るとほとんどjqueryの機能は使ってなく、IEとFF(Firefox)にしか対応してないようでロジックがIE用とFF用に分岐してます。

if (jQuery.browser.msie || jQuery.browser.mozilla) {
    var table = new ScrollableTable(this, tableHeight, tableWidth);
}
… 省略 …
if (document.all && document.getElementById && !window.opera) this.initIEengine();
if (!document.all && document.getElementById && !window.opera) this.initFFengine();
IE用のロジックにおける主要な処理は
  1. tableをdivで囲う。
  2. divのheightをパラメータ指定の高さにする
  3. divのoverflowをautoにする
  4. theadのtrのpositionをrelativeにし、expressionでdivのscrollbarの移動量をtrのtopに加算する

と言う流れみたいですが、expressionの処理は無くてもうまくいくみたいです。(IETesterのIE6,IE7で確認。IE8では基本的に動かないようです。)

if (this.thead) {
    var trs = this.thead.getElementsByTagName('tr');
    for (x=0; x<trs.length; x++) {
        trs[x].style.position ='relative';
        trs[x].style.setExpression("top",
            "this.parentElement.parentElement.parentElement.scrollTop + 'px'");
    }
}
FFの主要な処理は
  1. tableをdivで囲う。
  2. divのheightをパラメータ指定の高さにする
  3. divのoverflowをhiddenにする
  4. tbodyのoverflowを -moz-scrollbars-vertical にする
  5. tbodyのheightを調整する(ヘッダ、フッタの高さを考慮)

う〜ん・・・divっているんですかね?なくても問題なさそうですけど・・・基本的には上のhxxk.jpさんと同じ方法ですかね。(tbodyのoverflowを上のhxxk.jpさんみたいにautoにせず -moz-scrollbars-vertical にしてるのは横スクロールバーを非表示するためのようですね・・・)

見た目

IEはdivで、FFはtbodyでscrollbarを出してるので見た目が異なります
IE

FF

CSSでの書き方

これをCSSで簡単に書いてみるとこんな感じでしょうか。

/*IE向け*/
    #ie div{
        height:150px;
        overflow-y:auto;
    }
    #ie thead tr{
        position:relative;
    }
/*FF向け*/
    #ff tbody{
        overflow:-moz-scrollbars-vertical;
        height:100px;
    }

IE用サンプルページ(IEで見てください)
FF用サンプルページ(FFで見てください)

というわけで、IEのやり方が自分にとっては新たな発見だったわけですが、IE8だとうまく動かないみたいです。う〜ん・・・

結論

Javascriptで生成するなら小飼さん方式でいいんじゃないでしょうか(そっちの方が安心)。ちなみにあのExt.jsのgridテーブルも小飼さん方式+divとtableの嵐で実現しています。行ごとにtableがあります。

Ext.js3.0だとdl、dtでタグの数が若干緩和されてますね。名前もsimple listviewになってます。

関連エントリー

tableのヘッダを固定させる簡易scriptをサクっと作ってみた
jQuery プラグインで簡単に実現。CSS の記述がめんどうな場合にどうぞ
tableのヘッダ固定やソートとかのAjax系ライブラリまとめ
高機能なライブラリが必要な場合にどうぞ
IE8 beta2対応版IETesterでtableヘッダ固定のCSS定義を確認した
CSS オンリーでヘッダ固定を実現させたい場合にどうぞ