目录
- 引言
- 浏览器支持性
- HSL介绍
- HSL相较于RGB的优势在哪?
- HSL在网页设计的应用场景
- 如何用代码转换hsl
- RGB转HSL
- HSL转RGB
- HEX格式的互转
- 总结
引言
本篇不会对rgb颜色模型或是hsl颜色模型的显色原理进行深入的探究,仅从前端开发角度去论述在工作中选择哪种比较合适。
- 大多数电视机、显示器、投影仪通过将不同强度的红、绿、蓝色光混合来生成不同的颜色,这就是RGB三原色的加色法。通过这种方法可以在RGB色彩空间生成大量不同的颜色,然而,这三种颜色分量的取值与所生成的颜色之间的联系并不直观。
- 艺术家有时偏好使用HSL或HSV而不选择三原色光模式(即RGB模型)或 印刷四分色模式(即CMYK模型),因为它类似于人类感觉颜色的方式,具有较强的感知度。HSL以人类更熟悉的方式封装了关于颜色的信息:“这是什么颜色?深浅如何?明暗如何?”。
浏览器支持性
- 在Can i use?网站上查询到hsl的支持性结果为:
目前为止主流的浏览器均支持hsl颜色,所以可以放心使用。
HSL介绍
HLS 有三个分量,hue(色相)、saturation(饱和度)、lightness(亮度)。
-
hue代表色相(色相环角度),色相的定义中,许多的颜色分布在一个圆环上,取值范围则是 0-360度,每个角度代表着一种颜色。以六大主色为基础,他们分别按 60 度的间隔排列在圆环上。这六大主色分别是:360°/0°红、60°黄、120°绿、180°青、240°蓝、300°洋红。
-
saturation代表饱和度。饱和度是指颜色的强度或纯度,使用 0 ~ 100% 的百分比来度量。表示色相中颜色成分所占的比例,数值越大,颜色中的灰色越少,颜色越鲜艳,呈现的是一种从灰色到色相颜色的变化。
-
lightness代表亮度,表现颜色的明暗程度,使用 0 ~ 100% 的百分比来度量。反映色彩中混入的黑白两色,50% 处只有纯色,小于 50% 时,数值越小混入的黑色越多,越接近于黑色;大于 50% 时,数值越大混入的白色越多,越接近于白色。
-
一般在css中写法为:hsl( 255, 90%, 50% ) 或是带透明度 hsal( 255, 90%, 50%, 0.5 )。
HSL相较于RGB的优势在哪?
- 感知相关性:RGB模型中的颜色分量并不直接对应人类对颜色的感知。在RGB中改变一个颜色的单个分量(红、绿或蓝),通常不会产生直观的颜色变化。相比之下,HSL模型的设计更接近人类对颜色的认知,其中色相(Hue)代表颜色的基本色调,饱和度(Saturation)代表颜色的纯度,亮度(Lightness)代表颜色的明暗程度。因此,在需要根据感知调整颜色时,HSL往往更为直观。
- 颜色混合:当需要混合颜色以获得新的颜色时,使用RGB模型可能不容易预测结果。而在HSL模型中,可以通过较为简单的方式调整颜色的各个方面,如改变色相来得到类似的颜色变化,调整饱和度来控制颜色的鲜艳度等。
- 计算复杂性:虽然RGB模型直接对应于硬件上的颜色生成,但在需要进行复杂的颜色运算时,如颜色渐变、颜色过滤或者颜色对比度调整等,HSL模型可能提供更加简便的方法。
- 易于编程和算法实现:对于某些图形处理算法来说,使用HSL模型可以使某些任务变得更简单,比如色彩校正、图像分割和颜色过滤等。
HSL在网页设计的应用场景
- 颜色主题生成:使用HSL可以方便地生成一系列颜色,这些颜色共享相同的色相或亮度,但有不同的饱和度,从而创建出和谐的颜色主题。
- 生成互补色:使用HSL可以快速的为网站logo或标题icon设置强烈对比的互补色,只需要将hue值+180即可,根据实际需求动态调整。
- 交互反馈:在设计交互元素时,可以使用HSL来创建动态的颜色变化,例如当用户悬停或点击按钮时,通过调整饱和度或亮度来提供视觉反馈。
- 其实只要是小幅度调整参数即可获得颜色变化的场景都适合使用hsl,hsl带来的好处就是可以更符合直觉的去生成颜色,而不用像rgb一样变换颜色毫无规律。
举个交互反馈的例子:
button{background: hsl(200, 50%, 50%); /* 蓝色调背景 */transition: background-color 2s;
}
// 仅提高亮度即可提供选中的视觉反馈效果
button:hover {background: hsl(200, 50%, 70%); /* 亮一点的蓝色 */
}
如何用代码转换hsl
RGB转HSL
设(r,g,b)分别是一个颜色的红、绿和蓝坐标,它们的值是在0到1之间的实数。设 max等价于(r,g,b)中的最大者。设 min等于这些值中的最小者。要找到在HSL空间中的(r,g,b)值,这里的h∈[0,360)度是角度的色相角,而s,l∈[0,1] 是饱和度和亮度,计算为:
h的值通常规范化到位于0到360°之间。
以下是js代码实现,返回值为数组,分别对应hue(色相)、saturation(饱和度)、lightness(亮度)。
/*** rgb2hsl** @param {number} r 红色颜色值 0~255* @param {number} g 绿色颜色值 0~255* @param {number} b 蓝色颜色值 0~255*/
function rgb2hsl(r, g, b) {r /= 255;g /= 255;b /= 255;const max = Math.max(r, g, b);const min = Math.min(r, g, b);const diff = max - min;let h = 0;let l = (max + min) / 2;let s = 0;if (max === min) {h = 0;} else if (max === r && g >= b) {h = 60 * ((g - b) / diff);} else if (max === r && g < b) {h = 60 * ((g - b) / diff) + 360;} else if (max === g) {h = 60 * ((b - r) / diff) + 120;} else if (max === b) {h = 60 * ((r - g) / diff) + 240;};if (l === 0 || max === min) {s = 0;} else if (0 < l && l <= 0.5) {s = diff / (2 * l);} else if (l > 0.5) {s = diff / (2 - 2 * l);};return [Math.round(h), Math.round(s * 100), Math.round(l * 100)];
}
HSL转RGB
给定HSL空间中的(h,s,l)值定义的一个颜色,h在指示色相角度的值域 [0,360] 中,s和l在饱和度和亮度的值域 [0,1] 中。相应在RGB空间中的(r,g,b)三原色,r,g和b也分别对应于红色、绿色和蓝色的值域[0,1]中,它们可计算为:
首先,如果s=0,则结果的颜色是非彩色的、或灰色的。在这个特殊情况,r,g和b都等于l。注意h的值在这种情况下是未定义的。
当s≠0的时候,可以使用下列过程:
以下是js代码实现,返回值为数组,分别对应R(红)、g(绿)、b(蓝)。
/*** hsl2rgb** @param {number} h Hue 色调 0 ~ 360* @param {number} s Saturation 饱和度 0 ~ 100* @param {number} l Lightness 亮度 0 ~ 100*/
function hsl2rgb(h, s, l) {h /= 360;s /= 100;l /= 100;let r = 0;let g = 0;let b = 0;let p = 0;let q = 0;function rgb(t, p, q) {if (t < 1.0 / 6.0) {return p + (q - p) * 6.0 * t;} else if (t >= 1.0 / 6.0 && t < 1.0 / 2.0) {return q;} else if (t >= 1.0 / 2.0 && t < 2.0 / 3.0) {return p + (q - p) * ((2.0 / 3.0) - t) * 6.0;} else {return p;}}function _rgb(t) {if (t < 0) {return t + 1.0;} else if (t > 1) {return t - 1.0;} else {return t;}}if (s === 0) {r = g = b = l;} else {q = l < 0.5 ? l * (1.0 + s) : l + s - l * s;p = 2.0 * l - q;r = rgb(_rgb(h + 1.0 / 3.0), p, q);g = rgb(_rgb(h), p, q);b = rgb(_rgb(h - 1.0 / 3.0), p, q);}return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
HEX格式的互转
HEX只是由16进制数字代表了0-255,都可以通过rgb作为桥梁去转换hsl格式。
以下是hex和rgb的互转的js实现:
/*** rgb2hex** @param {number} r 红色颜色值 0~255* @param {number} g 绿色颜色值 0~255* @param {number} b 蓝色颜色值 0~255* @param {number} a 透明度 0~100,默认100*/
function rgb2hex(r, g, b, a) {if (typeof a === 'undefined') {a = '';}else {a = Math.round(255 * a / 100);a = (a | 1 << 8).toString(16).slice(1);}const val = ((b | g << 8 | r << 16) | 1 << 24).toString(16).slice(1);return val.toUpperCase() + a.toUpperCase();
}/*** hex2rgb** @param {string} hex hex颜色值 eg: #000、#325312、#b2c343*/
function hex2rgb(hex) {hex = hex.replace(/^#/, '');let a = null;if (hex.length === 8) {a = parseInt(hex.slice(6, 8), 16) / 255;hex = hex.slice(0, 6);}if (hex.length === 4) {a = parseInt(hex.slice(3, 4).repeat(2), 16) / 255;hex = hex.slice(0, 3);}if (hex.length === 3) {hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];}const num = parseInt(hex, 16);const r = num >> 16;const g = (num >> 8) & 255;const b = num & 255;const rgb = [r, g, b];if (a !== null) {rgb.push(Math.round(a * 100));}return rgb;
}
总结
在日常开发过程中,大多数情况下UI提供的颜色值为rgb或者hex格式,有些设计网站会直接提供hsl格式的色值。通过这篇文章主要想阐述一个事实,那就是hsl相对于rgb在前端开发领域是有很大优势的,尤其是编码层面上。使用hsl会使css的编码更加清晰,得到的颜色大概率不会偏离预期。可能现阶段大家用的不是很多,所以会有所抵触,在使用一段时间后,相信你会爱上这种颜色模式。