CSS で横グラデーションボーダーのテーブルを作る


CSS で横グラデーションボーダーのテーブルを作る。
こんなやつ。
![table01.png](https://qiita-image-store.s3.amazonaws.com/0/73925/e742659a-5af8-e48d-ac6a-66a8d9b01a23.png)

- Mac：Safari 10, Firefox 56, Chrome 61, Opera 48
- Windows 7：IE 11, Firefox 56, Chrome 61　以上の環境で確認

##背景を塗りつぶしても構わない場合
テーブルの背景を単一色で塗りつぶしても良いなら、シンプルに以下で実装可能。
table の背景を linear-gradient で塗り、border-spacing の隙間からそれを見せる仕組み。

```html
<div class="grad-border">
<table>
<tbody>
<tr>
<th>見出し</th>
<td>サンプルテキスト</td>
</tr>
...　一般的なテーブル
</table>
</div>
```
```CSS
.grad-border table {
background: linear-gradient(to right, transparent 0%,#f00 30%,#00f 70%,transparent 100%);
border-collapse: separate;
border-spacing: 0 4px;
}

.grad-border table tr {
background: #fff;
}
```

##背景を塗りつぶさず、純粋に罫線のみを描く場合
一方で、多色＆柄背景への対応を考え、純粋に罫線のみを描こうとすると意外にコレが難しい。
...と思ったのだが、すったもんだの回り道の末たどり着いたのは単純な結論という、よくあるオチだった。

**2017年10月9日追記
before 擬似要素を使用した場合、特定構成の table において表示崩れの発生が見られたので after を使用する形に修正。**

```CSS
/* HTML は上記と共通 */

.grad-border table {
position: relative;
}

.grad-border th,.grad-border td {
vertical-align: middle;/* top,middle,bottom いずれかの指定が必須 */
}

.grad-border table::after,.grad-border tr::after {
position: absolute;
content: "";
width: 100%;
height: 4px;/* 罫線の太さ */
left: 0;
margin-top: -2px;/* 罫線の太さの半分のネガティブ値 */
background: linear-gradient(to right, transparent 0%,#f00 30%,#00f 70%,transparent 100%);
}

.grad-border table::after {
bottom: -2px;/* 罫線の太さの半分のネガティブ値 */
}
```

上記の通り、tr::after の背景をグラデーションに塗り罫線に見せるという単純なもの。
なぜ回り道する事になったかは後述。

なお、tr::before, tr::after どちらも垂直方向の初期配置は tr の上部に張り付く形となるため、tr の擬似要素で描く事ができるのは上罫線のみ。そのため、最後の下罫線は table 自体の擬似要素を利用している。（tr に position: relative は適用されないため bottom:0 で位置調整して下罫線を引く事はできない）

テーブルの内側のみ罫線を引きたい場合は下記の通り。
table 自体の擬似要素は作成せず、最初の tr::after を隠せば良い。
最上段、最下段の罫線だけ要らないなんてケースもこれらを組み合わせる事で実現可能。
![table02.png](https://qiita-image-store.s3.amazonaws.com/0/73925/3470d1ed-f8a9-d79b-59ce-59a6b57f46f9.png)

```CSS
.grad-border table {
position: relative;
}

.grad-border th,.grad-border td {
vertical-align: middle;/* top,middle,bottom いずれかの指定が必須 */
}

.grad-border tr::after {
position: absolute;
content: "";
width: 100%;
height: 4px;/* 罫線の太さ */
left: 0;
margin-top: -2px;/* 罫線の太さの半分のネガティブ値 */
background: linear-gradient(to right, transparent 0%,#f00 30%,#00f 70%,transparent 100%);
}

.grad-border tr:first-child::after {
visibility: hidden;
}

/* thead がある場合、tbody の最初の tr::after は再表示させる */
.grad-border thead + tbody tr:first-child::after {
visibility: visible;
}
```

##回り道する羽目になった理由

当然この「tr::after の背景をグラデーションに塗り罫線に見せる」という手法は真っ先に試してみたのだが、大きな回り道をする要因となったのは以下の部分。

```CSS
.grad-border th,.grad-border td {
vertical-align: middle;/* top,middle,bottom いずれかの指定が必須 */
}
```

table 系タグの内部要素（tr や th,td）は CSS の仕様上 position: relative が適用されないため、top:0 等の指定は使えず、位置調整は margin による「初期配置からの上下移動」のみとなる。
この縛りがあるため「各ブラウザで同じ初期配置になる要素を使って罫線を描く」事が前提条件となるのだが、

**vertical-align: baseline（無指定の場合の初期値）の場合、「Firefox / IE」と「Safari / Chrome」では tr 擬似要素の、垂直方向の初期配置が異なる**

という落とし穴があった。
そんな訳で、vertical-align を明示指定せずに行った最初のテストでは、ブラウザによって罫線が揃わない事態となり、「ありゃ、イケると思ったのにダメか」と延々遠回りする羽目となった。

なお、上記の理由により、**vertical-align: baseline を適用したい table に、この手法は使えない**ので注意。
その場合は、最初の背景を塗りつぶす方法を使うしかない。

##おまけ：CSS によるグラデーション下線
上記に辿り着くまでに見つけた小ネタ。
CSS でグラデーションのラインを引く方法というと、今回も使用している「擬似要素を作り、その要素の background をグラデーションに塗る」手法がよく知られているが、border-radius を使わない単純な直線で良ければ、シンプルに以下でも設定できる。ただし、**[border-image は IE11 以降対応](https://caniuse.com/#search=border-image)なので、それ以前も対象に含める場合は使用できない。**

```CSS
h2 {
border-bottom: solid 4px;
border-image: linear-gradient(to right, #ff6e02 0%, #ff0 50%, #ffb600 74%, #ff6e02 100%);
border-image-slice: 1;
}
```

「border-image-slice: 1」がポイント。
ショートハンドで下記のようにまとめる事もできる。

```CSS
h2 {
border-bottom: solid 4px;
border-image: linear-gradient(to right, #ff6e02 0%, #ff0 50%, #ffb600 74%, #ff6e02 100%) 1;
}
```

また、同様に border-radius を使わない直角の枠で良ければ、上記を「border: solid 4px;」にする事でグラデーションの囲み枠も簡単に作成できる。border-image と border-radius が併用できないのが非常に惜しい。

もちろん「tr にこれを使えば簡単じゃん」と試してみたのだが、「border-collapse: collapse」の場合「border-image」は反映されないらしく撃沈。（tr に border を描く際は「border-collapse: collapse」が必須）