我想展示一些像这个例子的图片

填充颜色由数据库中颜色为十六进制的字段决定(例如:ClassX -> color: #66FFFF)。 现在,我想显示上面的数据与所选的颜色填充(如上图),但我需要知道如果颜色是暗或光,所以我知道如果文字应该在白色或黑色。 有办法吗?谢谢大家


当前回答

以我对类似问题的回答为基础。

您需要将十六进制代码分解为3个部分,以获得单独的红色、绿色和蓝色强度。代码的每两个数字代表一个十六进制(以16为基数)表示法的值。这里我就不详细讲了,它们很容易查到。

一旦有了各个颜色的强度,就可以确定颜色的整体强度并选择相应的文本。

if (red*0.299 + green*0.587 + blue*0.114) > 186 use #000000 else use #ffffff

186的阈值是基于理论的,但可以根据口味进行调整。根据评论,低于150的阈值可能更适合您。


Edit: The above is simple and works reasonably well, and seems to have good acceptance here at StackOverflow. However, one of the comments below shows it can lead to non-compliance with W3C guidelines in some circumstances. Herewith I derive a modified form that always chooses the highest contrast based on the guidelines. If you don't need to conform to W3C rules then I'd stick with the simpler formula above. For an interesting look into the problems with this see Contrast Ratio Math and Related Visual Issues.

The formula given for contrast in the W3C Recommendations (WCAG 2.0) is (L1 + 0.05) / (L2 + 0.05), where L1 is the luminance of the lightest color and L2 is the luminance of the darkest on a scale of 0.0-1.0. The luminance of black is 0.0 and white is 1.0, so substituting those values lets you determine the one with the highest contrast. If the contrast for black is greater than the contrast for white, use black, otherwise use white. Given the luminance of the color you're testing as L the test becomes:

if (L + 0.05) / (0.0 + 0.05) > (1.0 + 0.05) / (L + 0.05) use #000000 else use #ffffff

这在代数上简化为:

if L > sqrt(1.05 * 0.05) - 0.05

或约:

if L > 0.179 use #000000 else use #ffffff

唯一剩下的就是计算l。该公式也在指南中给出,它看起来像从sRGB到线性RGB的转换,然后是ITU-R建议BT.709的亮度。

for each c in r,g,b:
    c = c / 255.0
    if c <= 0.04045 then c = c/12.92 else c = ((c+0.055)/1.055) ^ 2.4
L = 0.2126 * r + 0.7152 * g + 0.0722 * b

阈值0.179不应该改变,因为它与W3C指南相关联。如果你发现结果不是你喜欢的,试试上面更简单的公式。

其他回答

我从来没有做过这样的事情,但是写一个函数来检查每个颜色的值与十六进制7F (FF / 2)的中位数颜色。如果三种颜色中有两种大于7F,那么你正在使用较深的颜色。

从hex到black或white:

function hexToRgb(hex) {
  var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
  return result
    ? [
        parseInt(result[1], 16),
        parseInt(result[2], 16),
        parseInt(result[3], 16)
      ]
    : [0, 0, 0];
}

function lum(hex) {
  var rgb = hexToRgb(hex)
  var lrgb = [];
  rgb.forEach(function(c) {
    c = c / 255.0;
    if (c <= 0.03928) {
      c = c / 12.92;
    } else {
      c = Math.pow((c + 0.055) / 1.055, 2.4);
    }
    lrgb.push(c);
  });
  var lum = 0.2126 * lrgb[0] + 0.7152 * lrgb[1] + 0.0722 * lrgb[2];
  return lum > 0.179 ? "#000000" : "#ffffff";
}

我不认为这段代码是我的功劳,因为它不是我的,但我把它留在这里,让其他人将来很快就能找到:

根据Mark Ransoms的回答,下面是一个简单版本的代码片段:

function pickTextColorBasedOnBgColorSimple(bgColor, lightColor, darkColor) {
  var color = (bgColor.charAt(0) === '#') ? bgColor.substring(1, 7) : bgColor;
  var r = parseInt(color.substring(0, 2), 16); // hexToR
  var g = parseInt(color.substring(2, 4), 16); // hexToG
  var b = parseInt(color.substring(4, 6), 16); // hexToB
  return (((r * 0.299) + (g * 0.587) + (b * 0.114)) > 186) ?
    darkColor : lightColor;
}

下面是高级版本的代码片段:

function pickTextColorBasedOnBgColorAdvanced(bgColor, lightColor, darkColor) {
  var color = (bgColor.charAt(0) === '#') ? bgColor.substring(1, 7) : bgColor;
  var r = parseInt(color.substring(0, 2), 16); // hexToR
  var g = parseInt(color.substring(2, 4), 16); // hexToG
  var b = parseInt(color.substring(4, 6), 16); // hexToB
  var uicolors = [r / 255, g / 255, b / 255];
  var c = uicolors.map((col) => {
    if (col <= 0.03928) {
      return col / 12.92;
    }
    return Math.pow((col + 0.055) / 1.055, 2.4);
  });
  var L = (0.2126 * c[0]) + (0.7152 * c[1]) + (0.0722 * c[2]);
  return (L > 0.179) ? darkColor : lightColor;
}

要使用它们,只需调用:

var color = '#EEACAE' // this can be any color
pickTextColorBasedOnBgColorSimple(color, '#FFFFFF', '#000000');

同时,感谢Alx和chetstone。

除了算术解决方案,还可以使用人工智能神经网络。这样做的好处是,你可以根据自己的口味和需求来定制它。灰白色的文字在明亮的饱和红色上看起来很好,和黑色一样可读)。

下面是一个简洁的Javascript演示,演示了这个概念。你也可以在演示中生成自己的JS公式。

https://harthur.github.io/brain/

下面是一些帮助我解决这个问题的图表。 在第一个图表中,亮度是一个常数128,而色调和饱和度变化。在第二张图中,饱和度是恒定的255,而色调和亮度变化。

以我对类似问题的回答为基础。

您需要将十六进制代码分解为3个部分,以获得单独的红色、绿色和蓝色强度。代码的每两个数字代表一个十六进制(以16为基数)表示法的值。这里我就不详细讲了,它们很容易查到。

一旦有了各个颜色的强度,就可以确定颜色的整体强度并选择相应的文本。

if (red*0.299 + green*0.587 + blue*0.114) > 186 use #000000 else use #ffffff

186的阈值是基于理论的,但可以根据口味进行调整。根据评论,低于150的阈值可能更适合您。


Edit: The above is simple and works reasonably well, and seems to have good acceptance here at StackOverflow. However, one of the comments below shows it can lead to non-compliance with W3C guidelines in some circumstances. Herewith I derive a modified form that always chooses the highest contrast based on the guidelines. If you don't need to conform to W3C rules then I'd stick with the simpler formula above. For an interesting look into the problems with this see Contrast Ratio Math and Related Visual Issues.

The formula given for contrast in the W3C Recommendations (WCAG 2.0) is (L1 + 0.05) / (L2 + 0.05), where L1 is the luminance of the lightest color and L2 is the luminance of the darkest on a scale of 0.0-1.0. The luminance of black is 0.0 and white is 1.0, so substituting those values lets you determine the one with the highest contrast. If the contrast for black is greater than the contrast for white, use black, otherwise use white. Given the luminance of the color you're testing as L the test becomes:

if (L + 0.05) / (0.0 + 0.05) > (1.0 + 0.05) / (L + 0.05) use #000000 else use #ffffff

这在代数上简化为:

if L > sqrt(1.05 * 0.05) - 0.05

或约:

if L > 0.179 use #000000 else use #ffffff

唯一剩下的就是计算l。该公式也在指南中给出,它看起来像从sRGB到线性RGB的转换,然后是ITU-R建议BT.709的亮度。

for each c in r,g,b:
    c = c / 255.0
    if c <= 0.04045 then c = c/12.92 else c = ((c+0.055)/1.055) ^ 2.4
L = 0.2126 * r + 0.7152 * g + 0.0722 * b

阈值0.179不应该改变,因为它与W3C指南相关联。如果你发现结果不是你喜欢的,试试上面更简单的公式。