グリッド作成メモ - htmlでtableのheaderを固定する。

エクセルのようなヘッダが常に定位置に固定されたテーブルを作成したい。
このテーブルの事をここではグリッドと呼ぶ事にする。

出来上がったサンプルはこちら。IEのみ対応。

http://www.geocities.jp/uchblog/grid/

構造の分析

一つのテーブルを書いてスクロールさせる事は無理。なのでヘッダとボディに分けてみる。

作成するテーブルは4つ。

  • 上部のカラムヘッダ - gridHeaderColumn(CLASS)
  • 側部のロウヘッダ - gridHeaderRow(CLASS)
  • 上部・側部の重なっているヘッダ - gridHeaderRowColumn(CLASS)
  • データ本体 - gridBody(CLASS)

グリッドの位置やサイズの為にDivブロックを定義

  • グリッドエリア - gridArea(ID)

実現させる為に必要な事

  • 縦、横スクロールのどちらかだけを定位置にする方法。
  • スクロール時に関連するテーブルの連動。

単純に位置指定だけだからJava Scriptを使わずにスタイルシートで何とかなるんじゃないかとリファレンスを眺める。IE用のタグで良さそうなのを発見。expressionというやつを使えば出来そう。

*追記:expressionって、これタグじゃなくてIEスクリプトのビルドイン関数だね。

ベースとなるHTMLソース

グリッドエリア内に4つのテーブルを定義。グリッドにはIDを振りテーブルにはCLASSを指定。特別な記述はなく極々単純なソース。

<!-- saved from url=(0013)about:internet -->
<HTML>

<HEAD>
<TITLE>example - grid</TITLE>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=Shift_JIS" />
<META HTTP-EQUIV="Content-Style-Type" CONTENT="text/css" />
<LINK REL="stylesheet" TYPE="text/css" HREF="layout.css"/>
<LINK REL="stylesheet" TYPE="text/css" HREF="table.css"/>
</HEAD>

<BODY>

<DIV ID="gridArea">

<TABLE CLASS="gridHeaderRowColumn">
<THEAD>
<TR>
<TD>&nbsp;</TD>
</TR>
</THEAD>
</TABLE>

<TABLE CLASS="gridHeaderColumn">
<THEAD>
<TR>
<TH>data01</TH>
<TH>data02</TH>
<TH>data03</TH>
<TH>data04</TH>
<TH>data05</TH>
<TH>data06</TH>
<TH>data07</TH>
<TH>data08</TH>
<TH>data09</TH>
<TH>data10</TH>
</TR>
</THEAD>
</TABLE>

<TABLE CLASS="gridHeaderRow">
<THEAD>
<TR><TH>1</TH></TR>
<TR><TH>2</TH></TR>
<TR><TH>3</TH></TR>
<TR><TH>4</TH></TR>
<TR><TH>5</TH></TR>
<TR><TH>6</TH></TR>
<TR><TH>7</TH></TR>
<TR><TH>8</TH></TR>
<TR><TH>9</TH></TR>
<TR><TH>10</TH></TR>
</THEAD>
</TABLE>

<TABLE CLASS="gridBody">
<TBODY>
<TR>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
</TR>
<TR>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
</TR>
<TR>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
</TR>
<TR>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
</TR>
<TR>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
</TR>
<TR>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
</TR>
<TR>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
</TR>
<TR>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
</TR>
<TR>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
</TR>
<TR>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
</TR>
</TBODY>
</TABLE>

</DIV>

</BODY>

</HTML>

レイアウト

グリッドエリア

任意のサイズと位置が指定出来るようにする。スクロール可能なようスクロールバーを表示する。

4テーブルの配置

適当に配置し一つのテーブルっぽく見せる。それと各セルのサイズ指定。

ここで問題発生。各テーブルのセルに幅サイズの指定するが期待通りに反映されず。親ブロックに収まるよう自動的に調整されるみたい。オーバーフローはしない。

原因はTH、TD各セルの自動改行が有効になっている為。NOWRAPを指定すると期待通りの幅に。

が、ここでさらに問題発生。TH、TDタグの属性としてNOWRAPを指定すると期待通りだがスタイルシートでのしていWHITE-SPACE:NOWRAP;だとサイズは変わらず。いろいろ調べて見るが有用な情報はなし。WHITE-SPACEは改行の無効にはなるけれどサイズの指定には影響しないみたい。属性NOWRAPはスタイルシートのどれに影響を与えるんだろうか?わかんないから保留で要調査とする。とりあえず属性のNOWRAPでいく。

NOWRAPを加えたhtmlソース
<!-- saved from url=(0013)about:internet -->
<HTML>

<HEAD>
<TITLE>example - grid</TITLE>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=Shift_JIS" />
<META HTTP-EQUIV="Content-Style-Type" CONTENT="text/css" />
<LINK REL="stylesheet" TYPE="text/css" HREF="layout.css"/>
<LINK REL="stylesheet" TYPE="text/css" HREF="table.css"/>
</HEAD>

<BODY>

<DIV ID="gridArea">

<TABLE CLASS="gridHeaderRowColumn">
<THEAD>
<TR>
<TD nowrap>&nbsp;</TD>
</TR>
</THEAD>
</TABLE>

<TABLE CLASS="gridHeaderColumn">
<THEAD>
<TR>
<TH nowrap>data01</TH>
<TH nowrap>data02</TH>
<TH nowrap>data03</TH>
<TH nowrap>data04</TH>
<TH nowrap>data05</TH>
<TH nowrap>data06</TH>
<TH nowrap>data07</TH>
<TH nowrap>data08</TH>
<TH nowrap>data09</TH>
<TH nowrap>data10</TH>
</TR>
</THEAD>
</TABLE>

<TABLE CLASS="gridHeaderRow">
<THEAD>
<TR><TH nowrap>1</TH></TR>
<TR><TH>2</TH></TR>
<TR><TH>3</TH></TR>
<TR><TH>4</TH></TR>
<TR><TH>5</TH></TR>
<TR><TH>6</TH></TR>
<TR><TH>7</TH></TR>
<TR><TH>8</TH></TR>
<TR><TH>9</TH></TR>
<TR><TH>10</TH></TR>
</THEAD>
</TABLE>

<TABLE CLASS="gridBody">
<TBODY>
<TR>
<TD nowrap>data</TD>
<TD nowrap>data</TD>
<TD nowrap>data</TD>
<TD nowrap>data</TD>
<TD nowrap>data</TD>
<TD nowrap>data</TD>
<TD nowrap>data</TD>
<TD nowrap>data</TD>
<TD nowrap>data</TD>
<TD nowrap>data</TD>
</TR>
<TR>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
</TR>
<TR>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
</TR>
<TR>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
</TR>
<TR>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
</TR>
<TR>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
</TR>
<TR>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
</TR>
<TR>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
</TR>
<TR>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
</TR>
<TR>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
<TD>data</TD>
</TR>
</TBODY>
</TABLE>

</DIV>

</BODY>

</HTML>
レイアウト用css layout.css
/* 一般 */

 *{margin:0;padding:0;}
html, body{overflow:hidden;}

/* グリッドエリア */

#gridArea{

	position:		absolute;

	top:			0em;

	left:			0em;

	width:			100%;

	height:			100%;

	border:			0;

	overflow:		auto;

}

/* グリッドポジション */

.gridHeaderRowColumn,
.gridHeaderRow,
.gridHeaderColumn,
.gridBody{

	position:		absolute;

}

.gridHeaderColumn,
.gridBody{

	left:			3.0em; /* カラムヘッダーとボディの位置(横) */

}

.gridHeaderRow,
.gridBody{

	top:			1.8em; /* ロウヘッダーとボディの位置(縦) */	

}

/* セルサイズ */

.gridHeaderRowColumn,
.gridHeaderRow{

	width:			3em; /* グリッドポジションと関連付いている */

}

.gridHeaderRowColumn,
.gridHeaderColumn{

	height:			1em; /* グリッドポジションと関連付いている */

}

.gridBody th,
.gridBody td,
.gridHeaderColumn th,
.gridHeaderColumn td{

	width:			7em; /* ボディとカラムヘッダセルのサイズ */

}
見栄え定義

せっかくなんでボーダーラインも綺麗にしてみる。あとヘッダにも色づけ。

table.css
/* 罫線っぽいボーダーライン */

table.gridHeaderColumn,
table.gridHeaderRow,
table.gridHeaderRowColumn,
table.gridBody{

	border: 1px solid black;

	border-collapse:collapse;

}

table.gridHeaderColumn th, table.gridHeaderColumn td,
table.gridHeaderRow th, table.gridHeaderRow td,
table.gridHeaderRowColumn th, table.gridHeaderRowColumn td,
table.gridBody th, table.gridBody td{

	border: 1px solid black;

	padding: 0.3em;

	text-align:left;

	vertical-align:top;

}


/* ヘッダの色 */


table.gridHeaderColumn,
table.gridHeaderRow,
table.gridHeaderRowColumn{

	background: silver;

}

見栄えはいい感じになってきた。あとはヘッダが固定出来れば完了。

ヘッダを固定する

expressionはこんな感じで。詳しくはネット等で検索を。

grid.css
/* ヘッダー部がスクロールせず固定する為の指定 (for IE) */
.gridHeaderRowColumn{

	top: 			expression(
					   document.getElementById('gridArea')
					&& document.getElementById('gridArea').scrollTop
				);

	left:			expression(
					   document.getElementById('gridArea')
					&& document.getElementById('gridArea').scrollLeft
				);

}

.gridHeaderRow{

	left:			expression(
					   document.getElementById('gridArea')
					&& document.getElementById('gridArea').scrollLeft
				);

}

.gridHeaderColumn{

	top: 			expression(
					   document.getElementById('gridArea')
					&& document.getElementById('gridArea').scrollTop
				);

}

/* 各テーブルのz-index */

.gridHeaderRowColumn{

	z-index:		4;

}

.gridHeaderColumn{

	z-index:		3;
}

.gridHeaderRow{

	z-index:		2;

}

.gridBody{

	z-index:		1;

}

htmlソースにgrid.css読み込みを追加。

<LINK REL="stylesheet" TYPE="text/css" HREF="grid.css"/>

取り合えず完成。

スタイルシートってやっぱりいいね。

既知の問題点

  • IE専用。
  • セルサイズの指定。
  • ベースとなるソースが美しくない

GeckoSafariOperaにも対応させたい。ってか出来れば標準仕様で実現させたい。セルのサイズ指定も何とかしたい。NOWRAPは出来れば避けたい。テーブルのサイズ指定で何とかなるっぽいけどそれはメンテが面倒になりそうだから嫌。ベースとなるHTMLソースもDivでのエリア指定までは良いとしてもテーブルを4つ個別に書かなきゃいけないとこが何か嫌だ。

メンテナンスや扱いやすさを考えるとJava Scriptで書いた方がいい気がしてきた。html本体にJava Script gridソース、データはCSVとか。これは簡単に出来そう。今度作ろう。

あ、誰か改良して下さい。