【CSS】linear-gradient()でブロックに斜線を引く【斜線】

## はじめに
業務で久しぶりにややこってりCSSを書いて ~~やっぱ嫌いだなぁって思った~~
結構つまずいたり、使ったことないスタイル当ててみたりしたので記録。

## 何がしたかったのか
いったんダメな例。

https://codepen.io/tsuchinoko0102/pen/LYmWJNy

ある特定のブロックに対して斜線を引いてあげるっていう割と簡単そうな実装を行いたかったが、 **まぁしんどいめんどい。**
getクラスをどう付与するかとかいうJS的な話はどうでもいいので今回は無視してます。

今回は、pタグにgetクラスが当たっている要素に斜線を引っ張りました。
```css
.get::before {
  position: absolute;
  content: "";
  display: block;
  background-color: rgba(204, 204, 204, 0.5);
  height: 1px;
  width: 160px;
  top: 1.7rem;
  right: -0.4rem;
  transform: rotate(-20deg);
}
```
疑似要素beforeを使い、pタグには``position: relative;``を当て、それに対して``position: absolute;``や``top right``を使って位置調整。
``transform: rotate(-20deg)``で斜線の角度、``width``で線の長さを…と**かなりの時間と労力を費やし**できたのが上記の程度。
よく見ると、左下の頂点がちゃんと角と接していません。
ちゃんとやろうとすると、三平方の定理とかゴリゴリに使って計算する必要がありますね。~~そこまでやってられるか~~

この時点でかなり残念な実装ですが、もう1つ非常に大きな問題があります。
それは、**ブロックのサイズが変わった瞬間に崩壊する**というものです。

上記CSSの実装は、あくまでpタグのサイズが``width: 210px; height: 52.5px;``であることを前提に（そのために）頑張って調整したもののため、
たとえば``width: 250px;`` とかなった瞬間にさようならです。
あるいは、斜線を引きたいブロックのサイズが%指定やrem指定だったり、レスポンシブ対応だったりで可変の場合もあるでしょうか。~~もう嫌だ~~

ブロックの寸法変えたら崩壊した例

https://codepen.io/tsuchinoko0102/pen/xxjqavY

今回は、ブロックサイズが可変だったので、特定のサイズに依存しないように斜線を引きたい。
そんなときに出会ったのが、今回ご紹介する**linear-gradient**です。

## linear-gradient
MDNから引用
> linear-gradient() は CSS の関数で、二つ以上の色の連続的な直線に沿った変化から構成される画像を生成します。結果は\<gradient>データ型のオブジェクトであり、これは\<image>の特殊型です。

**CSSのデータ型**が、もう？？？なのでいったん分解。

**image型**
二次元の画像を表現するデータ型。よく見かける``background-image: url("/hoge/fuga.png");`` の``url()``などで表現できるデータ型のこと。

**gradient型**
image型の特殊な型で、2色以上の連続的な色の変化で構成されるimageのこと。（グラデーションだからそういうこと）

で、このgradient型のimageを表現する関数のうちのひとつがlinear-gradientですね。
linearなので**直線**でグラデーションを表現してくれます。
ほかにも、放射状にグラデーションする``radial-gradient()``や扇形の``conic-gradient()``などがいます。

\<image>型を返す関数になるので、``background-image``のような\<image>型を期待するスタイルにしか使えません。``background-color``とかはダメ。

**2色以上のグラデーションを表現する**CSSなので、斜線…？となりますが、CSSで「色」といえばあいつがいますね。``transparent`` 透明です。

## linear-gradientを使ってダメな例を改修
https://codepen.io/tsuchinoko0102/pen/rNvyqGJ

```css
.get {
  background-image: linear-gradient(to left top, transparent 50%, rgba(204, 204, 204, 0.5) 50%,
rgba(204, 204, 204, 0.5) calc(50% + 1px), transparent calc(50% + 1px));
}
```
前述のダメな例で使っていたbefore疑似要素を丸ごと削除。
代わりに、getクラスに直に``background-image: lineat-gradient(...)``を当てています。
これだと、ブロックの寸法を変更してもちゃんと斜線が斜線として機能します。

ブロックの寸法を変えてもちゃんと斜線が機能しているサンプル

https://codepen.io/tsuchinoko0102/pen/xxjqyPy

と、CSSだけで簡単に斜線が引けるよ！という紹介は以上になりますので
もし、**簡単なCSSだけでブロックに斜線を引きたいんじゃい**って目的でここにたどり着いた方はここでブラウザバックor参照リンクまで移動を推奨です。

以下は、この関数が何してるかよく分からん！CSSの謎文法が気に食わん！っている稀有な人（私です）用の解説。
MDNの解説が~~クソ~~初心者殺しの難しさなので、CSSの仕様書を引っ張り出して研究してみます。

### linear-gradient()の構文
``linear-gradient() = linear-gradient([<angle> | to <side-or-corner>]? , <color-stop-list>)``

``<>``で括られているのはCSSのデータ型を表します。
``[]``はグループです。上記例でいうと、\<angle>とto \<side-or-corner>がグループ（宣言したい中身は同じだよ）的な意味。
``|``はorみたいなもんです。
``||``はorですが、これで区切られている両サイドのうち、片方は最低でも必要だよ、という意味。
``?``は、その直前の型とか語句があってもなくてもいいよ的な意味。


**第1引数 [\<angle> | to \<side-or-corner>]?**
グラデーションの軸をどうするか、を決めます。
``<angle>`` の場合90degとか270degとか、角度で表します。
``to <side-or-corner>``の場合、``<side-or-corner> = [ [left | right] || [top | bottom] ]``なので、
今回の例のように``to left top``でもいいし、``to top``でも``to right``でも良いです。
この引数に何も入れないと、デフォルトの値（``180deg = to bottom``）になります。
軸が決まるとき、そのブロックに対しての**グラデーションの軸**及びのその**始点** **終点**が定まります。
![linear-gradient軸](https://w3c.github.io/csswg-drafts/css-images-3/images/gradient-diagram.png)

**第2引数以降 \<color-stop-list>**
グラデーションする色（最低2つ）やそれらの範囲などを示してあげます。
``<color-stop-list> = <linear-color-stop> , [<linear-color-hint>? , <linear-color-stop>]#``
``<linear-color-stop> = <color> && <length-percentage>?``
``<linear-color-hint> = <length-percentage>``
``<length-percentage> = [length | percentage]``

``#``は、直前の型や語句が1回以上使われることを表します。~~もう呪文だらけで嫌になってきた。~~

まず、どこにでもいる``<linear-color-stop> = <color> && <length-percentage>?``から見ましょう。
例でいうところの、``transparent 50%`` や ``rgba(204, 204, 204, 0.5) 50%`` ですね。

``<color>``はいいでしょう、問題は``<length-percentage>``の方。
これは、上記図の始点に対してどこから次の色に向けてのグラデーションを開始するのか、ということを決めてあげます。

今回の例について分解すると、
1つ目と2つ目 ``transparent 50%, rgba(204, 204, 204, 0.5) 50%``
→同じ50%地点を始点としているのでグラデーションが起こりません。
3つ目と4つ目 ``rgba(204, 204, 204, 0.5) calc(50% + 1px), transparent calc(50% + 1px)``
→１・２と同じで、同じ``calc(50% + 1px)``を始点としているのでグラデーションが起こりません。
ちなみに、``calc(50% + 1px)``としているのは、**ブロックのサイズに関わらず**常に1pxの線が欲しいからです。

そのため、2つ目と3つ目の ``rgba(204, 204, 204, 0.5) 50%, rgba(204, 204, 204, 0.5) calc(50% + 1px)``
つまり、``calc(50% +1px)``の範囲で``rgba(204, 204, 204, 0.5)``の線が引かれる、ということになります。

と、文字だけだと？？？な人も多い（私です）と思うので、いろいろ試してみたものを貼っておきます。

## グラデーションいろいろ

https://codepen.io/tsuchinoko0102/pen/RwyKvxP

**1. グラデーションしない**

```css
.twotone {
  border: none !important;
  background-image: linear-gradient(to left top, red 50%, lightblue 50%);
}
```
2色の始点を同じにすることで、グラデーションせず2色が半分ずつそのままの色で表現されます。

**2. ちゃんとグラデーションする**
```css
.two-gradient {
  border: none !important;
  background-image: linear-gradient(to left top, red 20%, yellow 80%);
}
```
始点から0~20%地点までは赤、始点から80%~100%までは黄色がそのままの色。その間（20~80%）を赤と黄色のグラデーションで表現されます。

**3. グラデーションの割合（強さ？）を変えてみる**
```css
.two-gradient-yellow {
  border: none !important;
  background-image: linear-gradient(to left top, red 20%, 30%, yellow 80%);
}
```
~~なぜか本当に分からないけど~~ colorを抜いてpercentageだけ入れてあげると、グラデーションの具合が変わる。
2の例は``linear-gradient(to left top, red 20%, 50%, yellow 80%)``と同義っぽいです。

**4. 多色や\<angle>を試してみた**
```css
.three-gradient {
  border: none !important;
  background-image: linear-gradient(to left top, red, lightblue, green);
}

.deg-gradient {
  border: none !important;
  background-image: linear-gradient(75deg, red, orange, yellow, green);
}
```
\<length-percentage>をしないと、CSS側の計算に基づいてよしなにグラデーションしてくれます。
~~そこのロジック読み解く体力ないﾏｼﾞﾑﾘﾘｽｶｼﾖ~~
最後の``.deg-gradient``は、他と違い角度指定なので、グラデーションの軸が異なっています。

## 最後に
~~やっぱりCSS大嫌い~~
見た目が整えばいいや〜くらいの軽いノリでしかCSSを触ったことがなかったので、今回ここまでがっつり掘ってみることが出来たのはよかった。
偶然ではあるものの、``linear-gradient``が関数だったことが大きな要因かもしれない。
CSSの仕様書とか初めて見たけど、なかなか面白かったのでCSS極めたい方は是非ご一読を！

## 参考リンク
**~~アンチになりそう~~ MDNの解説記事**
https://developer.mozilla.org/ja/docs/Web/CSS/gradient

**CSSの仕様書**
https://w3c.github.io/csswg-drafts/css-images-3/

**linear-gradientを使って斜線が書けることを教えてくださった記事**
https://csshtml.work/diagonal-line/

**弊社フロントエンジニア@ibetakuさんの、linear-gradientでオシャレなことする記事（本当におしゃれ）**
https://qiita.com/ibetaku/items/c357739ab9c86c370e24