tableタグで作成した表をレスポンシブに対応する方法を実装例を挙げてわかりやすく解説します。
パソコンのデスクトップ画面サイズを基準に作成した横長いレイアウトの表は、スマートフォン画面では、ブラウザの幅にきれいに収まりません。収まったとしても、個々のセルが縮小して見づらい印象を与えてしまいます。特に、列の多い表や、セルの中のコンテンツ量が多い場合は、対策が必要となります。
そこで、table表のレスポンシブ化やレスポンシブデザインを取り入れることで解決することができます。
table表のレスポンシブ対応の仕方
tableタグで作成する表は、コードが複雑になることもあるため、はじめは、デスクトップ画面を基準にHTMLとCSSで表を作成します。そのうえで、スマホ画面サイズで、どのようなビジュアルやテーブルレイアウトに切り替えるか、という点をイメージします。
コードに慣れてきたら、作成基準を逆にして、モバイルファーストの考え方を適用してもよいでしょう。
切り替えのパターンとしては、大きくわけると次の2つの方法があります。
- セル(th, td)のレイアウトを切り替える方法
- 横向きのスクロール形式に切り替える方法
ブラウザの幅が縮小したときに、どちらの方法を採用するかで、実装方法が変わります。
いずれも、スマホ画面でブラウザの幅以内に、表をうまく収めることを目的とします。
セル(th, td)のレイアウトを切り替える方法
1つ目は、セルの配置を横並びから縦並びに切り替える方法です。
比較的シンプルな構成の表や、情報量の少ない表でよく使います。
イメージとしては、テーブル内の横向きに並んだセルを、ブラウザ幅が縮小したときに、縦向きに並べ直して、ブラウザ幅いっぱいにセルを広げる感じです。
実装の仕方は、とても簡単です。
CSSで、tableタグ内のすべてのthとtdタグに、display: block;
とwidth: 100%;
を設定します。
どうして、displayプロパティの値をblockにするかというと、table配下のthとtdには、デフォルトでdisplayの値にtable-cellが設定されているからです。
table-cellは、親要素にdisplay:table(tableタグのデフォルト値)が設定されている場合、子要素が表のセルとして認識され、自動で横並びになる値です。
このような理由で、表のセルを強制的にblockにして、thとtdを1つのブロック要素に変化させることで、横並びが解除されます。
また、display値をblockにすることで、thとtdの幅は、親要素の100%の幅になりますが、表のレイアウト構造によっては、セルの幅を指定していることも多いため、thとtdの幅を個々に100%いっぱいにしておくと万全です。
忘れないように、tableタグのwidth値も、100%を設定しておきましょう。
th, td {
display: block;
width: 100%; /* ブレイクポイントで幅が異なる場合は忘れずに! */
}
table表のレスポンシブデザイン実装例 1
それでは、シンプルな表を例に、セル(th, td)のレイアウトを切り替える方法を使ってレスポンシブ化してみましょう。
HTMLは、基本的なtableタグの構成で作成したシンプルなコードです。
<table class="sample1">
<tbody>
<tr>
<th>会社名</th>
<td>株式会社〇〇〇</td>
</tr>
<tr>
<th>所在地</th>
<td>〇〇県〇〇市〇〇町 〇丁目〇番〇号</td>
</tr>
<tr>
<th>電話番号</th>
<td>00-0000-0000</td>
</tr>
<tr>
<th>事業内容</th>
<td>〇〇事業<br>〇〇事業<br>〇〇事業</td>
</tr>
</tbody>
</table>
CSSのブレイクポイントは、デスクトップサイズとスマホサイズのどちらを基準にしてもよいです。
例では、ブラウザ幅が768px以上の場合に、thとtdのdisplay値をデフォルト値のtable-cellに戻すカタチにしています。
.sample1 {
border-collapse: collapse;
table-layout: fixed;
width: 100%; /* table幅を100%に指定 */
background: #fff;
border: none;
}
.sample1 th,
.sample1 td {
display: block; /* セルをブロック要素に指定 */
width: 100%; /* セルを親要素いっぱいの幅に指定 */
border: none;
font-size: 14px;
padding: 10px;
vertical-align: top;
text-align: left;
box-sizing: border-box;
}
.sample1 th {
font-weight: 700;
color: #fff;
background: #14116e; /* thの背景色 */
}
@media screen and (min-width: 768px) {
.sample1 th,
.sample1 td {
display: table-cell; /* デフォルト値に指定 */
border-bottom: 1px solid #ccc;
color: #000;
background: #fff;
}
.sample1 th {
color: #000;
background: #fff; /* thの背景色 */
}
.sample1 tr th:first-child {
width: 100px; /* thの固定幅 */
}
}
パソコンで見ている人はブラウザの幅を伸縮して、スマホで見ている人は縦向き・横向きで、表デザインの変化をご覧ください。
会社名 | 株式会社〇〇〇 |
---|---|
所在地 | 〇〇県〇〇市〇〇町 〇丁目〇番〇号 |
電話番号 | 00-0000-0000 |
事業内容 | 〇〇事業 〇〇事業 〇〇事業 |
ブラウザ幅が768px以上のとき、セル(thとtd)は、通常のテーブルレイアウトで横並びになっていますが、幅が767px以下のときは、縦に並んで幅いっぱいに広がっています。このようにレスポンシブ化することで、スマホでもスッキリ見やすくなりました。
table表のレスポンシブデザイン実装例 2
次は、theadとtbodyタグ、行と列の両方にthタグが存在するtableで実装してみます。
このような表の場合は、セルを縦に並べるだけではなく、thの部分の見せ方や配置を工夫する必要があります。
方法はいろいろありますが、よく使われるdata属性を活用したテクニックをご紹介します。
data属性は、HTML要素に付けることができるカスタムデータと呼ばれる属性です。
独自のオリジナル属性を作成して、その値をCSSでも使うことができる便利な手法です。
例では、「data-label」という名前のオリジナルの属性を作成して解説します。
data属性の補足として、簡単に説明しておきます。あまり深く考えず、こういうものだと思ってください。
カスタムデータの属性名は、data-
を頭に付けて、ハイフンの後に任意のアルファベット文字を記述するのがお決まりです。
ハイフンに続く文字は、あらかじめ決められている命名規則に従って付けなければいけません。
名前に使用できるのは、「文字」「数字」「-(ハイフン)」「.(ドット)」「_(アンダースコア)」のみです。
大文字は使用できませんので注意しましょう。
慣例的には、アルファベットの小文字の使用が基本となります。
コードに関連する意味のある単語にしておくと、あとから見たときに判別しやすいです。
今回は、ラベルをイメージして、「label」という文字にしています。
実際のtableタグの中では、オリジナルで作成したdata-label属性をこのように使います。
<table>
<thead>
<tr>
<th>タイトル1</th>
<th>タイトル2</th>
</tr>
</thead>
<tbody>
<tr>
<td data-label="タイトル1">〇〇〇</td>
<td data-label="タイトル2">〇〇〇</td>
</tr>
</tbody>
</table>
作成したdata-label属性を、tdタグに記述します。
属性の値の部分には、表示させたい内容、例えば、theadのthのテキストを入れます。
このようにすることで、属性を付けたtdに関連するthの内容を紐づけることができます。
HTML側で属性を紐づけたら、CSS側で属性値を画面上に表示させる指示を記述します。
どのように記述するかというと、疑似要素を使います。
疑似要素のcontentプロパティの値に、attr(カスタムデータの属性名)を指定することで、属性の値に記述したデータをCSS側で受け取ることができるようになります。
セレクタ::before {
content: attr(data-label);
}
セレクタ::after {
content: attr(data-label);
}
CSSの疑似要素の基本は、こちらで解説していますので、参考にしてください。
それでは、HTMLとCSSの実例を見ていきましょう。
HTMLの構成は、theadとtbodyタグがあり、thの項目数が多い表を想定します。
前提として、セルを横並びから縦並びにするところまでは同じです。
ただ、thead内の3つのthについては、そのまま縦並びにしても視覚的に意味の分からない表になってしまいます。
そこで、データ属性を使って、セルの一部を別の場所に表示させることにします。
まず、「data-label」という独自の属性をtdタグに付けます。
次に、別の場所に表示させたいthead内のth要素のテキストを、それぞれ紐付するtdのdata-label属性の値に記述しておきます。
<table class="sample2">
<thead>
<tr>
<th>本日のランチ</th>
<th>期間限定メニュー</th> <!-- 別の場所に表示したいth -->
<th>特別価格</th> <!-- 別の場所に表示したいth -->
</tr>
</thead>
<tbody>
<tr>
<th>ランチA</th>
<td data-label="期間限定メニュー">スパイシーチキンカレー<br>グリーンサラダ<br>ライスまたはチーズナン</td>
<td data-label="特別価格">800円</td>
</tr>
<tr>
<th>ランチB</th>
<td data-label="期間限定メニュー">エビバターマサラ<br>グリーンサラダ<br>ライスまたはチーズナン</td>
<td data-label="特別価格">1,000円</td>
</tr>
</tbody>
</table>
CSS側で、ブラウザ幅が768px以下のとき、疑似要素beforeを使って、content: attr(data-label);
を設定して、データ属性の値を表示するよう指示します。あわせて、theadごとdisplay: none;
で非表示にしています。あとは、表全体のデザインを整えて完成です。
.sample2 {
border-collapse: collapse;
table-layout: fixed;
width: 100%;
background: #fff;
border: none;
}
.sample2 th,
.sample2 td {
font-size: 14px;
background: #fff;
border: 1px solid #ccc;
padding: 8px;
vertical-align: middle;
box-sizing: border-box;
}
.sample2 th {
font-weight: 700;
text-align: center;
}
.sample2 thead th {
color: #fff;
background: #14116e;
}
.sample2 tbody td:last-child {
text-align: right;
}
.sample2 thead th:first-child,
.sample2 thead th:last-child {
width: 20%;
}
@media screen and (max-width: 768px) {
.sample2 thead {
display:none;
}
.sample2 tr {
background-color: unset;
}
.sample2 th, .ex_sample2 td {
display: block;
width: 100%;
border: 0;
border-bottom: 1px solid #ccc;
}
.sample2 tbody th{
background: #14116e;
color:#fff;
text-align: center;
}
.sample2 tbody tr td:not(:last-child) {
display: flex;
flex-direction: column;
gap: 5px;
}
.sample2 tbody tr td:not(:last-child)::before{
content: attr(data-label);
width: fit-content;
padding: 0.2em 1em;
border-radius: 100vw;
font-size: 12px;
background: #eee;
}
.sample2 tbody td:last-child::before{
content: attr(data-label);
display: inline-block;
margin-right: 10px;
}
.sample2 tbody td:last-child{
display: flex;
justify-content: space-between;
}
}
疑似要素を使う場所によってもデザインは変わりますが、例では、tdの直前に表示させてスタイルで整えています。
ブラウザの幅を伸縮、またはスマホの向きを変えて、表デザインの変化をご覧ください。
本日のランチ | 期間限定メニュー | 特別価格 |
---|---|---|
ランチA | スパイシーチキンカレー グリーンサラダ ライスまたはチーズナン |
800円 |
ランチB | エビバターマサラ グリーンサラダ ライスまたはチーズナン |
1,000円 |
セルを縦に並べつつ、theadのthの部分は、疑似要素で表示してみました。
これで、スマホ画面で見たときも、ユーザーに伝えたい情報を漏れなく表示することができます。
data属性は、テーブル以外にもいろいろなところで活用できるので、覚えておくと便利です。
横向きのスクロール形式に切り替える方法
2つ目は、セルの配置はそのままに横向きのスクロール形式に切り替える方法です。
デザイン重視で情報量の多い表や、セルを結合した複雑な表でよく使います。
イメージとしては、表の幅は固定のまま、ブラウザ幅が縮小したときは、表のはみ出した部分を横向きのスクロールで表示させる感じです。
実装の仕方は、レイアウトを切り替える方法より簡単です。
HTML側で、tableの外側に親要素を1つ追加します。
例では、divタグを使用してクラスtable-scrollを付けています。
<div class="table-scroll"> <!-- 追加するtableの親要素div -->
<table>
<!-- 省略 -->
</teble>
</div>
CSS側で、この親要素であるdivタグにoverflow-x : auto;
を設定するだけです。
.table-scroll{
overflow-x : auto;
}
CSSのoverflowは、要素の内容が多くて、表示させたい範囲に収まらない場合に、一括指定(x軸方向とy軸方向)できるプロパティです。
overflowの対象を、x軸(横)に限定する場合は「overflow-x」。y軸(縦)に限定する場合は「overflow-y」を使います。
overflowの値は、visible、hidden、clip、scroll、autoがあります。
横スクロールに対応したいので、overflow-xプロパティ値に、autoまたはscrollを設定します。
autoとscrollの違いは、スクロールバーを常に表示するのがscroll、表示しないのがautoです。autoは、表示させたい範囲に収まらないときだけスクロールバーが表示されます。
従って、表がすべて見えているときは、スクロールバーは不要なので、autoを設定しています。
table表のレスポンシブデザイン実装例 3
それでは、レイアウトを崩したくない表を例に、横スクロールを使ってレスポンシブ化してみましょう。
HTMLのポイントとしては、table全体をdivタグで囲って親要素を記述している部分です。また、説明は後述しますが、スクロールができることを伝えるための矢印をspanタグで配置しています。
<div class="table_wrap"> <!-- tableの親要素 -->
<span class="table_arrow"></span> <!-- スクロールを伝える矢印 -->
<table class="sample3">
<thead>
<tr>
<th></th>
<th>プランA</th>
<th>プランB</th>
<th>プランC</th>
</tr>
</thead>
<tbody>
<tr>
<th>料金</th>
<td>無料</td>
<td>1,500円</td>
<td>3,000円</td>
</tr>
<tr>
<th>サポート</th>
<td>対象外</td>
<td>1回 / 月</td>
<td>無制限</td>
</tr>
<tr>
<th>プラン変更</th>
<td>不可</td>
<td>可能</td>
<td>可能</td>
</tr>
<tr>
<th>長期契約割引</th>
<td>×</td>
<td>〇</td>
<td>〇</td>
</tr>
</tbody>
</table>
</div>
CSSでは、表の幅が600px以下になったらスクロール形式に切り替わるように設定しています。
どこで600pxを設定しているかというと、tableタグに、min-width: 600px;
を指定しています。
表の最小幅は600pxで固定してね。という指示になります。
このようにすると、ブラウザ幅が縮小したときも、表のデザインを維持することができます。
.table_wrap {
overflow-x : auto; /* 横スクロール */
}
.sample3 {
width: 100%;
min-width: 600px; /* 幅が600px以下になったらスクロール */
table-layout: fixed;
border-collapse: separate;
border-spacing: 2px 0;
white-space: nowrap; /* 折り返し禁止 */
}
.sample3 th,
.sample3 td {
font-size: 14px;
border: none;
padding: 8px;
background: #e8e6f3;
text-align: center;
vertical-align: middle;
box-sizing: border-box;
}
.sample3 td {
font-size: 15px;
}
.sample3 tr:nth-child(even) th,
.sample3 tr:nth-child(even) td {
background: #eaf6fe;
}
.sample3 thead th {
border-radius: 6px 6px 0 0;
color: #fff;
}
.sample3 thead th:nth-child(1) {
background: #eaf6fe;
background-color: transparent;
color: #000;
}
.sample3 thead th:nth-child(2) {
background: #14116e;
}
.sample3 thead th:nth-child(3) {
background: #b50165;
}
.sample3 thead th:nth-child(4) {
background: #6f9b12;
}
.sample3 tbody tr:first-child th{
border-radius: 6px 6px 0 0;
}
.sample3 tbody tr:last-child th,
.sample3 tbody tr:last-child td{
border-radius: 0 0 6px 6px;
}
.sample3 thead th:nth-child(3) {
border-top:solid 4px #b50165;
border-left:solid 4px #b50165;
border-right:solid 4px #b50165;
}
.sample3 tbody td:nth-child(3) {
border-left:solid 4px #b50165;
border-right:solid 4px #b50165;
}
.sample3 tbody tr:last-child td:nth-child(3){
border-bottom:solid 3px #b50165;
}
@media screen and (max-width: 480px) {
.table_wrap {
position: relative;
}
/* 幅が480px以下になったら矢印を表示 */
.table_wrap::before {
content: 'スクロール';
font-size: 12px;
color: #ccc;
position: absolute;
top: 0;
left: 5px;
}
.table_arrow {
display: block;
position: relative;
}
.table_arrow::before {
content: '';
position: absolute;
top:20px;
left:5px;
width: 100px;
height: 1px;
background:#ccc;
}
.table_arrow::after {
content: '';
position: absolute;
top:15px;
left:90px;
width: 15px;
height:1px;
background:#ccc;
transform: rotate(35deg);
}
}
ブラウザの幅を伸縮、またはスマホの向きを変えて、表デザインの変化をご覧ください。
プランA | プランB | プランC | |
---|---|---|---|
料金 | 無料 | 1,500円 | 3,000円 |
サポート | 対象外 | 1回 / 月 | 無制限 |
プラン変更 | 不可 | 可能 | 可能 |
長期契約割引 | × | 〇 | 〇 |
これで、スマホ画面で見たときも、表のデザインを変えずに、ユーザーに伝えたい情報を横スクロールで表示することができました。
ただし、スクロール形式は、気を付けておきたいことがあります。
それは、スマホユーザーが、横方向にスクロールできることに気づかなかったり、スクロールできることを見落としてしまう可能性があるという点です。
従って、スマホ画面サイズのときは、スクロールできることを予測できるように配慮しておくことも重要です。
例では、対策の一例として、ブレイクポイント480px以下のとき、「スクロール」という矢印付きのテキストを疑似要素で表示させています。
予測を伝える目印は、javascriptで実装することがよくありますが、最低限のサポート表示であれば、このようにHTMLやCSSでも可能です。
まとめ
最後に、これまで見てきた2つのレスポンシブ方法の特徴をメリット、デメリットをふまえてまとめておきます。
セルのレイアウトを切り替える方法の特徴
メリット
- ブラウザ画面の幅以内にすべての情報を収めることができる。
デメリット
- パソコンとスマホでテーブルデザインが変わってしまう。
- スマホ画面で情報量が多い場合は縦スクロールが必要になる。
よく使われる場面
- 比較的シンプルな構成の表
スクロール形式に切り替える方法の特徴
メリット
- パソコンとスマホでテーブルデザインが変わらない。
デメリット
- スマホ画面で横スクロールが必要になる。
- 横スクロールの仕様は、隠れている情報を見落としてしまうことがある。
よく使われる場面
- ブラウザ幅に応じてデザインを崩したくない表
- セルを結合した複雑な構成の表
- 情報量の多い表
特徴からわかることは、表現したいデザインや、表示する情報量、重要度によって使い分ける必要があるということです。
また、Web制作の現場では、マーケティングにおけるターゲットやペルソナによって、どちらの方法を採用するか判断するケースもよくあります。
一般的には、スマートフォンでWebサイトを見る際は、上から下にスワイプしながら閲覧することが多いと思います。
そのような観点からは、セル(th, td)のレイアウトを切り替える方法を軸に、すべての情報が画面に収まっている状態がいいかもしれません。
中には、比較表や項目の多い表など、ビジュアルを崩さないほうが見やすい表もあります。
そのような表は、あえてスクロール形式を取り入れるほうがいいですね。
tableタグの表は、使う場面は限られますが、レスポンシブのスキルは必須です。
テーブルデザインのレスポンシブ対応の基本になりますので、ぜひ覚えておいてください。