※2012/02/01 若干改良.
※2012/02/09 まとめてみた.
※2012/02/14 display:blockの他にfloat:leftも便利に使えるっぽい.詳しくは上の記事を参照.
※2018/01/24 display:stickyと組み合わせる方法があるようです
https://qiita.com/shunsuke_i_anotelia/items/14fb4ec2600828a21a22
- [対象ブラウザ]
動作を確認したブラウザ:firefox,chrome,opera(大体css3に対応したブラウザ)
- [経緯]
世間一般ではテクニックとしてcssのみでヘッダーを固定する方法が有名だけれど,これを拡張して見出しの列を固定できないかと考えた.
巷には既にこの機能を実現するjQueryプラグイン等が存在するようだが,そのほとんどがソースとなるtableを切り貼りして処理しているため,例えば内部にinput要素が含まれていたり,行を挿入したりソートしたりする際に無用な記述が必要となる.
そのためあくまでtableの機能を損なわない範囲でヘッダー,見出しの固定を実現する方法はないか探ってみた.
- [アイディア]
ヘッダー(フッター) の固定はこれまでどおりPushpin Headerテクニックで固定するとし,横方向のスクロールが行われた際,その移動量を元に固定したい列のセルの位置を(見た目が移動していないように)左右にずらせれば問題は解決するはずである.
しかし通常のth,tdはテーブル内の要素として振舞うので,position:relativeによる相対位置指定が機能しない.
一方,このテーブル内の要素はcssのdisplay 属性に対応しており,たとえdiv要素であってもdisplay属性を正しく設定すればtableの如く振る舞う.
ならば逆にtableの要素にdisplay属性をblockとしたら通常のdiv要素と同様に相対位置指定が可能となるのではないか?
下はその実験結果です.実装の簡便さからjQueryを使ってるけれど,素朴な作りをしているので他のツールや手組でも上手く行くと思います.
- [ポイント]
- table自体には全く手を入れていないので,おそらくどんな用途にも応用ができると思う.
- Pushpin Headerよりも更に1枚divを噛ませるところ.
table幅を固定する-スクロールバーを表示する-絶対位置指定を有効化するdiv要素がそれぞれ連携して動作する. - 固定したい列のセルにdisplay:blockを指定しているところ.これでjavascriptによる位置指定が動作するようになる.
- スクロールバー表示div要素のスクロールイベントに,固定列のtd要素の相対位置の設定処理を記述する.
- display:blockを指定したことで,通常のtd要素で有効だったvertical-align属性が無効になる.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<style type="text/css">
/*absolute配置の基準*/
#container{
width:410px;
height:200px;
position:relative;
padding-top:79px;
padding-bottom:83px;
overflow:hidden;
border:solid 1px black;
}
/*スクロールバーを表示させる*/
#scroller{
width:410px;
height:200px;
overflow:auto;
}
/*テーブル幅・高さを固定する*/
#fixer{
width:500px;
}
/*スクロール対象のテーブル*/
#scrollee th, td, tr{
border:solid 1px black;
}
#scrollee td, th{
width:100px;
height:75px;
background-color:white;
vertical-align:middle;
text-align:center;
}
/*header*/
#scrollee thead{
/*absoluteを指定し,containerに追い出す.*/
position:absolute;
width:500px;
top:0;
left:0;
z-index:2;
}
#scrollee thead tr th:first-child{
/*block表示を指定し,相対位置指定を有効化する.*/
display:block;
position:relative;
z-index:3;
}
#scrollee thead tr th:last-child{
display:block;
position:relative;
right:0;
z-index:3;
}
/*body*/
#scroller tbody{
width:500px;
}
#scrollee tbody tr td:first-child{
display:block;
position:relative;
z-index:1;
}
#scrollee tbody tr td:last-child{
display:block;
position:relative;
right:0;
z-index:1;
}
/*footer*/
#scrollee tfoot{
position:absolute;
width:500px;
bottom:0;
left:0;
z-index:2;
}
#scrollee tfoot tr td:first-child{
display:block;
position:relative;
z-index:3;
}
#scrollee tfoot tr td:last-child{
display:block;
position:relative;
right:0;
z-index:3;
}
</style>
<script type="text/javascript" charset="UTF-8" src="./jquery-1.7.1.min.js"></script>
<script type="text/javascript">
window.onload = function(){
//イベントを発生させるdiv
var scroller = document.getElementById("scroller");
var thead, theadF, theadL, tbodyF, tbodyL, tfoot, tfootF, tfootL;
init();
//スクロール時の処理
scroller.onscroll = function(){
//scrollerのスクロール位置
var left = scroller.scrollLeft;
var right = 106 - left;
thead.css("left", left * -1);
theadF.css("left", left);
theadL.css("right", right);
tbodyF.css("left", left);
tbodyL.css("right", right);
tfoot.css("left", left * -1)
tfootF.css("left", left);
tfootL.css("right", right);
};
scroller.onscroll();
//行を変化させたらjQeryオブジェクトを再構成.
/*
$("#scrollee tbody").append("<tr><td>A</td><td>B</td><td>C</td><td>D</td><td>E</td></tr>");
init();
*/
//jQueryオブジェクトを取得する.
function init(){
thead = $("#scrollee thead");
theadF = $("#scrollee thead tr th:first-child");
theadL = $("#scrollee thead tr th:last-child");
tbodyF = $("#scrollee tbody tr td:first-child");
tbodyL = $("#scrollee tbody tr td:last-child");
tfoot = $("#scrollee tfoot");
tfootF = $("#scrollee tfoot tr td:first-child");
tfootL = $("#scrollee tfoot tr td:last-child");
}
};
</script>
</head>
<body>
<div id="container"><!--absolute表示する際の基準-->
<div id="scroller"><!--スクロールバーを表示する-->
<div id="fixer"><!--tableの幅を固定する-->
<table id="scrollee">
<thead>
<tr>
<th>H1</th><th>H2</th><th>H3</th><th>H4</th><th>H5</th>
</tr>
</thead>
<tfoot>
<tr>
<td>F1</td><td>F2</td><td>F3</td><td>F4</td><td>F5</td>
</tr>
</tfoot>
<tbody>
<tr>
<td>11</td><td>12</td><td>13</td><td>14</td><td>15</td>
</tr>
…
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>
0 件のコメント:
コメントを投稿