CSSで文字にグラデーションの色を付ける方法
文字にグラデーションの色を付けるには、要素の背景に linear-gradient() を敷き、background-clip: text で背景を文字の形に切り抜いて、文字の色を transparent にします。見出しの幅が文字より広いと、グラデーションの途中までしか文字に乗らないので、width: fit-content で幅を文字に合わせます。折り返した行で色を行ごとにかけ直すには box-decoration-break: clone を、影を付けるには text-shadow ではなく filter: drop-shadow() を使います。
検証環境は Ubuntu 24.04、Node.js 22.23.4、Playwright 1.63.0、Chromium 153 です。HTML と CSS だけのページを Playwright で開き、スクリーンショットの画素を読んで、文字の左端と右端の色を調べたり、白でない画素の数を数えたりしました。Firefox と Safari、スマートフォンのブラウザ、グラデーションを動かすアニメーションは試していません。
背景を文字の形で切り抜いて、文字の色を透明にする
基本の CSS は次のとおりです。
.gradient-text {
background-image: linear-gradient(90deg, #00c8e8, #d85878);
-webkit-background-clip: text; /* Chrome 119 以前・Safari 13 以前向け */
background-clip: text; /* 背景を文字の形で切り抜く */
color: transparent; /* 文字の色を透明にして、後ろの背景を見せる */
}
<h1 class="gradient-text fit">猫の手を借りる</h1>
fit は、見出しの幅を文字の幅に合わせるクラスです(次の節で説明します)。
linear-gradient() で、左の水色から右のピンクへ変わる背景を作ります。background-clip は背景をどこまで描くかを決めるプロパティで、text を指定すると、背景は文字の形の中にだけ描かれます。MDN の英語版の background-clip のページの説明によると、文字の色が不透明か半透明だと、background-clip: text の効果はほとんど見えません。そのため color: transparent を合わせて書きます。

background-clip: text を外すと、背景が要素の四角いっぱいに描かれ、透明な文字は見えなくなりました。要素の範囲の画素は、すべて白ではなくなっています。付けたときは、白でない画素は要素の範囲の 33.1% で、文字の形の部分だけでした。文字の左端の色は #0fc2e2、右端の色は #ca6282 で、水色からピンクへ変わっています。
見出しの右端までピンクにならないときは、幅を文字に合わせる
h1 のようなブロック要素は、ふつう親の幅いっぱいに広がります。背景のグラデーションは要素の幅いっぱいに描かれるので、文字が短いと、グラデーションの左側だけが文字に乗ります。

幅 640px の見出しに「猫の手」の3文字(幅 144px)を書いたところ、右端の文字の色は #2eb1d1 で、ほとんど水色のままでした。見出しに width: fit-content を付けると、要素の幅が文字の幅(144px)になり、右端の色は #c86181 のピンクになりました。
.fit {
width: fit-content;
}
<h1 class="gradient-text fit">猫の手</h1>
折り返した文字で、行ごとに水色から始めたいときは box-decoration-break: clone
文の中の一部を span で囲んでグラデーションにすると、span が2行に折り返すことがあります。既定では、1行目の最後で止まった色の続きから、2行目が始まります。

幅 624px の1行目と、幅 192px の2行目に折り返した span で測りました。既定のままだと、1行目の右端は #9e7898 の紫がかった色で、2行目の左端は #a97090、右端は #d45b7b でした。2行をつないだ長さで、1本のグラデーションを描いています。
box-decoration-break は、折り返したインライン要素の背景や枠線を、行ごとにどう描くかを決めるプロパティです。既定の slice は、折り返す前の1つのボックスとして描いてから、行ごとに分けます。clone を指定すると、背景を行ごとに描き直します。
.clone {
-webkit-box-decoration-break: clone;
box-decoration-break: clone;
}
<p><span class="gradient-text clone">猫の手も借りたいほど忙しい日のメモ</span></p>
clone にすると、1行目は #0dc3e3 から #ce607f、2行目は #11bfdf から #c86181 になりました。どちらの行も、水色で始まってピンクで終わっています。
MDN の互換性データ(@mdn/browser-compat-data 8.1.8)では、接頭辞なしの box-decoration-break は Chrome 130 から、Firefox 32 から使えます。Chrome 129 以前と Safari は -webkit-box-decoration-break だけに対応していて、インライン要素にだけ効くと書かれています。これらのブラウザにも対応するなら、上のように両方を書きます。
影を付けるなら text-shadow ではなく filter: drop-shadow()
グラデーションの文字に text-shadow を付けると、文字が暗くなります。text-shadow の影は文字の後ろに置かれますが、文字の色を透明にしているので、文字の形の内側にも影の色が見えてしまいます。

text-shadow: 2px 2px 2px rgb(0 0 0 / 0.4) を付けて、影を付けない文字と同じ位置の画素の明るさを比べました。影がないときの平均 138.6 に対して、text-shadow を付けると 101.0 まで下がり、文字の色が濁って見えました。MDN の background-clip のページの例でも、background-clip: text にするときは text-shadow: none にしています。
影を付けたいときは、filter の drop-shadow() を使います。drop-shadow() は、描かれた形(透明でない部分)に沿って影を作ります。
.shadow-filter {
filter: drop-shadow(2px 2px 2px rgb(0 0 0 / 0.4));
}
<h1 class="gradient-text fit shadow-filter">猫の手を借りる</h1>
こちらは、文字の部分の明るさの平均が 138.1 で、影がないときとほとんど変わりませんでした。文字の外側では、影がないときに白かった画素のうち 4,251 個が白でなくなり、影が付いています。
background-clip: text が使えないブラウザでは単色にする
background-clip: text が効かず、背景と color: transparent だけが効くと、最初の比較画像の上の段(background-clip: text を外したもの)と同じになります。背景の四角だけが見えて、文字は読めません。MDN の background-clip のページでも、@supports で対応しているかを確かめ、対応していなければ代わりの表示にすることが勧められています。
.safe-gradient-text {
color: #067a98;
}
@supports (background-clip: text) or (-webkit-background-clip: text) {
.safe-gradient-text {
background-image: linear-gradient(90deg, #00c8e8, #d85878);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
}
Chromium 153 では、この書き方で、白でない画素の割合と左右の端の色が基本の CSS と同じになり、color の計算値は rgba(0, 0, 0, 0)、background-clip は text でした。比べるために、@supports の条件をわざと成り立たないもの(background-clip: no-such-value)に変えたところ、背景は付かず、文字は #067a98 の単色で表示されました。
MDN の互換性データでは、接頭辞なしの background-clip: text は Chrome 120 から、Firefox 49 から、Safari 14 から使えます。ただし Firefox は、background-attachment: fixed と組み合わせたときなどに効かない場合があるという注記付きの、部分的な対応の扱いです。Chrome 119 以前と Safari 13.1 以前は、-webkit-background-clip: text だけに対応していました。検証環境の Chromium 153 では、CSS.supports() で調べると、接頭辞のあるほうもないほうも true でした。





