Sassのcolor.mixで結果がrgb()形式になってしまうので、HEX形式で出力するようにした

当ページのリンクには広告が含まれています。
Sassのcolor.mixで結果がrgb()形式になってしまうので、HEX形式で出力するようにした

以前、色の濃度を変えるにはSassのmixが便利だね、という記事を書きました。

私も今ではIllustratorのデザインデータでコーディングすることも少なくなりましたが、先日、当時の案件の修正を行なっていたところ、mix関数辺りに異変が起きていました。

2025年現在のSassのmixモジュールの使い方を、改めて検証してみます。

目次

起きていた異変

数年前に制作したWebサイトのSassを更新し、コンパイルを行ったところ、以下のようなエラーが。

Warning:
Global built-in functions are deprecated and will be removed in Dart Sass 3.0.0.
Use color.mix instead.

そのまま翻訳してみます。

警告:
グローバル組み込み関数は非推奨であり、Dart Sass 3.0.0 で削除されます。
代わりに color.mix を使用してください。

mixは組み込み関数として使用していましたが、Dart Sass v3ではビルトインモジュールとして使用することになったようです。

そこで、書き方を以下のように変更すると、無事コンパイルできるように。
※詳細や経緯は前述の記事をご確認ください

//Before

//関数の設定
@function colorMix($color, $percent) {
  @return mix($color, #fff, $percent * 1%);
}

これを、こう。

//After

@use "sass:color";        //追加

//関数の設定
@function colorMix($color, $percent) {
  @return color.mix($color, #fff, $percent * 1%);     //「color.mix」表記に変更
}

解決、解決ぅ♪とルンルンでコンパイルされたコードの差分チェックを行うと、新たな異変が。

以前はカラーコード(16進数 / HEX / #XXXXXXの形式)で出力されていたはずのCSSが、なぜかrgb()形式で出力されていました。

しかも、小数点という細かい数値で。

mixの出力形式が変わってしまった原因

どうやら、Dart Sass v3 の color.mix() の結果は「内部的に計算した色」をそのまま出すので、#fccのような16進数ではなく rgb() 形式で出力されることがあるとのこと。
これは仕様であって、color.mix() 側に「16進数で出力する」というオプションはない模様。

公式ドキュメントによると、$methodで色空間を指定できるそうなのですが、私の場合は結果は同じでした。

@use ‘sass:color’;
@debug color.mix(#036, #d2e1dd, $method: rgb); // #698aa2

Sass: sass:color

rgb()のままでも正確であれば良いのですが、やはり保守はしにくいなぁということで、HEX形式で出力できるようにしてみました。

color.mix() の結果をHEX形式で出力する

もちろん、color.mix()だけでは出力できないので、自前で hex 文字列に変換する関数を作ってみます。
具体的な処理はこんな感じ。

  1. 以前のようにcolor.mix()で色を変換する
  2. 1.で出力されたrgb()形式のカラーをR/G/Bに分解する
  3. 2.のカラーを16進に変換
  4. 3.を連結して #rrggbb を組み立てる
// sassモジュールの読み込み
@use 'sass:color';
@use 'sass:string';
@use 'sass:math';

// 関数の設定
// rgb()形式のカラー(0〜255)の数値を、2桁の16進文字列に変換
@function toHex($n) {
  $hexchars: '0123456789abcdef';
  $n: math.round($n);
  $hi: math.floor(math.div($n, 16)) + 1;
  $lo: ($n % 16) + 1;
  @return string.slice($hexchars, $hi, $hi) + string.slice($hexchars, $lo, $lo);
}

// #rrggbbを返す関数
@function hexColor($c) {
  $r: color.channel($c, 'red', $space: rgb);
  $g: color.channel($c, 'green', $space: rgb);
  $b: color.channel($c, 'blue', $space: rgb);
  @return string.unquote('#' + toHex($r) + toHex($g) + toHex($b));
}

// colo.mix()の処理
@function colorMix($color, $weight) {
  @return hexColor(color.mix($color, #fff, $weight * 1%));
}

// SCSSの表記
.example {
  background: colorMix(#00619e, 30);
}

// コンパイルされたCSS(#00619eを30%まで薄くした色)
background: #b3d0e2;

この処理を挟むことで、color.mix()の出力結果をrgb()ではなくHEX形式にすることはできました。

出力されたカラーコードとしては、前回の記事の「mixを使用したSassの結果」と同じ結果となりました。
より正確に変換されていた結果を、曖昧な数値に戻してしまった、という感じですね。

前回の記事の検証結果

なお、私は「色の濃度を変える」ことを目的としているので、color.mix()の2色目を#fff(白)に固定している+色の混ぜる割合($weight)の指定時の%表記をラクしてます。

本来は「2色を混ぜる」機能ですので、2色で行う場合はこちらで。

@function colorMix($color1, $color2, $weight: 50%) {
  @return hexColor(color.mix($color1, $color2, $weight));
}

//SCSSの表記
.example {
  background: colorMix(#ff0000, #00ffff, 20%);
}

まとめ

Dart Sass v3では、color.mix() の結果がrgb() で出力されてしまうため、HEX形式で出力するようにしてみた話でした。

前回の記事で、mixで出力した値が、ところどころ意図しない結果になっていたのが不思議でしたが、元々「内部的に計算した色」を無理やりHEX形式にしていたので誤差が出ていたのかなぁと、今さら気づきました。

今回も結果的には同じことをしているので、この小さな誤差を通していいのかはデザイナーさんにもご相談いただくなど、使用についてはご自身にて確認・判断いただければと思います。

参考になりましたら、記事をシェアいただけると嬉しいです!
  • URLをコピーしました!
目次