CSS の色指定は、HSL を使っていこう
CSS の色指定は、HSL を使っていこう
色の勉強をしていると、 色の3属性として 色相 (Hue)・彩度 (Saturation)・明度 (Lightness)が出てくる。 しかし、RGBで色を指定しまう(指定する機会が多い)と、 この3属性を活かすことができない。。 hsl();
を使えば、色の3属性そのままで、色を指定することができる。
HSL の利点として、 彩度 (S)と明度 (L)を固定にして、色相 (Hue)を変えるだけで、 同じトーンの色を作ることができる。 さらに、彩度 (S)と色相 (H)を固定にして、 明度 (L)を変えることで、明るさの違う同系色を作ることができる。 色弱の方でも、明度の違いがわかる方は多いので、 アクセシビリティに強い配色を行うことができる。
ColorGenerator(色変換)サンプル
ES6 のclass を使っているので、最新版Chrome で動作します。 range をグリグリして、色を決めることができます。
トーン、同系色サンプル
同じトーンの色、同系色の例を貼っておきます。 codepen.io
hsl対応ブラウザ
対応状況としては、 IE8以前には対応しておらず、 IE9以降のブラウザで対応しています。
Can I use... Support tables for HTML5, CSS3, etc
HSL to RGB
HSL からRGB への変換アルゴリズムは、 W3C の CSS Color Module Level 3 ( 日本語訳: CSS カラーモジュール Level 3)
に書いてあります。
以下に、ABC記法で書かれたHSL to RGB への変換アルゴリズムを 引用して貼っておきます。
HOW TO RETURN hsl.to.rgb(h, s, l): SELECT: l<=0.5: PUT l*(s+1) IN m2 ELSE: PUT l+s-l*s IN m2 PUT l*2-m2 IN m1 PUT hue.to.rgb(m1, m2, h+1/3) IN r PUT hue.to.rgb(m1, m2, h ) IN g PUT hue.to.rgb(m1, m2, h-1/3) IN b RETURN (r, g, b) HOW TO RETURN hue.to.rgb(m1, m2, h): IF h<0: put="" h="" 1="" in="" if="">1: PUT h-1 IN h IF h*6<1: return="" m1="" m2-m1="" h="" 6="" if="" 2="" 1:="" m2="" 3="" 2:="" 3-h="" code="">
これをJS で書いたものを貼っておきます。
function hsl2rgb(h_deg, s_percent, l_percent) {
var h_norm = h_deg / 360;
var s_norm = s_percent / 100;
var l_norm = l_percent / 100;
var m2;
if (l_norm < 0.5) {
m2 = l_norm * (s_norm + 1);
} else {
m2 = l_norm + s_norm - l_norm * s_norm;
}
var m1 = l_norm * 2 - m2;
var r_norm = _hsl2rgb(m1, m2, h_norm + 1 / 3);
var g_norm = _hsl2rgb(m1, m2, h_norm);
var b_norm = _hsl2rgb(m1, m2, h_norm - 1 / 3);
var r = parseInt(Math.round(r_norm * 255));
var g = parseInt(Math.round(g_norm * 255));
var b = parseInt(Math.round(b_norm * 255));
return [r, g, b];
}
function _hsl2rgb(m1, m2, h) {
var _h = h;
if (_h < 0) {
_h = _h + 1;
}
if (_h > 1) {
_h = _h - 1;
}
if (_h * 6 < 1) {
return m1 + (m2 - m1) * _h * 6;
}
if (_h * 2 < 1) {
return m2;
}
if (_h * 3 < 2) {
return m1 + (m2 - m1) * (2 / 3 - _h) * 6;
}
return m1;
}
RGB to HSL
RGB からHSL への変換アルゴリズムは、 W3Cの仕様 CSS Color Module Level 3 には書いてないです。
なので、以下を参考にしました。
詳細は省きますが、JS で書いたコードを貼っておきます。
function rgb2hsl(r, g, b) {
var h = _calcHue(r, g, b);
var s = _calcSaturation(r, g, b);
var l = _calcLightness(r, g, b);
return [h, s, l]
}
色相(H)の計算では、H = 0 (0[deg]red)~1 (360[deg]red)に収めるよう計算します。 H = 1/3 (120[deg])であれば green となり、 H = 2/3 (240[deg])であれば、blue となります。
function _calcHueNorm(r, g, b) {
var color_arr = [r, g, b];
var h_norm = 0.0;
// 等しいとき
if ((color_arr[0] == color_arr[1]) && (color_arr[1] == color_arr[2])) {
h_norm = 0.0;
} else if ((color_arr[0] >= color_arr[1]) && (color_arr[0] >= color_arr[2])) {
// r最大の場合
h_norm = ((color_arr[1] - color_arr[2]) / (Math.max.apply(null, color_arr) - Math.min.apply(null, color_arr))) / 6;
} else if ((color_arr[1] >= color_arr[0]) && (color_arr[1] >= color_arr[2])) {
// g最大の場合
h_norm = ((color_arr[2] - color_arr[1]) / (Math.max.apply(null, color_arr) - Math.min.apply(null, color_arr))) / 6 + 1 / 3;
} else if ((color_arr[2] >= color_arr[0]) && (color_arr[2] >= color_arr[1])) {
// b最大の場合
h_norm = ((color_arr[0] - color_arr[1]) / (Math.max.apply(null, color_arr) - Math.min.apply(null, color_arr))) / 6 + 2 / 3;
}
// 求めたhueが 0以下なら1足す
if (h_norm < 0) {
h_norm += 1;
}
return h_norm;
}
function _calcHue(r, g, b) {
return Math.round(this._calcHueNorm(r, g, b) * 360);
}
明度(L)(輝度)の計算では、 RGBのうち最大値と最小値を求め、その平均になります。 red(rgb(255, 0, 0)), green(rgb(0, 255, 0)), blue(rgb(0, 0, 255))
では、明度は、等しく128(50%) になります。
function _calcLightnessNorm(r, g, b) {
var color = [r, g, b];
var max = Math.max.apply(null, color);
var min = Math.min.apply(null, color);
var l = (max + min) / 2;
l /= 255;
return l;
}
function _calcLightness(r, g, b) {
return Math.round(this._calcLightnessNorm(r, g, b) * 100);
}
彩度(S): 0%というのはRGBがすべて同じで、 グレースケールの世界なので明度の値のとき、S = 0% になる。 一方、彩度: 100%は、彩度0%のときのRGBが均等に拡がって、いずれかが0 または255になったときが S = 100% になる。 なので、輝度(S=0%)とS=100%になるまでの幅と現在値がわかれば、現在の彩度(S)を求めることができる。
function _calcSaturationNorm(r, g, b) {
var color = [r, g, b];
// 収束値CNTを求める
var max = Math.max.apply(null, color);
var min = Math.min.apply(null, color);
var cnt = (max + min) / 2;
var s = 0.0;
if (cnt < 127) {
s = (max - min) / (max + min);
} else if (510 <= (max + min)) {
return 0.0;
} else {
s = (max - min) / (510 - max - min);
}
return s;
}
function _calcSaturation(r, g, b) {
return Math.round(this._calcSaturationNorm(r, g, b) * 100);
}
RGB(10進) to RGB(16進)
RGB10進数からRGB16進数に変換する関数も貼っておきます。
parseInt(hoge).toString(16)
で16進数の文字列へ 変換できます。しかし、00 - 0f にはならず、1桁になってしまうので、 .replace(/^([0-9]|[a-f])$/, '0$&')
で、'0'を 追加するようにしています。
function toHEX() {
return '#' +
parseInt(this.r_).toString(16).replace(/^([0-9]|[a-f])$/, '0$&') +
parseInt(this.g_).toString(16).replace(/^([0-9]|[a-f])$/, '0$&') +
parseInt(this.b_).toString(16).replace(/^([0-9]|[a-f])$/, '0$&');
}
自作Color class コード
上のサンプルで使った、rgb2hsl, hsl2rgb で計算してくれる Color class を貼っておきます。