在项目中,经常会碰到背景色不确定的场景,为了让内容文字足够清晰可见,文字和背景之间需要有足够的对比度。换句话说,当背景是深色时,文字为白色,当背景是浅色时,文字为黑色,就像这样:
一、CSS 滤镜实现
使用滤镜对文字单独处理,所以需要额外一层标签。然后容器和文字用同一种颜色表示,目的是让文字颜色和背景相关联,可以通过currentColor
实现。
用到对比度滤镜(contrast
),在前面的基础上再叠加一层,再用到反转滤镜(invert
),颠倒黑白。
<div class="box">
<span class="text">前端侦探</span>
</div>
<style>
.box {
width: 300px;
height: 300px;
color: #ffeb3b;
background-color: currentColor;
.text {
font-size: 30px;
filter: grayscale(1) contrast(999) invert(1);
}
}
</style>
效果如下:
下面用一张图来表示转换过程:
二、CSS 其他思路
除了上面这种方式,还可以通过 CSS 变量来实现,要复杂一些。
这里简单介绍一下实现思路
- 将颜色
RGB
值拆分成 3 个独立的 CSS变量 - 通过灰度算法,用 CSS 计算函数算出灰度
- 用得到的灰度和阈值做差值,通过
hsl
模式转换成纯黑和纯白
:root {
/* 定义RGB变量 */
--red: 44;
--green: 135;
--blue: 255;
/* 文字颜色变色的临界值,建议0.5~0.6 */
--threshold: 0.5;
}
.btn {
/* 按钮背景色就是基本背景色 */
background: rgb(var(--red), var(--green), var(--blue));
/**
* 使用sRGB Luma方法计算灰度(可以看成亮度)
* 算法为:
* lightness = (red * 0.2126 + green * 0.7152 + blue * 0.0722) / 255
*/
--r: calc(var(--red) * 0.2126);
--g: calc(var(--green) * 0.7152);
--b: calc(var(--blue) * 0.0722);
--sum: calc(var(--r) + var(--g) + var(--b));
--lightness: calc(var(--sum) / 255);
/* 设置颜色 */
color: hsl(0, 0%, calc((var(--lightness) - var(--threshold)) * -999999%));
}
相比前面的实现而言,实现更加灵活,可以少一层标签。
另外,CSS 正在起草一个颜色对比函数color-contrast
,可以从几个颜色中自动选择对比度最高的那个,实现是这样的
.text-contrast-primary {
color: color-contrast(var(--theme-primary) vs white, black);
}
不过,现在还没有任何浏览器支持。
三、优缺点总结
总的来说,在color-contrast
函数支持之前,我更推荐 CSS 滤镜方式,有以下几点好处
- 代码简洁,就一行代码,3 个滤镜
- 对颜色格式无任何要求,无需转换成
RGB
模式 - 无需了解颜色算法,对设计更为友好
当然,也是存在一些缺点
- 需要单独一层标签,使用场景可能有限制
- 对颜色敏感度较高,不然无从下手
- 颜色转换有限制,最终只能是黑白,其他颜色就无能为力了
下面来回顾一下用到的3个滤镜,总结一下
- 灰度滤镜(
grayscale
),可以将彩色的文字转换成灰色 - 对比度滤镜(
contrast
),可以极大的增强对比度,黑的更黑,白的更白,如果是浅灰,那就变成白色,如果是深灰,那就变成黑色 - 反转滤镜(
invert
),可以翻转颜色,颠倒黑白