1. ホーム
  2. CSS

【CSS】currentColor の使い方|文字色を border・背景・SVG に引き継いで色指定をまとめる方法

Share

ボタンの枠線、その中のアイコン、通知ボックスの帯やアイコン——ひとつの部品を作っていると、同じ色を何か所にも書くことになります。色違いのバリエーションを追加するたびに border-color と fill と background-color を並べて書き直すのは面倒ですし、どこか 1 つ書き換え忘れて色がちぐはぐになるのもよくある話です。そこで役に立つのが CSS の currentColor です。

currentColor は「その要素に効いている文字色」を指すキーワードで、色を受け取れるプロパティならどこにでも書けます。これを使うと部品の色指定が color の 1 行に集約され、バリエーションもホバーも color を書き換えるだけで済みます。この記事では、currentColor の仕組みと使えるプロパティ、ボタンや SVG アイコンでの実践例、カスタムプロパティ(CSS 変数)との使い分け、そして「色が変わらない」ときの原因までを、動かせるデモ付きで解説します。

currentColor は「その要素に効いている color の値」を指すキーワード

MDN の説明どおり、currentColor キーワードはその要素の color プロパティの値を表します。#1a73e8 や rgb(26 115 232) と同じように「色の値」のひとつとして扱われるので、色を受け取るプロパティであれば、プロパティの種類を問わず書けます。

style.css
.box {
  color: #1a73e8;

  /* 以下の 3 つはすべて #1a73e8 になる */
  border: 2px solid currentColor;
  outline-color: currentColor;
  box-shadow: 0 0 0 4px currentColor;
}

この例だけを見ると「#1a73e8 と 4 回書けばいいのでは」と思うかもしれません。currentColor の本当の価値は、色を変えるときに color の 1 か所だけ直せば全部が追従するところにあります。ホバー、フォーカス、色違いのバリエーション、ダークモードと、色を切り替える場面はいくらでもあるので、この差はすぐに効いてきます。

もうひとつ重要なのが、color は継承されるプロパティだという点です。親要素に color を指定すれば、その中の子孫要素にも同じ color が伝わります。つまり、子要素側で border-top: 1px solid currentColor; のように書いておけば、親から降りてきた文字色をそのまま参照できます。親の color を変えれば、その線の色も一緒に変わります。

border の色を省略すると文字色になるのは currentColor のおかげ

border: 1px solid; と色を書かずに枠線を指定すると、枠線が文字と同じ色で表示されます。これはブラウザーの気の利いた挙動ではなく、border-color の初期値が currentcolor だからです。border は一括指定プロパティなので、値を省略した border-color は初期値、つまり currentcolor にリセットされます。

つまり border: 2px solid currentColor; と border: 2px solid; は同じ結果になります。ただしチームで書くコードなら、currentColor と明示しておくほうが安全です。省略形は「色を書き忘れている」ようにも見えるため、あとから誰かが色を足してしまうことがあります。

初期値が currentcolor になっているプロパティは border-color だけではありません。主なものは次のとおりです。これらは色を指定しなければ、自動的に文字色が使われます。

プロパティ役割と初期値の意味
border-color枠線の色。初期値が currentcolor なので、色を書かなければ文字色で描かれる
border-block-color / border-inline-color論理プロパティ版の枠線の色。こちらも初期値は currentcolor
text-decoration-color下線・取り消し線の色。初期値が currentcolor なので、既定では文字と同じ色になる
column-rule-color段組み(マルチカラム)の段と段の間に引く線の色。初期値は currentcolor
text-emphasis-color圏点(傍点)の色。初期値は currentcolor

currentColor を書ける主なプロパティ

初期値が currentcolor ではないプロパティでも、色の値を受け取るものであれば currentColor と書けます。実務でよく使う組み合わせを整理しておきます。

書き方使いどころ
border-color: currentColor文字色に合わせた枠線。アウトラインボタンやタグの定番
background-color: currentColor文字色のベタ塗り。区切りの帯、インジケーター、下線代わりのバーなど
outline-color: currentColorフォーカスリングの色を部品の色に合わせる
box-shadow: 0 2px 4px currentColor影の色。色の指定を省略した場合も currentColor が使われる
text-decoration-color: currentColor下線の色を文字色に戻したいとき(初期値なので明示は任意)
caret-color: currentColor入力欄のカーソル(キャレット)を文字色にそろえる
fill: currentColor / stroke: currentColorインライン SVG の塗りと線を文字色にそろえる。アイコンで最もよく使う

box-shadow と text-shadow は少し特殊で、色の値を書かずに box-shadow: 0 2px 4px; と指定すると currentColor が使われます。ただし文字色そのままの影は多くの場合濃すぎるので、実際には rgb(0 0 0 / 0.15) のように別途指定するほうが自然です。「省略すると currentColor になる」という仕様を知っていれば、影の色が想定外に濃くなったときの原因にすぐ気付けます。

下のデモは、3 枚のカードでcolor の 1 行だけを変えているものです。枠線・上部の帯・アイコンの色は共通のクラスにまとめて書いてあり、カードごとの指定は一切ありません。CSS タブを開いて、色の指定がどこに 1 か所だけ書かれているかを確認してみてください。

<div class="cards">
  <div class="card card--blue">
    <div class="card__bar"></div>
    <p class="card__title">
      <svg class="card__icon" viewBox="0 0 24 24" aria-hidden="true">
        <path d="M12 2 15.1 8.6 22 9.6l-5 5 1.2 7.1L12 18.3 5.8 21.7 7 14.6l-5-5 6.9-1z"/>
      </svg>
      color: #1a73e8
    </p>
    <p class="card__text">枠線・帯・アイコンの色は書いていません。</p>
  </div>

  <div class="card card--green">
    <div class="card__bar"></div>
    <p class="card__title">
      <svg class="card__icon" viewBox="0 0 24 24" aria-hidden="true">
        <path d="M12 2 15.1 8.6 22 9.6l-5 5 1.2 7.1L12 18.3 5.8 21.7 7 14.6l-5-5 6.9-1z"/>
      </svg>
      color: #188038
    </p>
    <p class="card__text">違うのは color の 1 行だけです。</p>
  </div>

  <div class="card card--red">
    <div class="card__bar"></div>
    <p class="card__title">
      <svg class="card__icon" viewBox="0 0 24 24" aria-hidden="true">
        <path d="M12 2 15.1 8.6 22 9.6l-5 5 1.2 7.1L12 18.3 5.8 21.7 7 14.6l-5-5 6.9-1z"/>
      </svg>
      color: #d93025
    </p>
    <p class="card__text">まとめて色が切り替わります。</p>
  </div>
</div>
.cards {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  padding: 16px;
  font-family: sans-serif;
  font-size: 14px;
}

/* 色に関する指定は、この共通クラスの中では一切書かない */
.card {
  flex: 1 1 180px;
  padding: 16px;
  border-radius: 8px;
  background: #fff;
  /* border-color の初期値は currentcolor なので、色を省略すると文字色になる */
  border: 2px solid;
}

.card__bar {
  height: 6px;
  margin-bottom: 12px;
  border-radius: 3px;
  /* 背景色にも currentColor が使える */
  background-color: currentColor;
}

.card__title {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0 0 8px;
  font-weight: bold;
}

.card__icon {
  width: 18px;
  height: 18px;
  /* インライン SVG の塗りも文字色に合わせる */
  fill: currentColor;
}

.card__text {
  margin: 0;
  color: #555;
  font-size: 13px;
}

/* 各カードで変えているのは color だけ */
.card--blue {
  color: #1a73e8;
}

.card--green {
  color: #188038;
}

.card--red {
  color: #d93025;
}
Preview

currentColor を使わなければ、カードの種類ごとに border-color・background-color・fill を書くことになり、3 色なら 9 行に増えます。currentColor なら、色を増やすコストは 1 行だけです。

ボタンのホバーを color の 1 行だけで切り替える

currentColor が最も効くのが、状態によって色が変わるボタンです。枠線とアイコンを currentColor にしておけば、:hover や :focus-visible で書くのは color の 1 行で済みます。色違いのバリエーションも同じで、修飾クラスに color を書くだけで枠線もアイコンも付いてきます。

<div class="demo">
  <p class="demo__note">マウスを載せると、文字色につられて枠線とアイコンの色も変わります。</p>

  <div class="demo__row">
    <button class="btn" type="button">
      <svg class="btn__icon" viewBox="0 0 24 24" aria-hidden="true">
        <path d="M12 21 3 12.3a5.4 5.4 0 0 1 7.6-7.6l1.4 1.3 1.4-1.3a5.4 5.4 0 1 1 7.6 7.6z"/>
      </svg>
      お気に入りに追加
    </button>

    <button class="btn btn--danger" type="button">
      <svg class="btn__icon" viewBox="0 0 24 24" aria-hidden="true">
        <path d="M6 7h12l-1 13H7zM9 4h6l1 2H8z"/>
      </svg>
      削除する
    </button>
  </div>
</div>
.demo {
  padding: 16px;
  font-family: sans-serif;
  font-size: 14px;
}

.demo__note {
  margin: 0 0 12px;
  color: #555;
  font-size: 13px;
}

.demo__row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 18px;
  border-radius: 999px;
  background: #fff;
  font: inherit;
  cursor: pointer;
  /* この 1 行が枠線とアイコンの色の基準になる */
  color: #1a73e8;
  /* 枠線の色を書かない = currentColor */
  border: 2px solid;
  /* 色の変化をなめらかにする */
  transition: color 0.2s, border-color 0.2s, background-color 0.2s;
}

.btn__icon {
  width: 18px;
  height: 18px;
  fill: currentColor;
}

/* ホバーで変えるのも color だけ */
.btn:hover {
  color: #0b47a1;
  background-color: #eef4fd;
}

/* フォーカスリングの色も文字色に合わせる */
.btn:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 3px;
}

/* 色違いのボタンは color を上書きするだけで作れる */
.btn--danger {
  color: #d93025;
}

.btn--danger:hover {
  color: #a50e0e;
  background-color: #fdeeec;
}
Preview

ポイントは、.btn の中に色の指定が color: #1a73e8; の 1 行しかないことです。枠線は border: 2px solid; と色を省略し、アイコンは fill: currentColor;、フォーカスリングは outline: 2px solid currentColor; にしてあります。そのため .btn:hover と .btn--danger では color を上書きするだけで、部品全体の色が切り替わります。

色の変化をアニメーションさせたいときは、transition: color 0.2s, border-color 0.2s, background-color 0.2s; のように、color だけでなく currentColor を使っているプロパティも並べて書いておくのが確実です。

インライン SVG のアイコンを文字色にそろえる

アイコンは currentColor の代表的な使い道です。SVG の塗りを決める fill 属性は色の値を受け取るので、fill="currentColor" と書いておけば、そのアイコンは置かれた場所の文字色で描かれます。ボタンの中に置けばボタンの色に、見出しの中に置けば見出しの色になる、という具合です。

配布されている素材は fill="#333333" のように色が埋め込まれていることが多いので、その部分を currentColor に書き換えたうえで、SVG のコードを HTML にそのまま貼り付けて使います。width と height は CSS 側で指定し、装飾目的のアイコンには aria-hidden="true" を付けて読み上げから外しておくと親切です。

index.html
<p class="note">
  <svg class="icon" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
    <path d="M12 21 3 12.3a5.4 5.4 0 0 1 7.6-7.6l1.4 1.3 1.4-1.3a5.4 5.4 0 1 1 7.6 7.6z"/>
  </svg>
  この段落の文字色とアイコンの色がそろいます
</p>

fill は SVG の属性としても CSS のプロパティとしても書けます。属性に書き忘れた素材をまとめて扱いたいときは、CSS 側で指定するほうが確実です。SVG の fill 属性のようなプレゼンテーション属性は作成者のスタイルシートより弱いため、CSS の指定が優先されるからです。

style.css
.icon {
  width: 1em;   /* 文字サイズに連動させると収まりが良い */
  height: 1em;
  fill: currentColor;
  vertical-align: -0.125em;
}

色は currentColor、大きさは em という組み合わせにしておくと、アイコンが周囲の文字にそのまま馴染むので、置く場所ごとの調整がほとんど要らなくなります。

通知ボックスを color の指定 1 行で作り分ける

お知らせ・成功・エラーのように、同じ形で色だけが違う部品も currentColor の出番です。枠線・左の帯・アイコンをすべて currentColor にまとめておけば、種類を増やすときに書くのは color の 1 行だけになります。

<div class="alerts">
  <div class="alert alert--info">
    <svg class="alert__icon" viewBox="0 0 24 24" aria-hidden="true">
      <path d="M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20zm1 15h-2v-6h2zm0-8h-2V7h2z"/>
    </svg>
    <div class="alert__body">
      <p class="alert__title">お知らせ</p>
      <p class="alert__text">帯・枠線・アイコン・見出しの色を個別に指定していません。</p>
    </div>
  </div>

  <div class="alert alert--success">
    <svg class="alert__icon" viewBox="0 0 24 24" aria-hidden="true">
      <path d="M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20zm-1 15-5-5 1.4-1.4L11 13.2l5.6-5.6L18 9z"/>
    </svg>
    <div class="alert__body">
      <p class="alert__title">保存しました</p>
      <p class="alert__text">修飾クラスで color を変えているだけです。</p>
    </div>
  </div>

  <div class="alert alert--error">
    <svg class="alert__icon" viewBox="0 0 24 24" aria-hidden="true">
      <path d="M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20zm1 15h-2v-2h2zm0-4h-2V7h2z"/>
    </svg>
    <div class="alert__body">
      <p class="alert__title">入力エラー</p>
      <p class="alert__text">配色の追加は color を 1 行足すだけで済みます。</p>
    </div>
  </div>
</div>
.alerts {
  display: grid;
  gap: 12px;
  padding: 16px;
  font-family: sans-serif;
  font-size: 14px;
}

.alert {
  position: relative;
  display: flex;
  gap: 12px;
  padding: 14px 16px 14px 24px;
  border-radius: 8px;
  background: #fff;
  /* 枠線の色は指定しない(currentColor) */
  border: 1px solid;
  overflow: hidden;
}

/* 疑似要素は元の要素から color を受け継ぐので currentColor が使える */
.alert::before {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 6px;
  background-color: currentColor;
}

.alert__icon {
  flex: none;
  width: 20px;
  height: 20px;
  margin-top: 2px;
  fill: currentColor;
}

.alert__title {
  margin: 0 0 4px;
  font-weight: bold;
}

/* 本文だけは読みやすさのために色を上書きする */
.alert__text {
  margin: 0;
  color: #444;
  font-size: 13px;
}

/* 種類ごとに変えるのは color の 1 行だけ */
.alert--info {
  color: #1a73e8;
}

.alert--success {
  color: #188038;
}

.alert--error {
  color: #d93025;
}
Preview

CSS を見ると、.alert--info / .alert--success / .alert--error の中身が color だけになっているのが分かります。共通の .alert には枠線と ::before の帯、アイコンの fill が書かれていますが、いずれも色は currentColor です。

ここで効いているのが、疑似要素は生成元の要素から color を受け継ぐという性質です。.alert::before に background-color: currentColor; と書くと、その要素(.alert)の文字色が使われるので、帯の色も自動的にそろいます。::before や ::after で作る装飾と currentColor は相性が良い組み合わせです。

ひとつだけ注意したいのが、color は文字の色でもあるという点です。上のデモでは本文の .alert__text にだけ color: #444; を指定して、読みやすさを確保しています。部品のテーマ色をそのまま本文に使うと、色によっては文字が読みづらくなるので、長い文章の部分は個別に色を上書きしておくのが無難です。

カスタムプロパティ(CSS 変数)との違いと使い分け

「色をまとめて管理する」という話になると、--main-color のようなカスタムプロパティ(CSS 変数)を思い浮かべる方も多いはずです。どちらも色を一元管理できますが、性質はかなり違います。

比較currentColorカスタムプロパティ
値の出どころその要素に効いている color の値(固定)自分で定義した --名前 の値
持てる数1 要素につき 1 色だけいくつでも定義できる
入れられる値色のみ色に限らず、サイズでも文字列でも何でも
文字色への影響color がそのまま文字色になる定義しただけでは何も起きない
定義の必要不要(color があれば書ける)あらかじめ --名前: 値; の定義が必要

使い分けの基準はシンプルで、その色が文字色と同じでよいなら currentColor、文字色とは別の色なら カスタムプロパティです。アウトラインボタンの枠線やアイコンのように、文字と一体で色が変わる要素は currentColor の独壇場です。一方で「文字は黒のまま、背景だけブランドカラー」のように文字色と切り離したい色は、color に縛られないカスタムプロパティのほうが素直に書けます。

両者は競合するものではなく、組み合わせて使うのが実用的です。サイト全体の色をカスタムプロパティで定義しておき、部品の中では color を起点に配る、という形にすると、色の管理とコードの短さを両立できます。

style.css
/* 1. サイト全体の色はカスタムプロパティで定義する */
:root {
  --color-brand: #1a73e8;
  --color-danger: #d93025;
}

/* 2. 部品では color に代入し、あとは currentColor で配る */
.btn {
  color: var(--color-brand);
  border: 2px solid;
}

.btn .icon {
  fill: currentColor;
}

/* 3. バリエーションは color の代入先を差し替えるだけ */
.btn--danger {
  color: var(--color-danger);
}

ダークモードへの対応も同じ考え方でまとめられます。prefers-color-scheme のメディアクエリで color(またはその元になるカスタムプロパティ)を差し替えれば、currentColor を使っている枠線もアイコンも一緒に切り替わります。

style.css
@media (prefers-color-scheme: dark) {
  :root {
    /* ここを変えるだけで、currentColor を使った箇所はすべて追従する */
    --color-brand: #8ab4f8;
  }
}

currentColor を使ったのに色が変わらないとき

currentColor がうまく効かない場面には、決まったパターンがあります。原因が分かれば対処も決まっているので、順に見ていきます。

img タグで読み込んだ SVG には外側の色が届かない

一番よく遭遇するのがこれです。fill="currentColor" と書いた SVG ファイルを <img src="icon-heart.svg"> として読み込むと、周囲の文字色をいくら変えてもアイコンは黒いままです。

理由は、<img> で読み込まれた SVG がページ本体とは別の文書として扱われるためです。読み込み元のページに書いた CSS は SVG の中には届かず、SVG 側から見た color は自分自身の値だけになります。そこに color の指定がなければ初期値(多くの環境では黒)が使われ、結果としてアイコンは黒く描かれます。

対処は、SVG のコードを HTML に直接書き込む(インライン SVG にする)ことです。同じ文書の一部になれば、周囲の color がそのまま継承されます。

background-image に指定した SVG でも currentColor は効かない

background-image: url("icon.svg"); のように背景画像として読み込む場合も、理由は <img> のときと同じです。data: URI で SVG を直接埋め込んだ場合も、やはり別の文書なので currentColor はページ側の文字色を参照できません。セレクトボックスの矢印などを背景画像で描いていて、色を変えられずに困るのはこのパターンです。

解決策は、画像を「絵」ではなく「型(マスク)」として使うことです。mask-image で SVG の形に切り抜き、実際の色は background-color: currentColor; で塗ります。こうすれば色を決めているのはページ側の CSS なので、文字色にきちんと追従します。

style.css
.icon-mask {
  display: inline-block;
  width: 1em;
  height: 1em;

  /* 色はこちらで決める */
  background-color: currentColor;

  /* SVG は形を切り抜く型として使う(接頭辞付きを先に書く) */
  -webkit-mask: url("icon-heart.svg") no-repeat center / contain;
  mask: url("icon-heart.svg") no-repeat center / contain;
}

ただしこの方法が使えるのは、単色のシルエットで表現できるアイコンに限られます。多色のイラストをマスクにすると塗り分けが失われて 1 色になるので、その場合はインライン SVG を選んでください。

SVG の中の path に色が直接書かれている

インライン SVG にしたのにアイコンの色が変わらない場合は、SVG の中身を確認してください。<path fill="#333333" /> のように、子要素そのものに色が指定されていることがよくあります。

この状態で svg { fill: currentColor; } と書いても、それは <svg> 要素に対する指定でしかありません。<path> は親から fill を継承しますが、自分自身に fill が指定されていれば、そちらが継承より優先されます。結果として #333333 のまま描かれるわけです。

対処は 2 つです。SVG 側の fill 属性を削除して親からの継承に任せるか、CSS のセレクターを <path> 自身に届くように書き換えるかです。素材をそのまま使いたいときは後者が手軽です。

style.css
/* path の fill 属性ごと上書きする。
   SVG のプレゼンテーション属性は CSS より弱いので、こちらが勝つ */
.icon path,
.icon circle,
.icon rect {
  fill: currentColor;
}

color プロパティ自身に currentColor を書いても自分の色にはならない

color: currentColor; という書き方は、循環しそうに見えて実は明確に定義されています。MDN の説明によれば、currentColor が color プロパティの値として使われた場合は、color が継承した値(親要素の文字色)が使われます。color: inherit; と書いたのと同じ結果になる、と考えて構いません。

つまり「自分の色を自分で参照する」わけではないので、期待した色にならないことがあります。紛らわしいので、親の色をそのまま使いたいときは素直に color: inherit; と書くのがおすすめです。とくにボタンやリンクなど、ブラウザーの既定スタイルが色を当ててくる要素で「親の文字色に戻したい」場面では color: inherit; が定番になります。

まとめ

currentColor は、その要素に効いている color の値を指すキーワードです。色を受け取るプロパティならどこにでも書けるので、border-color・background-color・outline-color・box-shadow・インライン SVG の fill や stroke といった色指定を、color の 1 行に集約できます。border-color や text-decoration-color のように初期値が currentcolor のプロパティは、色を書かないだけで自動的に文字色に追従します。

ホバーや色違いのバリエーション、ダークモードなど「色が切り替わる」場面ほど効果が大きく、書く量も書き換え漏れも確実に減ります。文字色と連動させたい色は currentColor、文字色とは独立した色はカスタムプロパティ、と役割を分けて使うのがコツです。色が変わらないときは、SVG を <img> や背景画像で読み込んでいないか、<path> に fill が直接書かれていないかをまず疑ってください。

参考ページ