これまで、tableタグ内で thead要素を固定してtbody要素をスクロール可能にするために、
table要素の外側の要素の高さを固定してposition:relative、overflow:autoと指定して、下記のような自作の簡易jQueryプラグインを使用していました。
HTMLとCSS
<div class="table-container"> <table> <thead> <tr> <th>カラム1</th> <th>カラム2</th> <th>カラム3</th> <th>カラム4</th> <th>カラム5</th> </tr> </thead> <tbody> <tr> <td>カラムデータ1</td> <td>カラムデータ2</td> <td>カラムデータ3</td> <td>カラムデータ4</td> <td>カラムデータ5</td> </tr> ... ... </tbody> </table> </div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> <script src="./jquery.headerFixedTable.js"></script> <script type="text/javascript"><!-- (function($) { $('.table-container').headFixed(); })(jQuery); //--></script>
.table-container { position: relative; overflow: auto; height: 100px; width: 80%; border: 1px solid #ccc; } .table-container table { width: 100%; border-collapse: collapse; } .table-container table > thead { background-color: #eee; } .table-container table > thead th { border-bottom: 2px solid #ccc !important; } .table-container table > tbody { background-color: white; } .table-container table tr > * { text-align: left; border-bottom: 1px solid #ccc; } .table-container table > tbody > tr:last-child > * { border-bottom: none !important; }
jQueryのプラグインは適当に作成。汎用性はなし。
/****************************************************************************** thead固定テーブル require following... <div class="table-wrap" style="position: relative;"> <table> <thead>...</thead> <tbody>...</tbody> </table> </div> <script type="text/javascript"> (function($) { $('.table-wrap').headFixed(); })(jQuery); </script> 要点としては、table要素を複製して、複製したテーブルはtheadだけを、元のテーブルはtbodyのみを表示するようにする。 その際 displayプロパティにすると元table,複製tableの各々カラム幅が揃わなくなるので、 display: none ではなく、visibility:hiddenを適用する。 ******************************************************************************/ (function($) { $.fn.headFixed = function() { return this.each(function() { var $table = $(this).find('table:first'); var $wrapElement = $('<div>') .css({'position': 'absolute','top': 0,'left':0,'width': $table.outerWidth(),'overflow':'hidden'}) .height($table.find('thead').outerHeight()); var $wrap = $table .clone() .insertAfter($table) .wrap($wrapElement) .css('width','100%') .find('tbody') .css({'visiblity': 'hidden'}) .end() .parent(); $table .find('thead') .css({'z-index':10,'visibility': 'hidden'}); $(this).on('scroll',function() { $wrap.css({'top':$(this).scrollTop()}); }); // ウィンドウのリサイズに追随 $(window).resize(function() { $wrap.width($table.outerWidth()); }); }); }; })(jQuery);
で、最近 display: sticky というのがあって便利だよ、というのを今更ながら知りまして、chrome,firefox用の画面にはこれを使うようしました。
MDNサイトで見ると「粘着位置指定要素 (stickily positioned element)」と言うそうで、要はイケてるサイトでよく見る、
下方スクロールしたら勝手にメニューなんかがページ上部に張り付く(固定される)挙動を簡単に実現できる CSSプロパティみたいです。
stickily positioned elementとは、 position の計算値が sticky である要素です。これは包含ブロックがフロールート (又はその中でスクロールするコンテナー) 内の指定されたしきい値 (例えば top に設定された auto 以外の値など) を達するまでは相対的な配置として扱われ、包含ブロックの反対の端が来るまでその位置に「粘着」するものとして扱われます。
これ読んでも、正直よく分かりません💦 すみません。
で、これをテーブルヘッダに利用しよう、というわけです。
ググると結構記事になっていて、要するに thead要素内の th要素に display:sticky を指定して固定するようです。
theadをstickyにするのが真っ当な感じですが、現在のブラウザのバージョンでは thead を固定することはできないみたい(無視される)。
それと、th要素をstickyで固定しても、th要素に適用されている border は固定されないみたいな挙動になる感じです(若干ずれてしまう?)
/* 実際のCSS */ .table-container { position: relative; overflow: auto; height: 100px; width: 80%; border: 1px solid #ccc; } .table-container table { width: 100%; border-collapse: collapse; } .table-container table > thead { background-color: #eee; } .table-container table > thead th { border-bottom: 2px solid #ccc !important; position: -webkit-sticky !important; position: sticky !important; z-index: 2 !important; top:0 !important; } .table-container table > tbody { background-color: white; } .table-container table tr > * { text-align: left; border-bottom: 1px solid #ccc; } .table-container table > tbody > tr:last-child > * { border-bottom: none !important; }
HTMLはほとんど同じ 。最後のscript要素が要らないだけ。
<div class="table-container"> <table> <thead> <tr> <th>カラム1</th> <th>カラム2</th> <th>カラム3</th> <th>カラム4</th> <th>カラム5</th> </tr> </thead> <tbody> <tr> <td>カラムデータ1</td> <td>カラムデータ2</td> <td>カラムデータ3</td> <td>カラムデータ4</td> <td>カラムデータ5</td> </tr> ... ... </tbody> </table> </div>
ただし、Internet Explorerには全バージョンを通して非対応なので(display:stickyは単に無視される)、
かっこ悪いけどブラウザで判別し(navigator.userAgent)、IEの時のみjQueryプラグインを使用するように分岐するようにした。
たとえば、ウェブシステムで行をjavascriptで動的に増やしたり減らしたりするときは、行を追加したり削除したりする関数を一個作っておき、もしブラウザがIEなら 複製テーブル、複製元テーブル両方に行を追加したり、削除したり。なんにしてもメンドクサイが。
IEユーザーがいなくなれば、これも必要なくなるかなと。