如何根据背景颜色动态修改文字颜色

12,959 阅读4分钟

效果

先看下效果图

效果

需求

我司有个需求,用户可以自定义主题色。但当我使用选色器选择不同颜色的时候,发现了一个问题。如果用户选择黑色为主题色,然后字体颜色也是黑色的,那他不就看不到字体了吗。

效果

思考

突发奇想

思考问题,如何判断背景色什么时候使用黑色还是白色的字体时,ps里面有个方法去色提醒了我。

去色:把RGB三通道的色彩信息设置成一样;即:R=G=B,那么图像就变成了灰色,并且,为了保证图像亮度不变,同一个通道中的R、G、B相加应为1。即:R+G+B=1;如:0.213+0.715+0.072=1; 此时RGB=0.213, 0.715, 0.072

0.2130.7150.072三个数字是如何来的,感兴趣的同学可以去了解一下Color FAQ颜色矩阵

为什么一定要是灰色?

色彩分为两大类:有彩色系与无彩色系,有彩色系与无彩色系。

最大的区别在于,有彩色系有色彩三属性及色相、饱和度、明度。

无彩色系不会受到色相、饱和度的干扰。(黑白灰均属于无彩色系)

参考灰度与色彩

这样做有什么意义呢?

我们可以通过计算背景颜色色值正常灰色色值进行对比。

如果背景颜色正常灰色色值要大的话,说明背景颜色是偏黑的,此时使用白色的字体。

如果背景颜色正常灰色色值要小的话,说明背景颜色是偏白的,此时使用黑色字体。

开始实践

思路理清了,看下能否实现

我们先选择好一个rgb色值,改为数组:

const rgbArr = [15, 35, 64];

由于灰色的色值是(128, 128, 128),通过判断灰色色值255/2识别rgb相对的大小

/**
 * 转换字体颜色
 * 
 * @param {array} rgbArr rgb数组
 */
function resBgColor(rgbArr) {
    // 当color值大于128时,color值偏向255,即#ffffff,此时字体颜色应为#000000
    // 当color值小于128时,color值偏向0,即#000000,此时字体颜色应为#ffffff
    var color = 0.213 * rgbArr[0] + 0.715 * rgbArr[1] + 0.072 * rgbArr[2] > 255 / 2;
    return color? '#000000': '#ffffff'
}

使用

var textColor = resBgColor(rgbArr);
console.log(textColor)      // #ffffff

成功了,竟然如此简单就完成了。那么要做成上面gif的效果要怎样实现呢?

进阶

一般我们会使用rgb(12,34,56)或者是#123456形式来进行颜色配置,为了方便我们使用函数resBgcolor,那么我们需要新编译一个函数findTextColor转为rgbArr的数组

rgbArr = [15, 35, 64];

下面方法是统一返回rgb数组后并且执行字体匹配resBgcolor(colorValue)的最终代码

function findTextColor(colorValue) {
    // #123456或者rgb(12,34,56)转为rgb数组[12,34,56]
    const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
    var that = colorValue;
    if (/^(rgb|RGB)/.test(that)) {
        // 处理rgb转为数组
        var aColor = that.replace(/(?:\(|\)|rgb|RGB)*/g, "").split(",");
        return resBgColor(aColor);
    } else if (reg.test(that)) {
        // 处理十六进制色值
        var sColor = colorValue.toLowerCase();
        if (sColor && reg.test(sColor)) {
            if (sColor.length === 4) {
            var sColorNew = "#";
            for (var i = 1; i < 4; i += 1) {
                sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1));
            }
            sColor = sColorNew;
        }
        //处理六位的颜色值
        var sColorChange = [];
        for (var i = 1; i < 7; i += 2) {
            sColorChange.push(parseInt("0x" + sColor.slice(i, i + 2)));
        }
        return resBgColor(sColorChange);
        } else {
            return false;
        }
    } else {
        return false;
    }
}

再次使用

// 用法一:
var textColor = findTextColor('#000');
console.log(textColor);     // #ffffff

// 用法二:
var textColor2 = findTextColor('rgb(255, 255, 255)');
console.log(textColor2);    // #000000

更酷炫的玩法

我在html页面引入一个颜色选择器,然后通过选择器返回的值来给我的文字颜色赋值。

效果

下面放主要代码

JavaScript:

var textDom = document.getElementById('color-text');
var obj = document.getElementById("picker");

var a = Colorpicker.create({
    el: "color-picker",
    color: "#0081ff",
    change: function (elem, hex) {
        textDom.style.color = TEXTColor.colorRgb(hex);
        elem.style.backgroundColor = hex;
    }
})

HTML:

<div class="container">
    <h2>点击下方选择颜色</h2>
    <div class="picker" id="color-picker">
        <div id="color-text">文字颜色</div>
    </div>
</div>

具体的demo已经上传到了github,你也可以在github上下载我的demo玩耍(欢迎⭐)。

为你所用

我已经将该函数封装并发布到npm上面,你可以通过npm install安装或者直接引用

安装方法

方法一:通过npm引入

npm install textcolor --save

方法二:通过<script>引入

<script type="type/javascript" src="https://unpkg.com/textcolor@1.0.2/textcolor.js" ></script>

用法

如何使用TEXTColor

import TEXTColor from 'textcolor'

let hex = '#000000';        // or '#666' or 'rgb(12,34,56)'
let textcolor = TEXTColor.findTextColor(hex);
console.log(textcolor)      // #ffffff

结语

如果本文对你有任何帮助的话,感谢点个赞支持一下作者😄