设想一个这样的场景:
UI给了一个比如#FFA91E的HEX给你,让你用于给一个iconfont上色,并且图标的背景色是这个颜色的某一透明度色。你会如何实现?
设置透明度首先会想到用opacity,但如果背景色使用 opacity 会把被设置的元素及其子元素同时设置为同一个透明度,iconfont也跟着透明了,效果不符合预期,opacity就不能用了。
那要如何解决这个问题呢?
一、将6位HEX转成RGBA
因为rgba的alpha值可以设透明度而不影响子元素,所以我们可以手动把6位HEX格式转成RGB格式,再加上alpha值就能写成rgba(x, x, x, alpha)。
其实HEX转RGB就是十进制转十六进制,最简单的办法就是用JS原生的parseInt() 函数帮我们做转换。
我们都知道parseInt的第二个可选参数radix可以设置被解析值的进制数,当然既然是可选,就意味着它有些默认行为。这个默认行为就是,parseInt会根据第一个参数来推算radix的值;比如,当第一个参数为0x开头,那么radix就会被推算成16。
如果 radix 是 undefined、0或未指定的,JavaScript会假定以下情况:
- 如果输入的 string以 "0x"或 “0x”(一个0,后面是小写或大写的X)开头,那么radix被假定为16,字符串的其余部分被解析为十六进制数。
- 如果输入的 string以 “0”(0)开头, radix被假定为8(八进制)或10(十进制)。具体选择哪一个radix取决于实现。ECMAScript 5 澄清了应该使用 10 (十进制),但不是所有的浏览器都支持。因此,在使用 parseInt 时,一定要指定一个 radix。
- 如果输入的 string 以任何其他值开头, radix 是 10 (十进制)。
根据说明,我们有两种方式HEX转RGB,可以parseInt(hex.slice(x, x+2), 16); 也可以parseInt('0x'+hex.slice(x, x+2))。出于规范和安全的考虑,我们使用第一种指定radix的方式进行转换:
const hexToRgba = (bgColor, alpha) => {
let color = bgColor.slice(1); // 去掉'#'号
let rgba = [
parseInt(color.slice(0, 2), 16),
parseInt(color.slice(2, 4), 16),
parseInt(color.slice(4, 6), 16),
alpha
];
return `rgba(${rgba.join()})`
};
二、使用8位HEX
CSS Color Module Level 4标准在2014年推出过8位hex和4位hex来支持设置alpha值,以实现hex和rgba的互转。
8位hex就是在6位hex基础上加后两位来表示alpha值,00表示完全透明,ff表示完全不透明。
同理,4位hex是在3位hex基础上加后一位来表示alpha值,0表示完全透明,f表示完全不透明。
以下三种写法表示的是同一个颜色:
.element {
background: rgba(0, 255, 0, 0.53); // rgba
background: #0f08; //4位hex
background: #00ff0088; //8位hex
}
以下是摘自文章8-Digit Hex Codes?的alpha值的十进制和十六进制对照表:
| Alpha % | Hex | Rgb 255 |
|---|---|---|
| 100% | FF | 255 |
| 95% | F2 | 242 |
| 90% | E6 | 230 |
| 85% | D9 | 217 |
| 80% | CC | 204 |
| 75% | BF | 191 |
| 70% | B3 | 179 |
| 65% | A6 | 166 |
| 60% | 99 | 153 |
| 55% | 8C | 140 |
| 50% | 80 | 128 |
| 45% | 73 | 115 |
| 40% | 66 | 102 |
| 35% | 59 | 89 |
| 30% | 4D | 77 |
| 25% | 40 | 64 |
| 20% | 33 | 51 |
| 15% | 26 | 38 |
| 10% | 1A | 26 |
| 5% | 0D | 13 |
| 0% | 00 | 0 |