過去に作ったフレームワーク無しのHTMLテーブルを、Bootstrap(5)で再現しようとすると、
過去、手抜き、つまりborder-bottom: noneなどで罫線を消してセル結合っぽくしている場合、
(HTML的にはダメですが、ループを回してDBを表示する場合めんどくさくてつい…)
融通がきかなくて困る場合があります(した)。
##手抜きをBootstrapで再現
###HTML
- 罫線無しのテーブル(table-borderless)にして、個別にborderを設定する
- 同列の前行が違う値だったら、border-topを追加設定する
<div class="table-responsive">
<table class="table table-borderless">
<thead class="text-center table-light">
<tr>
<th scope="col" class="border-start border-top" nowrap>部名</th>
<th scope="col" class="border-start border-top" nowrap>部長</th>
<th scope="col" class="border-start border-top" nowrap>課名</th>
<th scope="col" class="border-start border-top" nowrap>課長</th>
<th scope="col" class="border-start border-top" nowrap>ユニット名</th>
<th scope="col" class="border-start border-top" nowrap>ユニット<br>リーダー</th>
<th scope="col" class="border-start border-end border-top" nowrap>メンバー</th>
</tr>
</thead>
<tbody>
<tr>
<td class="border-start border-top" nowrap>何でも部</td>
<td class="border-start border-top" nowrap>部長 太郎</td>
<td class="border-start border-top" nowrap>課1</td>
<td class="border-start border-top" nowrap>課長 太郎</td>
<td class="border-start border-top" nowrap>ユニット1</td>
<td class="border-start border-top" nowrap>ユニット 太郎</td>
<td class="border-start border-end border-top" nowrap>メンバー 太郎</td>
</tr>
<tr>
<td class="border-start" nowrap></td>
<td class="border-start" nowrap></td>
<td class="border-start" nowrap></td>
<td class="border-start" nowrap></td>
<td class="border-start" nowrap></td>
<td class="border-start" nowrap></td>
<td class="border-start border-end" nowrap>メンバー 次郎</td>
</tr>
<tr>
<td class="border-start" nowrap></td>
<td class="border-start" nowrap></td>
<td class="border-start" nowrap></td>
<td class="border-start" nowrap></td>
<td class="border-start border-top" nowrap>ユニット2</td>
<td class="border-start border-top" nowrap>ユニット 次郎</td>
<td class="border-start border-end border-top" nowrap>メンバー 三郎</td>
</tr>
<tr>
<td class="border-start" nowrap></td>
<td class="border-start" nowrap></td>
<td class="border-start border-bottom" nowrap></td>
<td class="border-start border-bottom" nowrap></td>
<td class="border-start border-bottom" nowrap></td>
<td class="border-start border-bottom" nowrap></td>
<td class="border-start border-end border-bottom" nowrap>メンバー 四郎</td>
</tr>
<tr>
<td class="border-start" nowrap></td>
<td class="border-start" nowrap></td>
<td class="border-start border-top" nowrap>課2</td>
<td class="border-start border-top" nowrap>課長 次郎</td>
<td class="border-start border-top" nowrap>ユニット1</td>
<td class="border-start border-top" nowrap>ユニット 三郎</td>
<td class="border-start border-end border-top" nowrap>メンバー 五郎</td>
</tr>
<tr>
<td class="border-start" nowrap></td>
<td class="border-start" nowrap></td>
<td class="border-start" nowrap></td>
<td class="border-start" nowrap></td>
<td class="border-start" nowrap></td>
<td class="border-start" nowrap></td>
<td class="border-start border-end" nowrap>メンバー 六郎</td>
</tr>
<tr>
<td class="border-start" nowrap></td>
<td class="border-start" nowrap></td>
<td class="border-start" nowrap></td>
<td class="border-start" nowrap></td>
<td class="border-start border-top" nowrap>ユニット2</td>
<td class="border-start border-top" nowrap>ユニット 四郎</td>
<td class="border-start border-end border-top" nowrap>メンバー 七郎</td>
</tr>
<tr>
<td class="border-start border-bottom" nowrap></td>
<td class="border-start border-bottom" nowrap></td>
<td class="border-start border-bottom" nowrap></td>
<td class="border-start border-bottom" nowrap></td>
<td class="border-start border-bottom" nowrap></td>
<td class="border-start border-bottom" nowrap></td>
<td class="border-start border-end border-bottom" nowrap>メンバー 八郎</td>
</tr>
</tbody>
</table>
</div><!-- .table-responsive -->
###PHP
<?php
$data[0] = array("何でも部", "部長 太郎", "課1", "課長 太郎", "ユニット1", "ユニット 太郎", "メンバー 太郎");
$data[1] = array("何でも部", "部長 太郎", "課1", "課長 太郎", "ユニット1", "ユニット 太郎", "メンバー 次郎");
$data[2] = array("何でも部", "部長 太郎", "課1", "課長 太郎", "ユニット2", "ユニット 次郎", "メンバー 三郎");
$data[3] = array("何でも部", "部長 太郎", "課1", "課長 太郎", "ユニット2", "ユニット 次郎", "メンバー 四郎");
$data[4] = array("何でも部", "部長 太郎", "課2", "課長 次郎", "ユニット1", "ユニット 三郎", "メンバー 五郎");
$data[5] = array("何でも部", "部長 太郎", "課2", "課長 次郎", "ユニット1", "ユニット 三郎", "メンバー 六郎");
$data[6] = array("何でも部", "部長 太郎", "課2", "課長 次郎", "ユニット2", "ユニット 四郎", "メンバー 七郎");
$data[7] = array("何でも部", "部長 太郎", "課2", "課長 次郎", "ユニット2", "ユニット 四郎", "メンバー 八郎");
?>
<div class="table-responsive">
<table class="table table-borderless">
<thead class="text-center table-light">
<tr>
<th scope="col" class="border-start border-top" nowrap>部名</th>
<th scope="col" class="border-start border-top" nowrap>部長</th>
<th scope="col" class="border-start border-top" nowrap>課名</th>
<th scope="col" class="border-start border-top" nowrap>課長</th>
<th scope="col" class="border-start border-top" nowrap>ユニット名</th>
<th scope="col" class="border-start border-top" nowrap>ユニット<br>リーダー</th>
<th scope="col" class="border-start border-end border-top" nowrap>メンバー</th>
</tr>
</thead>
<tbody>
<?php
$i = 0;
while($i < count($data)){
echo " <tr>\n";
//先頭行
if ($i == 0) {
echo " <td class=\"border-start border-top\" nowrap>{$data[$i]{0}}</td>\n";
echo " <td class=\"border-start border-top\" nowrap>{$data[$i]{1}}</td>\n";
echo " <td class=\"border-start border-top\" nowrap>{$data[$i]{2}}</td>\n";
echo " <td class=\"border-start border-top\" nowrap>{$data[$i]{3}}</td>\n";
echo " <td class=\"border-start border-top\" nowrap>{$data[$i]{4}}</td>\n";
echo " <td class=\"border-start border-top\" nowrap>{$data[$i]{5}}</td>\n";
echo " <td class=\"border-start border-end border-top\" nowrap>{$data[$i]{6}}</td>\n";
} else {
//先頭行後
$j = 0;
while($j <= 6){
//上罫線
$borderTop = " border-top";
//表示データ
$val = $data[$i][$j];
//同列の前行と値が一致したら上罫線と値は表示しない
if ($data[$i]{$j} == $data[$i - 1]{$j}) {
$borderTop = "";
$val = "";
}
//右罫線
//最終列のみ右罫線表示
$borderEnd = "";
if ($j == 6) {
$borderEnd = " border-end";
}
//下罫線
//最終行のみ下罫線表示
$borderBottom = "";
if ($i == count($data) - 1) {
$borderBottom = " border-bottom";
}
echo " <td class=\"border-start{$borderEnd}{$borderTop}{$borderBottom}\" nowrap>{$val}</td>\n";
$j++;
}
}
echo " </tr>\n";
$i++;
}
?>
</tbody>
</table>
</div><!-- .table-responsive -->
##HTML的に正しいやり方
###HTML
- 罫線有りのテーブル(table-bordered)にして、同じ値の場合はセルを結合する
<div class="table-responsive">
<table class="table table-bordered">
<thead class="text-center table-light">
<tr>
<th scope="col" nowrap>部名</th>
<th scope="col" nowrap>部長</th>
<th scope="col" nowrap>課名</th>
<th scope="col" nowrap>課長</th>
<th scope="col" nowrap>ユニット名</th>
<th scope="col" nowrap>ユニット<br>リーダー</th>
<th scope="col" nowrap>メンバー</th>
</tr>
</thead>
<tbody>
<tr>
<td nowrap rowspan="8">何でも部</td>
<td nowrap rowspan="8">部長 太郎</td>
<td nowrap rowspan="4">課1</td>
<td nowrap rowspan="4">課長 太郎</td>
<td nowrap rowspan="2">ユニット1</td>
<td nowrap rowspan="2">ユニット 太郎</td>
<td nowrap>メンバー 太郎</td>
</tr>
<tr>
<td nowrap>メンバー 次郎</td>
</tr>
<tr>
<td nowrap rowspan="2">ユニット2</td>
<td nowrap rowspan="2">ユニット 次郎</td>
<td nowrap>メンバー 三郎</td>
</tr>
<tr>
<td nowrap>メンバー 四郎</td>
</tr>
<tr>
<td nowrap rowspan="7">課2</td>
<td nowrap rowspan="7">課長 次郎</td>
<td nowrap rowspan="2">ユニット1</td>
<td nowrap rowspan="2">ユニット 三郎</td>
<td nowrap>メンバー 五郎</td>
</tr>
<tr>
<td nowrap>メンバー 六郎</td>
</tr>
<tr>
<td nowrap rowspan="2">ユニット2</td>
<td nowrap rowspan="2">ユニット 四郎</td>
<td nowrap>メンバー 七郎</td>
</tr>
<tr>
<td nowrap>メンバー 八郎</td>
</tr>
</tbody>
</table>
</div><!-- .table-responsive -->
###PHP
- 同列の前行と違う値だったら(同じ値だったら何も表示しない)
- 内部に別ループを回し、同列の次行と違う値になるまでループを回し、結合数(rowspan)をカウント
- rowspanに結合数を設定
<?php
$data[0] = array("何でも部", "部長 太郎", "課1", "課長 太郎", "ユニット1", "ユニット 太郎", "メンバー 太郎");
$data[1] = array("何でも部", "部長 太郎", "課1", "課長 太郎", "ユニット1", "ユニット 太郎", "メンバー 次郎");
$data[2] = array("何でも部", "部長 太郎", "課1", "課長 太郎", "ユニット2", "ユニット 次郎", "メンバー 三郎");
$data[3] = array("何でも部", "部長 太郎", "課1", "課長 太郎", "ユニット2", "ユニット 次郎", "メンバー 四郎");
$data[4] = array("何でも部", "部長 太郎", "課2", "課長 次郎", "ユニット1", "ユニット 三郎", "メンバー 五郎");
$data[5] = array("何でも部", "部長 太郎", "課2", "課長 次郎", "ユニット1", "ユニット 三郎", "メンバー 六郎");
$data[6] = array("何でも部", "部長 太郎", "課2", "課長 次郎", "ユニット2", "ユニット 四郎", "メンバー 七郎");
$data[7] = array("何でも部", "部長 太郎", "課2", "課長 次郎", "ユニット2", "ユニット 四郎", "メンバー 八郎");
?>
<div class="table-responsive">
<table class="table table-bordered">
<thead class="text-center table-light">
<tr>
<th scope="col" class="border-start border-top" nowrap>部名</th>
<th scope="col" class="border-start border-top" nowrap>部長</th>
<th scope="col" class="border-start border-top" nowrap>課名</th>
<th scope="col" class="border-start border-top" nowrap>課長</th>
<th scope="col" class="border-start border-top" nowrap>ユニット名</th>
<th scope="col" class="border-start border-top" nowrap>ユニット<br>リーダー</th>
<th scope="col" class="border-start border-end border-top" nowrap>メンバー</th>
</tr>
</thead>
<tbody>
<?php
$i = 0;
while($i < count($data)){
echo " <tr>\n";
//先頭行
if ($i == 0) {
$j = 0;
while($j <= 6){
//表示データ
$val = $data[$i][$j];
//同列の次行と値が一致したら
if ($data[$i]{$j} == $data[$i + 1]{$j}) {
//結合数
$r = 1;
//現行から開始
$n = $i;
while($n < count($data) - 1){
if ($data[$i]{$j} == $data[$n + 1]{$j}) {
$r++;
} else {
break;
}
$n++;
}
echo " <td rowspan=\"{$r}\" nowrap>{$val}</td>\n";
} else {
//以外は値のみ表示
echo " <td nowrap>{$val}</td>\n";
}
$j++;
}
} else {
//先頭行後
$j = 0;
while($j <= 6){
//表示データ
$val = $data[$i][$j];
//同列の前行と値が一致しなかったら(一致したら何も表示しない)
if ($data[$i]{$j} != $data[$i - 1]{$j}) {
//結合数
$r = 1;
//現行から開始
$n = $i;
while($n < count($data) - 1){
if ($data[$i]{$j} == $data[$n + 1]{$j}) {
$r++;
} else {
break;
}
$n++;
}
echo " <td rowspan=\"{$r}\" nowrap>{$val}</td>\n";
}
$j++;
}
}
echo " </tr>\n";
$i++;
}
?>
</tbody>
</table>
</div><!-- .table-responsive -->