CSS 如何根据背景色自动切换黑白文字?

发布时间 2023-06-16 15:31:49作者: 蓦然JL

在项目中,经常会碰到背景色不确定的场景,为了让内容文字足够清晰可见,文字和背景之间需要有足够的对比度。换句话说,当背景是深色时,文字为白色,当背景是浅色时,文字为黑色,就像这样:

一、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 变量来实现,要复杂一些。

这里简单介绍一下实现思路

  1. 将颜色RGB值拆分成 3 个独立的 CSS变量
  2. 通过灰度算法,用 CSS 计算函数算出灰度
  3. 用得到的灰度和阈值做差值,通过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 滤镜方式,有以下几点好处

  1. 代码简洁,就一行代码,3 个滤镜
  2. 对颜色格式无任何要求,无需转换成 RGB模式
  3. 无需了解颜色算法,对设计更为友好

当然,也是存在一些缺点

  1. 需要单独一层标签,使用场景可能有限制
  2. 对颜色敏感度较高,不然无从下手
  3. 颜色转换有限制,最终只能是黑白,其他颜色就无能为力了

下面来回顾一下用到的3个滤镜,总结一下

  1. 灰度滤镜(grayscale),可以将彩色的文字转换成灰色
  2. 对比度滤镜(contrast),可以极大的增强对比度,黑的更黑,白的更白,如果是浅灰,那就变成白色,如果是深灰,那就变成黑色
  3. 反转滤镜(invert),可以翻转颜色,颠倒黑白