CSS だけで table をレスポンシブデザインに対応させる

レスポンシブデザインのイメージ

標準のテーブル(table)は、親のコンテナ(解像度)に合わせて最大幅が変化します。 したがって、スマートフォンなどの水平方向の解像度が低いデバイスで閲覧するとき、テーブルの各セルの幅は非常に小さくなります。 セルの幅が小さくなると、その中にあるテキストは折り返しが多くなって著しく読みにくくなります。

そこでメディアクエリ(@media)を使って、低解像度のときでもテーブルを読みやすくします。 JavaScript(jQuery) を使う手法などがありますが、ここでは CSS だけで実現します。

CSS だけで実現する手法もいくつか種類がありますが、高解像度(PC)での閲覧時と大きく見た目が変化せず、 汎用性の高い、スクロールバーを表示する手法を解説します。

実行結果

先に実行結果を示します。オリジナルは Windows 番の Google Chrome でキャプチャしたものです。 iOS 7.0 の iPhone 5S と Androis 4.2 の Google Nexus 4 で表示した画像をキャプチャしています。

Windows 版 Google Chrome のキャプチャです。

Windows8 Chrome で開いた画面のキャプチャ

左が iPhone 5s (iOS 7.0)、右が Google Nexus 4 (Android 4.2) のキャプチャです。

iOS 7.0 の iPhone 5s と、Android 4.2 の Google Nexus で開いた画面のキャプチャ

実際のコード

実際にこのページで適応した結果が次のテーブルですが、広告等はブラウザの可変に連動しない点に注意してください。

テーブルヘッダテーブルセルの長いテキスト。このテキストが折り返されずに表示されます。
テーブルヘッダテーブルセルの長いテキスト。このテキストが折り返されずに表示されます。
テーブルヘッダテーブルセルの長いテキスト。このテキストが折り返されずに表示されます。

基本的な CSS の設定

基本的な CSS の設定は次の通りです。最低限のレスポンシブデザインは次のコードだけで成立します。 メディアクエリ(@media) の解像度設定については適宜変更してください。 また、適用する環境に合わせて、本文中の table 要素にだけ適用するような CSS セレクタを設定したほうが良いでしょう。

@media screen and (max-width: 819px)
{
table
{
    display: block;
    overflow-x: auto;
}

th, td
{
    width: 819px;
    white-space: nowrap;
}
}

まず table 要素の display プロパティを変更します。table 要素の規定値は table-cell です。 これを block に変更し、table 要素の最大幅をデバイスの解像度に制限されないようにします。 さらに、テーブルが横方向に長いとき、スクロールバーを表示するために overflow-x: auto; を設定します。

次いでテーブルのセル td / th 要素に white-space: nowrap; を設定します。 そうすることで、セルの中にあるテキストはセルの幅に合わせて折り返されることがなくなり、水平方向に広がり続けます。

th / td 要素 (= セル) の幅が広がり、そのコンテナである table 要素の幅も広がると、 先に設定した overflow-x: auto; によってスクロールバーが表示されます。

セルの幅が狭い状況を考慮する

th / td 要素の width プロパティには、これらの CSS が適用されるときの解像度の値を設定します。 サンプルの場合では、819px を指定しています。

これはセルの幅が狭いときに、テーブルの幅いっぱいにセルが広がるようにするためです。 コンテナ (親要素) に display: table が設定されないとき、 display: table-cell が設定された子要素の幅は、auto によって最小限の幅に決定されます。

セルの幅縮まった状態のテーブルでも外観に問題がないのであれば width プロパティの設定は不要ですが、 ほとんどの場合に、最大幅まで広げたほうが見栄えは良いと思います。

android / iOS でスクロールバーを常に表示する

デスクトップ向けブラウザで確認する限りは常にスクロールバーが表示されますが、 メインターゲットとなる android や iOS では、スクロールバーが表示されません。

スクロールそのものは可能ですが、ユーザに対し、スクロール可能なコンテンツであることを明示する必要があります。

-webkit-overflow-scrolling: touch; を table 要素に適用することで、 スクロール中にのみスクロールバーを表示する方法はありますが、それでは問題が解決しません。 また width / height プロパティに絶対値が必要になるなど使い勝手も悪く、対応する環境も安定しないようです。

webkit 向けの CSS ハックを使う

Android / iOS の標準ブラウザでスクロールバーを常に表示するためには、それらのレンダリングエンジンである、WebKit 向けの CSS ハックを使います。 WebKit はスクロールバーに CSS を適用することが可能で、CSS を適用した時点で、その設定が反映されたスクロールバーが表示されます。

具体的には次のような CSS を追加します (先のコードの続きで良い) 。 WebKit 向けの CSS ハックはデスクトップ向けの Google Chrome などでも反映されるので確認しやすいでしょう。

/* スクロールバー全体 */
table::-webkit-scrollbar
{
    height: 10px;
    height: 1rem;
    background-color: #F1F1F1;
}

/* スクロールバーのつまみ(可動部分) */
table::-webkit-scrollbar-thumb
{
    background-color: #BCBCBC;
    border-radius: 12px;
    border-radius: 1.2rem;
}

table::-webkit-scrollbar-thumb:hover
{
    background-color: #A9A9AA;
}

基本的に、marginpadding などの設定はできません。 border に背景色と同じ色を設定して、擬似的に間を取ることはできます。

ここで重要なのはスクロールバーであることがユーザに伝わることです。 言い換えれば適切なアフォーダンスが得られるようなデザインが必要です。

このサンプルではスクロールバーの角を丸くして、テーブルとは性質が異なるものであることを示します。 角ばった状態のままだと、テーブルのセルと識別しにくいように見えます。 他に、背景画像を設定するか、UI らしい影やグラデーションを設定することも考えられます。

他の手法との比較

他に、表示形式をリストに変更する方法や JavaScript(jQuery) を使ってレスポンシブデザインに対応する方法があります。

リスト形式で表示する

表示形式にリストを使う方法は、テーブルの前後の文章で "テーブル/表" などの単語を使うとき、正しく情報が伝わらなくなる可能性があります。 "表の ~ " としてテーブルを参照する文章があるとき、リストが表示されていることは良くはありません。

他にも、リスト形式で表示する手法には問題があります。

テーブルヘッダの表示位置は限定されるでしょう。例えばヘッダが2つあるテーブルが含まれる可能性があるとき、対応することは困難です。 また行か列の先頭のセルにしかヘッダを置くようにしなければ、CSS が複雑になります。結合されたセルが含まれるケースも対応が困難でしょう。 thead, tfoot, colgroup にも配慮する必要があります。

ここで解説する手法なら、基本的な表示方法は高解像度時(デスクトップ向け)と同じですから、複雑なパターンを考慮しなくてよいです。

もし、テーブルを使う用途が限定されていて、"テーブル" や "表" といった単語を使わないなら、リスト形式で表示する手法を使っても良いと思います。 例えば "レシピ" などの用語で説明する場合です。

JavaScript で対応する

JavaScript で対応する場合には、あらゆるパターンで対応することが出来るでしょう。 ここで解説する手法と同じように単純にスクロールするパターンも実現することができますし、それ以外の複雑なレイアウトも実現することが出来るでしょう。

一方で低解像度デバイスを識別して JavaScript を読み込む必要があります。 さらに JavaScript そのものの開発には大きなコストがかかります。 実質的には jQuery などのプラグインとして配布されているものを使うことになるでしょう。

解説した手法の欠点

解説した手法の欠点は、セル内に含まれるテキストが多い場合、それらが常に横に伸びきってしまう点です。 しかしながら、よほど長いテキストは最初からテーブルで表現しないほうが良いでしょう。

セル内で br 要素などによって改行されていればこの問題は解決されます。 あるいは、長いテキストが埋め込まれることが多いのであれば、リスト形式で表示することを検討します。