はじめに
業務で久しぶりにややこってりCSSを書いて やっぱ嫌いだなぁって思った
結構つまずいたり、使ったことないスタイル当ててみたりしたので記録。
何がしたかったのか
いったんダメな例。
ある特定のブロックに対して斜線を引いてあげるっていう割と簡単そうな実装を行いたかったが、 まぁしんどいめんどい。
getクラスをどう付与するかとかいうJS的な話はどうでもいいので今回は無視してます。
今回は、pタグにgetクラスが当たっている要素に斜線を引っ張りました。
.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指定だったり、レスポンシブ対応だったりで可変の場合もあるでしょうか。もう嫌だ
ブロックの寸法変えたら崩壊した例
今回は、ブロックサイズが可変だったので、特定のサイズに依存しないように斜線を引きたい。
そんなときに出会ったのが、今回ご紹介する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を使ってダメな例を改修
.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(...)
を当てています。
これだと、ブロックの寸法を変更してもちゃんと斜線が斜線として機能します。
ブロックの寸法を変えてもちゃんと斜線が機能しているサンプル
と、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
)になります。
軸が決まるとき、そのブロックに対してのグラデーションの軸及びのその始点 終点が定まります。
第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)
→1・2と同じで、同じ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)
の線が引かれる、ということになります。
と、文字だけだと???な人も多い(私です)と思うので、いろいろ試してみたものを貼っておきます。
グラデーションいろいろ
1. グラデーションしない
.twotone {
border: none !important;
background-image: linear-gradient(to left top, red 50%, lightblue 50%);
}
2色の始点を同じにすることで、グラデーションせず2色が半分ずつそのままの色で表現されます。
2. ちゃんとグラデーションする
.two-gradient {
border: none !important;
background-image: linear-gradient(to left top, red 20%, yellow 80%);
}
始点から0~20%地点までは赤、始点から80%~100%までは黄色がそのままの色。その間(20~80%)を赤と黄色のグラデーションで表現されます。
3. グラデーションの割合(強さ?)を変えてみる
.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>を試してみた
.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