顏色模型,是用來表示顏色的數學模型。比如最常見的 RGB模型
,使用 紅綠藍
三色來表示顏色。
一般的顏色模型,可以按照如下分類:
面向硬體裝置的顏色模型:RGB,CMYK,YCrCb。
面向視覺感知的顏色模型:HSL,HSV(B),HSI,Lab。
不同的顏色模型有不同的應用場景,而RGB模型適合於顯示器這樣的的裝置。
其中,前端支援的是 RGB
、HSL
,即在前端頁面中只有這兩種模型的顏色值可以有效展示出來。
而對於 HSV
,則是我們在建立顏色選擇器外掛時所需要了解的一種模型。
目前,chrome
瀏覽器,實現 H5
的顏色色盤,就是基於 HSV
模型:
注意:fixfore
瀏覽器支援的仍然是電腦系統色盤(如win系統下,與畫圖軟體中編輯顏色的色盤一樣)。
本文將主要介紹 RGB
、HSL
、HSV
這三種模型。
RGB模型
RGB 即常說的 紅(R)、綠(G)、藍(B)
三原色模型,是運用最廣泛的顏色模型。
特別是在前端開發中,幾乎都使用該模型處理顏色。如:rgb(0, 0, 255)
,#d3d3d3
。
該模型通過紅綠藍三個顏色通道的變化和相互之間的混合疊加,使用不同的強度,表現出不同的顏色。
它是一種加色混色模型,在疊加混合的過程中,亮度等於色彩亮度的綜合,混合的越多亮度就越高。
根據三色的取值不同,一般有以下幾種型別:
- R5G5B5(A1):16位,各色都用5位表示,取值範圍
0-31(2^5 - 1)
,剩餘1位作Alpha通道或者不用。 - R5G6B5:16位,R和B佔用5位,取值範圍
0-31(2^5)
;G佔用6位,取值範圍0-63(2^6 - 1)
。 - R8G8B8:24位,各色都用8位表示,取值範圍為
0-255(2^8 - 1)
。
最多能有2^24
種顏色,從24位開始的顏色就是真彩色,基本達到人眼極限。 - R8G8B8(A8):32位,各色都用8位表示,取值範圍為
0-255(2^8 - 1)
,剩餘8位作Alpha通道或者不用。
這其中,最常見的當然就是24位和32位的型別。
三色通道中每個顏色有256階的亮度,為0時最暗,255時最亮。
如果三色的數值都相同時,就會產生不同灰度值的灰度色調,都為0時最暗黑色,都為255時最亮白色。
RGB顏色值
先看下 RGB
顏色值在前端的展現,如紅色:
'rgb(255, 0, 0)'
'rgba(255, 0, 0, 1)' // 帶透明度
'#ff0000'
'#f00' // 縮寫
'red' // 顏色名稱
描述RGB模型,使用的顏色值,有 rgb
和 hex16
進位制兩種方式。
rgb(0,0,0)
表示法,一般情況下,紅綠藍三色分別取值範圍0-255
,如果加上alpha
透明通道,則為rgba(0,0,0,1)
。hex
16進製表示法,採用十六進位制對24位元的一種展示方式,如#000000
,共6位,每兩位分別對應紅綠藍,相同時可縮寫為#000
。
hex
也可以使用#00000000
,後面加上透明度的十六進位制數值。
此外,在前端開發中,還可以使用顏色名稱如 red
、green
、gray
等標識顏色。
實際上,這裡的顏色名稱仍然是對應的一個RGB顏色值,有一個規定的顏色名稱與值的關係表。大部分的顏色單詞基本都能使用。
上面兩種表示法的簡單轉換關係,如下所示。
rgb 轉 hex
function getHex (num) {
let val = num.toString(16)
val = (val.length === 1) ? ('0' + val) : val
return val
}
function rgbaToHexa (red, green, blue, alpha) {
red = getHex(red)
green = getHex(green)
blue = getHex(blue)
alpha = Math.round(alpha * 255)
alpha = getHex(alpha)
return '#' + red + green + blue + alpha
}
hex 轉 rgb
function hexaToRgba (color) {
const value = color.slice(color.indexOf('#') + 1)
const isShort = value.length === 3 || value.length === 4
const hasAlpha = value.length === 4 || value.length === 8
const r = isShort ? (value.charAt(0) + value.charAt(0)) : value.substring(0, 2)
const g = isShort ? (value.charAt(1) + value.charAt(1)) : value.substring(2, 4)
const b = isShort ? (value.charAt(2) + value.charAt(2)) : value.substring(4, 6)
let a = hasAlpha ? (isShort ? (value.charAt(3) + value.charAt(3)) : value.substring(6, 8)) : 'FF'
a = parseFloat((parseInt(a, 16) / 255).toFixed(2))
return [parseInt(r, 16), parseInt(g, 16), parseInt(b, 16), a]
}
HSL模型
前端在顏色的處理上,除了支援 RGB
模型外,另外支援的就只有 HSL
模型,所以我們需要了下解該模型。
HSL
顏色值表示,紅色:
hsl(0, 100%, 50%)
hsla(0, 100%, 50%, 1) // 帶透明度
HSL 是對色相H(hue)
、飽和度S(saturation)
、亮度L(lightness)
的處理得到顏色的一種模型。
-
色相(H):
色相、色調,代表人眼所能看到的不同的顏色,本質就是一種顏色。與HSV(B)
模型中的H
概念相同。
色相的定義中,許多的顏色分佈在一個圓環上,取值範圍則是 0-360度,每個角度代表著一種顏色。
在HSL和HSV的模型中,色相是以六大主色為基礎,他們分別按 60 度的間隔排列在圓環上。這六大主色分別是:360°/0°紅、60°黃、120°綠、180°青、240°藍、300°洋紅。
而在前端進行處理時,常常把圓環處理成長方形的色塊,通過顏色的線性漸變方式進行分段處理,角度換算成一定的比例,如下所示:
linear-gradient(90deg, #f00, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00);
-
飽和度(S):
飽和度是指顏色的強度或純度,使用0 ~ 100%
的百分比來度量。
表示色相中顏色成分所佔的比例,數值越大,顏色中的灰色越少,顏色越鮮豔,呈現的是一種從灰色到色相顏色的變化。 -
亮度(L):
表現顏色的明暗程度,使用0 ~ 100%
的百分比來度量。
反映色彩中混入的黑白兩色,50% 處只有純色,小於 50% 時,數值越小混入的黑色越多,越接近於黑色;大於 50% 時,數值越大混入的白色越多,越接近於白色。
L最大時必為白色,L最小時必為黑色。
體現的是從黑色到色相(H)選擇顏色再到白色的過渡。
HSV(B)模型
HSV
顏色值表示,紅色:
// 前端不支援
hsv(0, 100%, 100%)
hsva(0, 100%, 100%, 1) // 帶透明度
HSV 採用色相H(hue)
、飽和度S(saturation)
、明度V(Value)
3個引數來表示顏色的一種方式。
HSV
和 HSL
兩個模型都是更偏向於視覺上直觀的感覺。
而HSV
與 HSB
的內容基本是一樣的,可以理解為兩種不同寫法而已,其中 B( brightness )。
-
色相(H):
同HSL
模型中的H
色相。 -
飽和度(S):
飽和度是指顏色的強度或純度,使用0 ~ 100%
的百分比來度量。
在HSV
中更多的是反映色相的顏色中混入白色的值,值越大白色越少色相顏色越純,值越小白色越多色相顏色越淡。 -
明度(V):
表現顏色的明暗程度,使用0 ~ 100%
的百分比來度量。
反映色相的顏色中混入的黑色的值,值越小黑色越多顏色更暗(黑),值越大黑色越少顏色更純(亮)。
體現的是從黑色到色相(H)選擇顏色的過渡。
RGB 與 HSL 的轉換
下面是常用的 rgb
顏色值與 hsl
之間互相轉換的程式碼。
注意:
這兩個過程中,由於取整去除了小數位,並不是完全可逆的,可能存在個別個位數的差值。
雖有些微差別,但在頁面顏色顯示上基本沒分別,因為人眼分辨不出來。
rgb 轉 hsl
function rgbToHsl (red, green, blue) {
red = red / 255
green = green / 255
blue = blue / 255
let hue = saturation = lightness = 0
const max = Math.max(red, green, blue)
const min = Math.min(red, green, blue)
const diff = max - min
const sum = max + min
lightness = sum / 2
if (diff) {
saturation = lightness > 0.5 ? diff / (2 - sum) : diff / sum
switch (max) {
case red:
hue = (green - blue) / diff + (green < blue ? 6 : 0)
break
case green:
hue = (blue - red) / diff + 2
break
case blue:
hue = (red - green) / diff + 4
break
}
hue = hue / 6
}
hue = Math.round(hue * 360)
saturation = Math.round(saturation * 100)
lightness = Math.round(lightness * 100)
return [hue, saturation, lightness]
}
hsl 轉 rgb
function hslToRgb(hue, saturation, lightness) {
hue = hue / 360
saturation = saturation / 100
lightness = lightness / 100
let red, green, blue
const hue2rgb = (val1, val2, vH) => {
vH = vH < 0 ? (vH + 1) : vH > 1 ? (vH - 1) : vH
if (vH < 1 / 6) {
return val1 + (val2 - val1) * 6 * vH
}
if (vH < 1 / 2) {
return val2
}
if (vH < 2 / 3) {
return val1 + (val2 - val1) * (2 / 3 - vH) * 6
}
return val1
}
if (saturation === 0) {
red = green = blue = lightness;
} else {
const val2 = lightness <= 0.5 ? lightness * (saturation + 1) : (lightness + saturation) - (lightness * saturation)
const val1 = lightness * 2 - val2
red = hue2rgb(val1, val2, hue + 1 / 3)
green = hue2rgb(val1, val2, hue)
blue = hue2rgb(val1, val2, hue - 1 / 3)
}
red = Math.round(red * 255)
green = Math.round(green * 255)
blue = Math.round(blue * 255)
return [red, green, blue]
}