レスポンシブを考える際に非常に邪魔、もとい、悩むのがtableです。
後述しますが、どうせいろいろ組み替えるならこれはどうだと思いついたものを形にしてみました。
見た目はそれなりに整えましたが、実のところ欠陥品と未完成品です。
特に汎用性がほとんどありませんから、このコードをつかっても状態に応じて書き換える箇所は多くでてくると思います。
ですので、軽く流してご覧いただければと思います。
[2014.8.23追記]
探したら、dlを用いたtableの記事「レスポンシブWebデザインでテーブルを使う時の小技」がありました。
細部は違うのですが、あちらの方が明らかに実用的ですね。
[2014.8.24追記]
jsを使ってカスタムしたものを追加。他も手直し。
IE7以降で対応するために
なによりもまずIE7とIE8にはメディアクエリが効きませんから、おなじみの「css3-mediaqueries-js」を使います。
後述のコードにもすこしIE7用の記述がありますが、IE7対策はこのぐらいです。
IE7対応のレスポンシブなtableもどき1
まずは求める結果とベースの構造から。
完成図としては右記の画像のようになります。
とりあえず800pxで分岐させていますが、これは横に並べたliの数とその中身の文字数から考えての調整です。
中身がもっと少なければ、もっと小さなpx数での分岐が可能です。
なお、仕組みとして2種類つくってみました。
tableサンプル
以下のリンクより実際のサンプルがご覧いただけます。スマートフォンなどでご覧いいただくとよいかもしれません。Androidでは未確認です。
sample1のコードは以下の通りです。
<div id="table-wrap">
<ol>
<li class="th"><dl><dt>見出し</dt><dd>内容</dd></dl></li>
<li><dl><dt>no.1</dt><dd>data1</dd></dl></li>
<li><dl><dt>no.2</dt><dd>data2</dd></dl></li>
<li><dl><dt>no.3</dt><dd>data3</dd></dl></li>
<li><dl><dt>no.4</dt><dd>data4</dd></dl></li>
<li><dl><dt>no.5</dt><dd>data5</dd></dl></li>
<li><dl><dt>no.6</dt><dd>data6</dd></dl></li>
<li><dl><dt>no.7</dt><dd>data7</dd></dl></li>
<li><dl><dt>no.8</dt><dd>data8</dd></dl></li>
<li><dl><dt>no.9</dt><dd>data9</dd></dl></li>
<li class="edge-r"><dl><dt>no.10</dt><dd>data10</dd></dl></li>
</ol>
</div>
続いてcss。なお、奇数行の背景色設定の部分は省いています。
#table-wrap ol {
overflow: hidden;
width: 100%;
margin: 0;
padding: 0;
list-style: none;
}
#table-wrap ol li {
font-size: 1%; //IE7でliの下に隙間ができる時の対策
line-height: 0; //同上
float: left;
width: 9.05%; //100を横にならぶliの個数で割るより少し小さめ
margin-bottom: 10px;
}
#table-wrap ol li dl {
font-size: 14px; //IE7でliの下に隙間ができる時の対策を元に戻す
line-height: 1.4; //同上
margin: 0;
text-align: center;
border-top: 1px solid #ccc;
border-left: 1px solid #ccc;
}
#table-wrap ol li dl dt {
height: 20px;
margin: 0;
padding: 1em 0;
border-bottom: 1px solid #ccc;
}
#table-wrap ol li dl dd {
height: 20px;
margin: 0;
padding: 1em 0;
border-bottom: 1px solid #ccc;
}
#table-wrap ol li.th {
font-weight: bold;
text-align: center;
}
#table-wrap ol li.edge-r dl {
border-right: 1px solid #ccc;
}
@media screen and (max-width: 800px) { //800pxで分岐させる場合
#wrap {
width: 90%;
margin: 0 auto;
}
#table-wrap ol {
overflow: visible; //ol内部の要素をはみ出させた際に表示させる
}
#table-wrap ol li {
float: none;
width: 100%;
margin-bottom: 0;
}
#table-wrap ol li dl {
overflow: hidden;
width: 100%;
margin: 0 -1px; //左右の線を表示
text-align: center;
border-right: 1px solid #ccc;
border-bottom: 0;
}
#table-wrap ol li dl dt {
float: left;
width: 49%; //1xpの線を追加した際にカラム落ちをさせないため50%にしない
height: auto;
padding: 1em 0;
border-right: 1px solid #ccc;
border-bottom: 0;
}
#table-wrap ol li dl dd {
float: left;
width: 50%;
height: auto;
padding: 1em 0;
border-bottom: 0;
}
#table-wrap ol li.edge-r dl {
border-bottom: 1px solid #ccc;
}
}
なお、IE7以降ということで末尾のliを指定する余計なクラス「.edge-r」も入っていますが、IE7がなくていいなら「:last-child」などで指定すればHTML側のクラスは不要です。
基本的な構造
レスポンシブ対応のためにdivで構築する方法も見かけますが、もう少し対象の意味付けにあったコーディングはできないものかと考えました。
olのリストとし、liの中にdlを入れることで各データを順番に並べるという方法を考え、ウィンドウが狭い場合は縦に並ぶようにしています。
このコーディングであれば少なくとも、「順番に並んだデータ」という意味付けはできるのではと思います。…残念ながら「表」とはいえませんが。
cssの方は数値がやや適当ですが、「liとli」や「dtとdd」を横に並べた際に安全なラインでつくることを重視はしています。
欠陥部分
コードを見ていただければわかりますが、そもそもの部分で大きな問題があります。横一列にdlを並べる場合、dtとdd内部のテキスト増減に対応ができません。
liが横に並んでいる際にはdlもただそこにあるだけなので、当然横にあるdtやddの高さの変化には連動しないためです。1つでも2行になると破綻します。
一応dtとddの高さを20px(2段になっても下にはみ出ない程度)で固めていますので、表示がおかしくなりますが表自体は壊れません。しかしこれでは2行にまでしか対応できず、やはり無理矢理です。
サンプルコード2
3行にしたものも念のため下記に記載します。
<div id="table-wrap2">
<ol>
<li class="th"><dl><dt>出演順序</dt><dd>出演動物名</dd><dd>出演日時</dd></dl></li>
<li><dl><dt>no.1</dt><dd>Rat</dd><dd>1914年</dd></dl></li>
<li><dl><dt>no.2</dt><dd>Ox</dd><dd>1914年</dd></dl></li>
<li><dl><dt>no.3</dt><dd>Tiger</dd><dd>1915年</dd></dl></li>
<li><dl><dt>no.4</dt><dd>Hare</dd><dd>1916年</dd></dl></li>
<li><dl><dt>no.5</dt><dd>Dragon</dd><dd>1917年</dd></dl></li>
<li class="edge-r"><dl><dt>no.6</dt><dd>Sprent</dd><dd>1918年</dd></dl></li>
</ol>
</div>
続いてcss。
#table-wrap2 ol {
overflow: hidden;
width: 100%;
margin: 0;
padding: 0;
list-style: none;
}
#table-wrap2 ol li {
font-size: 1%;
line-height: 0;
float: left;
width: 14.2%;
margin-bottom: 10px;
}
#table-wrap2 ol li dl {
font-size: 14px;
line-height: 1.4;
margin: 0;
text-align: center;
border-top: 1px solid #ccc;
border-left: 1px solid #ccc;
}
#table-wrap2 ol li dl dt {
height: 20px;
margin: 0;
padding: 1em 0;
border-bottom: 1px solid #ccc;
}
#table-wrap2 ol li dl dd {
height: 20px;
margin: 0;
padding: 1em 0;
border-bottom: 1px solid #ccc;
}
#table-wrap2 ol li.th {
font-weight: bold;
text-align: center;
}
#table-wrap2 ol li.edge-r dl {
border-right: 1px solid #ccc;
}
@media screen and (max-width: 800px) {
#table-wrap2 ol {
overflow: visible;
}
#table-wrap2 ol li {
float: none;
width: 100%;
margin-bottom: 0;
}
#table-wrap2 ol li dl {
overflow: hidden;
width: 100%;
margin: 0 -1px;
text-align: center;
border-right: 1px solid #ccc;
border-bottom: 0;
}
#table-wrap2 ol li dl dt {
float: left;
width: 33%;
height: auto;
padding: 1em 0;
border-bottom: 0;
}
#table-wrap2 ol li dl dd {
float: left;
width: 33%;
height: auto;
padding: 1em 0;
border-bottom: 0;
border-left: 1px solid #ccc;
}
#table-wrap2 ol li.edge-r dl {
border-bottom: 1px solid #ccc;
}
}
%で指定する幅を適宜個数で割っていますが、基本的には先ほどのサンプルと変わりません。
tableサンプル jQuery使用版
htmlは同じで、scriptタグとその中身が追加部分です。
目的は、サンプル1の柔軟性の欠如を解決すること。dtとddの高さを自動で揃えるJavaScriptライブラリの「heightLine.js」を使用しました。
以下がサンプルへのリンクです。
追加したコードは以下の通り。
<script>
$(document).ready(function() {
var items1 = "div#table-wrap dl";
var items2 = "div#table-wrap2 dl";
var count1 = $(items1).length;
var count2 = $(items2).length;
function itemsNum1() {
for (var i = 0 ; i < count1 ; i++){
$('#table-wrap dl:eq('+ i +') dt,#table-wrap dl:eq('+ i +') dd').heightLine({maxWidth:800});
}
return itemsNum1;
}
function itemsNum2() {
for (var i = 0 ; i < count2 ; i++){
$('#table-wrap2 dl:eq('+ i +') dt,#table-wrap2 dl:eq('+ i +') dd').heightLine({maxWidth:800});
}
return itemsNum2;
}
function checkWindowSize() {
if ( $(window).width() > 800) {
$(items1 + ' dt').heightLine({minWidth:800});
$(items1 + ' dd').heightLine({minWidth:800});
$(items2 + ' dt').heightLine({minWidth:800});
$(items2 + ' dd:nth-of-type(1)').heightLine({minWidth:800});//ddの1行目の高さを揃える
$(items2 + ' dd:nth-of-type(2)').heightLine({minWidth:800});//ddの2行目の高さを揃える
} else {
$(document).ready(itemsNum1);
$(document).ready(itemsNum2);
}
}
$(document).ready(checkWindowSize);
var timer = false;
$(window).resize(function() {
if (timer !== false) {
clearTimeout(timer);
}
timer = setTimeout(function() {
$(document).ready(checkWindowSize);
}, 200);
});
});
</script>
基本的な構造
追加したのは、jquery.heightLine.jsを反映させるための部分です。
800px以上と以下で高さを揃え得る要素が変わるため、800pxで分岐させています。その後、リサイズとリロード時に処理を実行しています。
また、800px以下の場合は縦に重なるliごとにdtとddの高さを合わせる必要があります。そこで、dlの数を計測して、その数を「:eq()」の中にいれて個別に出力させています。
この計測と出力がイマイチ上手くいっている気がしません。
リサイズごとに毎回処理を繰り返すのが重さの原因だと思うので、なんとか回避したいといろいろ試していてこんな形になりましたが…。効果はあまりありませんでした。
「.heightLine({minWidth:800});」の「minWidth:800」に部分は、heightLine.jsに設定されているレスポンシブの設定です。これがないとリサイズによる変化がズレる時があったのでいれています。
resizeをつかっていると非常に重いので、「[jQuery] ウインドウのリサイズ操作が終わった時にだけ処理を実行する」という記事を参考に安全策を組み込みました。それが「(checkWindowSize)」の部分です。
未完成部分
形にはなったのですが、コードの書き方と処理のさせ方自体がまずく、処理が重くなってしまいました。
加えて、横に並ぶliのwidthをcssで%設定しないとならないため、liの数が変わるたびに設定しなおさなければなりません。つまり、汎用性がありません。
liの数を取得して全幅で割ってwidtに入れればいいのですが、現時点でさえ重いのにこれ以上動的なものをいれるのもどうかと悩む部分ではあります。
tableにはいろいろなパターンがあり、汎用的なものは相当難しいと思います。汎用性よりも拡張性のほうがよいのかもしれません。
結び
思いつきで前例をあまり調べずに作ってしまいましたが、すでにこの記事と同じものがあるかもしれません。または、この構造の欠陥から放棄されたかもしれません。またはもっと良い指定の仕方があるのかも。
効率的な動作をする作り方がよく分かっていないのが致命的ですね..。
なお、個人的にコーディングの提案的なものは苦手であまりやらないのですが、今回は公開によって間違いのご指摘やご助言をいただける可能性を考慮し、記事にしてみました。
この方法にこだわるつもりはないのですが、もう少しなんとかなるならそれはそれで嬉しいなと思う次第です。
時間ができたらまたすこし調整やらを行いたいと思います。
「display:table-cell;」とIE7
「display:table-cell;」や「display:box;」が使えたらと思いつつ、IE7では厳しいのが現状の模様です。
「display:table-cell;」に関しては、「display-table.htc」という方法があるようですが、htcに加えて、利用規約で制作元へのリンクが必要(readme.txtも同時にアップする必要があるようですが、そこに書かれたリンクだけで良いのかどうか判断がつきませんでした)にも見え、クライアントワークではちょっと厳しい印象でした。
0人がこの記事を評価
役に立ったよという方は上の「記事を評価する」ボタンをクリックしてもらえると嬉しいです。
連投防止のためにCookie使用。SNSへの投稿など他サービスとの連動は一切ありません。