2012年2月2日木曜日

複雑なレイアウトのテーブルを実装する際のヒント

※ie8でも同様の仕組みを実現することができる模様.
もっといい方法が見つかったのでそちらも参照のこと.

前回の記事をヒントにテーブルのレイアウトをカスタマイズする方法を探ってみる.
対応するブラウザはcss3のnth-childセレクタが使用可能なブラウザ(firefox,opera,chrome等).
通常table要素はdisplayスタイルがtable要素独自のものとなっている.これは表形式データの簡易表示にはとても便利なものだが,いざ見た目をカスタマイズしようとすると途端に処理が煩雑となる.例えばcolspan,rowspanによるセルの結合やら、セル内部の幅による列幅のズレへの対応がそれだ.tableタグのもつ便利機能がかえって思うようなカスタマイズの足かせとなってしまっているのだ.
ではこの機能を全て排除して自力でレイアウトの操作を行うことはできないのだろうか?
前回、td要素にdisplay:blockを指定し相対位置指定が有効となったことを見た.これを発展させてテーブルを構成する全ての要素にdisplay:blockを指定してみよう.
一般にdisplay:blockを指定した要素はブロック要素として振る舞うが,table要素群においても例外ではない.要するにtable要素は単なるdiv要素の連なりと同等になる.このときtable要素の構造に着目すると,tr要素の中のtd要素について表示位置の指定ができそうである.これらを念頭において下の例を見てみよう。

この例では1行の内容を複雑に区切ってセルを配置している.縦に2分割している部分と3分割している部分があるため,通常のrowspan,colspanでの実現は骨が折れるところだが,行毎にセルの位置を指定することでこのようなレイアウトも元のtable要素の構造を壊すことなく実現することが出来た.
また副次的な結果としてこの組み方であればセルの内容が長くなってもレイアウトが壊れる心配がない.tdのwidthとheightによりガチガチに固定されているためである.
というわけで、テーブルのレイアウトが余りに複雑で制御出来ずに困っている場合は試してみる価値がある.
    [記述追加 ]
  • vertical-alignスタイルは無視されてしまうので,中詰め・下詰めを実現するにはpadding-top,line-height値を使う必要がある.
  • tfootは通常tbodyの前に記述すべきだが,この細工を行うことによりHTMLレンダリングがシーケンシャルに行われるようになるため,順序をthead-tbody-tfootに変更しなければならない.環境によってはjavascriptによる追加処理を記述する必要があるかもしれない.
  • display:table-cellとblockとではtd,th要素に設定されているpadding(≒tableのcellpadding値)の分width,heightの解釈値がずれてしまうようだ.
※まあ,古いieとかはダメっぽいのですが…

<!DOCTYPE html>
<html>
  <head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
  <style type="text/css">
    /*tableの要素を単なるblock要素の入れ子として扱う*/
    table, thead, tfoot, tbody, tr, th, td{
      display:block;
    }
    table{
      border:solid 1px black;
      width:252px;
    }
    thead th{
      border:solid 1px red;
    }
    tbody td{
      border:solid 1px green;
    }
    tfoot td{
      border:solid 1px blue;
    }
    /*tdの位置指定の基準となるようにposition:relativeを指定する*/
    tr{
      height:30px;
      position:relative;
    }
    /*td要素の位置を絶対指定とする*/  
    td, th{
      position:absolute;
      font-size:8px;
      padding:0;
    }
    tr td:nth-child(1), tr th:nth-child(1){
      left: 0;
      top: 0;
      width: 8px;
      height: 28px;
    }
    tr td:nth-child(2), tr th:nth-child(2){
      left: 10px;
      top: 0;
      width: 48px;
      height: 13px;
    }
    tr td:nth-child(3), tr th:nth-child(3){
      left: 10px;
      top: 15px;
      width: 48px;
      height: 13px;
    }
    tr td:nth-child(4), tr th:nth-child(4){
      left: 60px;
      top: 0;
      width: 58px;
      height: 28px;
    }
    tr td:nth-child(5), tr th:nth-child(5){
      left: 120px;
      top: 0;
      width: 128px;
      height: 8px;
    }
    tr td:nth-child(6), tr th:nth-child(6){
      left: 120px;
      top: 10px;
      width: 128px;
      height: 8px;
    }
    tr td:nth-child(7), tr th:nth-child(7){
      left: 120px;
      top: 20px;
      width: 128px;
      height: 8px;
    }
  </style>
  </head>
  <body>
    <table>
      <thead>
        <tr><th>1</th><th>2</th><th>3</th><th>4</th><th>5</th><th>6</th><th>7</th></tr>
      </thead>
      <tbody>
        <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td></tr>
        <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
        <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
        <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
        <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
        <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
      </tbody>
      <tfoot>
        <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td></tr>
      </tfoot>
    </table>
  </body>
</html>

0 件のコメント:

コメントを投稿