CSS グラデーションを作る
background-image: 種類(向き 色空間, 色と止め位置…);
決めた向きへ、まっすぐ色が変わります。向きを書かないと上から下へ変わります。
いま linear-gradient(90deg, #0000ff 0%, #ffff00 100%) で描いています。この文字と、下に出るコードは同じものです。
いまのブラウザは sRGB、つまり画面の RGB の数のまま混ぜます。
色と止め位置上から順に、グラデーションの始めから終わりへ並びます1つ目/色 #0000ff/止め位置 0%2つ目/色 #ffff00/止め位置 100%
次の色とのちょうどまん中は、#808080(いまの既定)、#6cabc7(in oklab)です。
background-image: linear-gradient(90deg, #0000ff 0%, #ffff00 100%);
色ではなく画像なので、background-color ではなく background-image に書きます。
よくある質問
青から黄のグラデーションの真ん中が、灰色に見えるのはなぜですか?
色を赤・緑・青の数のまま等分しているからです。青は(0, 0, 255)、黄は(255, 255, 0)なので、ちょうど真ん中では3つとも127.5になります。3つの数が同じ色は灰色なので、真ん中がぴったり灰色になります。計算としては正しいのですが、人が「青と黄の中間」だと感じる色にはなりません。色空間にin oklabと書き足すと、人の感じ方に合わせた場所で混ぜてくれます。
in oklab はどのブラウザで使えますか?
Chrome 111、Edge 111、Firefox 127、Safari 16.2から使えます(MDNのブラウザ互換性データより)。書き方はlinear-gradient(90deg in oklab, blue, yellow)のように、向きのうしろに続けます。注意点は、向きと色空間の間にカンマを打たないことです。この2つは文法の上で1かたまりなので、カンマで割ると値ごと無効になり、グラデーションが消えます。
グラデーションを background-color に書いても効きません。なぜですか?
グラデーションは色ではなく画像だからです。CSSの仕様では、グラデーションは<image>という種類の値で、写真やイラストと同じ仲間にあたります。だから画像を書ける場所にしか置けません。background-imageに書きます。逆に言えば、画像を書ける場所ならどこでも使えるので、border-imageやmask-imageにも書けます。
境目をくっきりさせて、縞模様を作るにはどうしますか?
隣り合う2つの止め位置を同じ数にします。仕様に「複数の色の止め位置が同じ位置にあるとき、その場で色が切り替わる」と書かれています。たとえば青を0%と10%に、白を10%と20%に置くと、10%のところで青から白へ一気に変わります。これをrepeating-linear-gradientにすると、20%ぶんの模様が最後まで繰り返されて縞模様になります。
repeating- を付けたら、思っていない線が出ました。
繰り返しの継ぎ目です。仕様に「最後の色の止め位置と最初の色の止め位置は各くり返しの境目で必ず重なるので、始まりの色と終わりの色が違うと、そこで急な変化が起きる」と書かれています。滑らかにつなぎたいときは、最初の色と最後の色を同じにします。逆に、縞模様を作りたいときはこの飛びをわざと使います。
conic-gradient で円グラフを作っても大丈夫ですか?
見た目は作れますが、それだけで終わらせてはいけません。MDNも「背景画像は読み上げソフトに伝わらないので、円グラフの正しい作り方ではない」と注意しています。グラデーションは背景の画像なので、そこに描かれた割合は文字として存在しません。だから、同じ数字を必ず文字でも書きます。このページの円グラフも、下に時間と割合を文字で並べています。
linear-gradient の角度は、どちらが0度ですか?
0度が真上で、そこから時計回りです。仕様に「0degは上を指し、正の角度は時計回りの回転を表すので、90degは右を向く」と書かれています。時計の針と同じ向きだと考えると間違えません。角度を書かないときはto bottom、つまり上から下へのグラデーションになります。conic-gradientも同じで、真上から始まって時計回りに色が回ります。
色の止め位置は、順番どおりに書かないといけませんか?
書けますが、小さい数へ戻すことはできません。仕様の「色の止め位置の調整」という決まりで、前にある止め位置より小さい位置は、前と同じ位置まで押し上げられます。たとえば0%、80%、30%と書くと、3つ目は80%として扱われます。このとき2つ目と3つ目が同じ位置になるので、そこで色がくっきり切り替わります。上の道具では、押し上げが起きたときに何がどこへ動いたかを画面に出しています。
色と止め位置を足していくと、そのまま貼れる CSS が出ます。 直線・円・円錐の3つと、繰り返しの縞模様まで。
⭐ 青から黄のまん中が灰色になるのは、数を等分しているからです
青から黄へのグラデーションを引くと、まん中がくすんだ灰色になります。 にじんだのでも、画面が悪いのでもありません。計算どおりです。
コンピュータは色を赤・緑・青の3つの数で持っています。 青は (0, 0, 255)、黄は (255, 255, 0)。 この2つのちょうどまん中を数で取ると、3つとも (127.5, 127.5, 127.5) ── つまり 3つの数が全部同じになります。3つが同じ数の色は、灰色です。
数としては、まぎれもなくまん中です。けれど人の目は、明るさや色みを数のとおりには感じません。 だから「数のまん中」と「人が感じるまん中」がずれる、というのがこの現象の正体です。
色を混ぜる場所を変えると直ります
いまの CSS は、どこで色を混ぜるかを選べます。in oklab と書き足すと、人の感じ方に合わせて目盛りを引き直した場所で混ぜてくれます。 下は同じ2色で、変えたのは混ぜる場所だけです。
3つの数がどれも 0 と 255 の組なので、まん中はどれも 127.5 ── つまり灰色そのものです。 まん中の色は、既定が #808080、in oklab が #6cabc7 です。
赤と緑の数だけが入れ替わるので、まん中は暗い黄土色になります。青は 0 のままです。 まん中の色は、既定が #808000、in oklab が #d0a800 です。
in oklch は oklab を色相の輪で表したもので、輪をぐるりと回るため、青と黄のあいだに青緑が出てきます。 どれが正解ということはなく、出したい色で選びます。 ただし止め位置そのものの色は、どれを選んでも変わりません。 仕様にも 「色空間は止め位置のあいだの色にしか効かない」と書かれています。
書き方で1つだけ気をつけるところがあります。向きと色空間のあいだに、カンマを打ってはいけません。文法の上でこの2つは1かたまりなので、カンマで割ると値まるごとが無効になり、グラデーションが消えます。
- ◯
linear-gradient(90deg in oklab, blue, yellow) - ✕
linear-gradient(in oklab, 90deg, blue, yellow)
in oklab のような色空間の指定は、Chrome 111・Edge 111・Firefox 127・Safari 16.2 から使えます(MDN のブラウザー互換性データ(新しいタブで開きます))。 なお仕様のほうは先に進んでいて、新しい草案は 「色空間を書かないときの既定を oklab にする」と書き換えています。ブラウザはまだそこに追いついていません(書かないときと in srgb と書いたときで、描かれる色が1つも変わりません)。 だからいまは、狙うなら自分で書く必要があります。
グラデーションは「色」ではなく「画像」です
ここでつまずく人がとても多いところです。background-color にグラデーションを書いても、何も起きません。
CSS の仕様では、グラデーションは <image>(画像) という種類の値で、写真やイラストと同じ仲間です。 だから画像を書ける場所にしか置けません。 書くのは background-image です。
「画像の仲間」だと分かると、できることが増えます。画像を書ける場所ならどこでも使えるので、枠を塗る border-image や、 絵を型抜きする mask-image にも同じように書けます。絵の具ではなく、その場で描かれる絵を貼っていると考えると近いです。
止め位置を同じ数にすると、境目がくっきりします
グラデーションは「だんだん変わるもの」ですが、だんだん変わらないようにもできます。 やり方は1つだけ ──となり合う2つの止め位置を、同じ数にすることです。
仕様には「複数の色の止め位置が同じ位置にあるとき、その場で色が飛ぶ(infinitesimal transition=限りなく短い変化)」と書かれています。 混ざる区間の長さが 0 になるので、 境目が線のようにくっきりします。
linear-gradient(90deg, #0017c1 0%, #0017c1 50%, #e06c00 50%, #e06c00 100%)
repeating-linear-gradient(45deg, #0017c1 0%, #0017c1 8%, #ffffff 8%, #ffffff 16%)
repeating- を前に付けると、書いた区間が最後までくり返されます。 くっきりした2色をくり返せば縞模様、 斜めにすれば工事現場のしるしのような模様になります。
ここに落とし穴が1つあります。 仕様は「最後の止め位置と最初の止め位置は、くり返しの境目で必ず重なる。だから始まりと終わりの色が違うと、そこで急な変化が起きる」と書いています。 なめらかにくり返したいときは、最初の色と最後の色を同じにします。 縞模様のときは、この飛びをわざと使っているわけです。
⭐ conic-gradient なら、円グラフが CSS だけで描けます
conic-gradient は時計回りに色が変わるグラデーションです。 止め位置を角度で書き、真上(時計の12時)から始まって時計回りに回ります。時計の針と同じ向きです。
ここに「同じ位置に2つ置くとくっきりする」を組み合わせると、円グラフになります。 画像もライブラリも要りません。下の円は div が1つあるだけです。
- ねている ── 8時間(33.33%・120度)
- 学校にいる ── 7時間(29.17%・105度)
- のこり ── 9時間(37.5%・135度)
background-image: conic-gradient(#0017c1 0deg 120deg, #e06c00 120deg 225deg, #00664a 225deg 360deg); border-radius: 50%;
数の作り方はかんたんです。1周は360度で、1日は24時間。 だから 360 ÷ 24 = 15 で、1時間ぶんがちょうど15度です。 8時間なら 8 × 15 = 120度。あとは前の切れの終わりと、次の切れの始まりを同じ角度にするだけです。
丸く見えているのは border-radius: 50% のおかげで、グラデーションそのものは四角い画像です。角を丸く切り抜いています。
円グラフを CSS で描くときの大事な注意です。背景の画像は、読み上げソフトに伝わりません。 MDN もconic-gradient の説明(新しいタブで開きます)で「背景画像はアクセシブルではないので、これは円グラフの正しい作り方ではない」と はっきり注意しています。 絵の中にある数は、画面が見えない人にとっては存在しないのと同じです。 だから同じ数字を必ず文字でも書きます。 このページの円グラフも、 右(狭い画面では下)に時間と割合を文字で並べていて、絵のほうを読み上げから外してあります。
3つの種類は、色の「並べ方」が違うだけです
3つとも、色と止め位置を並べるところは同じです。違うのはどの方向に並べるかだけなので、1つ覚えれば残りも読めます。
- linear-gradient ── まっすぐな線に沿って並べます。 止め位置は%。角度を書かないと上から下です
- radial-gradient ── 中心から外へ、輪が広がるように。
circleなら正円、ellipseなら箱の形に合わせて伸びます - conic-gradient ── 中心のまわりをぐるりと1周。 止め位置は角度。円グラフや色相環はこれです
このページの文法と決まりは、すべて W3C の仕様そのものから取っています。 角度の向き・ くり返しの継ぎ目・同じ位置の止め位置・止め位置の押し上げはCSS Images Module Level 3(新しいタブで開きます)、色空間の指定はCSS Images Module Level 4(新しいタブで開きます)、Oklab の変換式はCSS Color Module Level 4(新しいタブで開きます)から取りました。 対応しているブラウザの版は MDN のブラウザー互換性データで確かめています。 まん中の色(#808080 と #6cabc7)は、計算した値を、実際にブラウザで描いた画素と突き合わせてあります ── 式が合っていても、ブラウザが別のやり方をしていたら、この説明は嘘になるからです。