2018年4月27日金曜日

グリッドレイアウトによるピュアCSSなスクロールテーブルの実装

CSSにおける大きな課題の一つとして「ヘッダー・フッターを固定した上での表のスクロール」が挙げられます. 既にこのブログにおいてもCSSによるおそらく最も簡単にヘッダとフッタを固定するスクロールテーブルの実装方法として言及していましたが, この方法を紹介してから既に6年が過ぎており, いささか時代遅れの印象があります.

そこで, 本記事ではよりモダンな方法で簡潔にスクロールテーブルを実装する方法について紹介します.



それではコードについてみてみましょう.

table{
 display: grid;
 grid-auto-flow: row;
 grid-auto-rows: 2.5em;
 width: 600px;
 height: 300px;
 overflow: scroll;
 grid-gap: 2px;
}
thead, tbody, tfoot{
 display: contents;
}
th, td{
 border: 1px black solid;
 display: grid;
 justify-content: center;
 align-content: center;
}
tr{
 display: grid;
 grid-auto-flow: column;
 grid-template-columns: repeat(11, 100px);
 grid-gap: 2px;
}
thead>tr, tfoot>tr, tr>*:first-child, tr>*:last-child{
 position: sticky;
}
thead>tr, tfoot>tr{
 z-index: 2;
}
:not(tbody)>tr>*{
 background-color: yellow;
}
tr>*:first-child, tr>*:last-child{
 z-index: 1;
 background-color: pink;
}
thead>tr{top: 0;}
tfoot>tr{bottom: 0;}
tr>*:first-child{left: 0;}
tr>*:last-child{right: 0;}

<table>
 <thead>
  <tr><th>a</th><th>a</th><th>a</th><th>a</th><th>a</th><th>a</th><th>a</th><th>a</th><th>a</th><th>a</th><th>a</th></tr>
 </thead>
 <tbody>
  <tr><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td></tr>
  <tr><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td></tr>
  <tr><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td></tr>
  <tr><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td></tr>
  <tr><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td></tr>
  <tr><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td></tr>
  <tr><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td></tr>
  <tr><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td></tr>
  <tr><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td></tr>
  <tr><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td></tr>
  <tr><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td></tr>
  <tr><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td></tr>
  <tr><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td></tr>
  <tr><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td></tr>
  <tr><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td></tr>
  <tr><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td></tr>
  <tr><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td></tr>
  <tr><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td></tr>
  <tr><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td></tr>
  <tr><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td></tr>
  <tr><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td><td>a</td></tr>
 </tbody>
 <tfoot>
  <tr><th>a</th><th>a</th><th>a</th><th>a</th><th>a</th><th>a</th><th>a</th><th>a</th><th>a</th><th>a</th><th>a</th></tr>
 </tfoot>
</table>

実際の動作を確認する


動作原理


スクロールテーブルを作るに応って利用したCSSの機能は次の通りです.

  • overflow: scrollを用いてテーブル要素をスクロール可能とする.
  • display: gridを用いてテーブルの構造をグリッド構造に再構成する.
    なお, 技術的にはcolspanによるセルの結合も可能.
    また, このプロパティはセル内の横位置・縦位置の制御(align-content/justify-content)にも利用する.
  • display: contentsを用いてコンテナノード(thead, tbody, tfoot)におけるボックスの生成を抑制する. こうすることで, あたかもtable要素直下にtr要素が配置されているかのように扱える.
    ※従ってテーブルを単一のtbody要素で構成する場合はこの設定は必須ではない.
  • position: stickyを用いてヘッダー・フッター・先頭/末尾列の表示位置を固定する(スクロールバーの位置に依存しない).
これらを使ってテーブル構成要素群のスタイルを上書きすることで, テーブルレイアウトをよりスクロール制御のしやすいグリッドレイアウトを使って再現しています.

課題 


動作環境が限られます. FireFox/Chromeでは動作するものの, IE/Edge/Safariでは動作しないでしょう.
とは言え, 動作原理的にtable要素を使わなければ(div要素などを使って2次元構造を作れば)動く環境が広がるものと考えられるため, 検討する価値はあるでしょう.

0 件のコメント:

コメントを投稿