如何根据背景颜色决定白色或黑色的字体颜色?

DJP*_*JPB 183 colors contrast

我想展示一些像这个例子的图像替代文字

填充颜​​色由数据库中的字段决定,颜色为十六进制(例如:ClassX - >颜色:#66FFFF).现在,我想用所选颜色显示填充上方的数据(如上图所示),但我需要知道颜色是暗还是浅,所以我知道这些单词应该是白色还是黑色.有办法吗?TKS

Mar*_*som 295

基于我对类似问题的回答.

您需要将十六进制代码分成3个部分以获得单独的红色,绿色和蓝色强度.代码的每两个数字代表十六进制(base-16)表示法的值.我不会在这里了解转换的细节,它们很容易查找.

获得单个颜色的强度后,您可以确定颜色的总强度并选择相应的文本.

if (red*0.299 + green*0.587 + blue*0.114) > 186 use #000000 else use #ffffff
Run Code Online (Sandbox Code Playgroud)

186的阈值基于理论,但可以根据需要进行调整.根据以下评论,阈值150可能对您更有效.


编辑:上面很简单,工作得相当好,似乎在StackOverflow上有很好的接受度.但是,下面的一条评论表明,在某些情况下,它可能导致不遵守W3C指南.在此,我推导出一种经过修改的形式,总是根据指南选择最高对比度.如果你没有需要遵循W3C规则,那么我会用上述简单的公式坚持.

W3C建议书中给出对比度的公式是(L1 + 0.05) / (L2 + 0.05),最亮L1颜色的亮度在哪里L2,最暗的亮度是0.0-1.0.黑色的亮度为0.0,白色为1.0,因此用这些值代替可以确定对比度最高的那个.如果黑色的对比度大于白色的对比度,请使用黑色,否则使用白色.给定测试颜色的亮度,L测试成为:

if (L + 0.05) / (0.0 + 0.05) > (1.0 + 0.05) / (L + 0.05) use #000000 else use #ffffff
Run Code Online (Sandbox Code Playgroud)

这简化了代数:

if L > sqrt(1.05 * 0.05) - 0.05
Run Code Online (Sandbox Code Playgroud)

或大约:

if L > 0.179 use #000000 else use #ffffff
Run Code Online (Sandbox Code Playgroud)

唯一剩下的就是计算L.该公式也在指南中给出,它看起来像是从sRGB到线性RGB的转换,接着是ITU-R推荐的BT.709亮度.

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

由于它与W3C指南相关,因此不应更改0.179的阈值.如果您发现结果不符合您的喜好,请尝试上面更简单的公式.

  • 一个[快速示例](http://codepen.io/znak/pen/aOvMOd)使用上面的公式. (32认同)
  • 比我的方式更好的答案 (8认同)
  • [这是另一个演示](http://jsfiddle.net/cu4z27m7/66/)比较这个答案中给出的两个公式.使用颜色选择器(在最近的Firefox或Chrome中),您可以检查任何颜色的对比度. (3认同)
  • 对我来说 150 而不是 186 在背景颜色和文本颜色之间形成了很好的对比 (3认同)
  • Tks Mark.尝试了一些改变:仅用第一个数字计算红绿色和蓝色(不太精确,但是重量更多的数字)而不是186使用9.对我来说效果更好,特别是绿色. (2认同)
  • 这个公式错了很多.举一个例子,它给黄色的"#D6B508"值171,因此是白色对比度.对比度应为黑色(但在此确认:http://webaim.org/resources/contrastchecker/) (2认同)
  • @chetstone 不运行。 (2认同)
  • 在使用@ chetstone的演示了一下之后,我认为Simple公式最适合我,除了我不同意阈值建议.基于纯绿色的结果,我尝试将阈值设置为149,并且在我看来效果更好.[我做了一个非常愚蠢的小提示来证明这一点](https://jsfiddle.net/q781qx52/); 您可以尝试更改顶部的阈值以查看原始建议. (2认同)
  • 对于绿色(或“石灰”)#00FF00,建议的公式非常失败。正如 Miral 所建议的,这可以通过将阈值降低到 149 (0.587 * 0xFF = 149.685) 来解决。 (2认同)

Sud*_*Plz 23

我不赞成这个代码,因为它不是我的代码,但是我将它留在这里供其他人在将来快速找到:

基于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;
}
Run Code Online (Sandbox Code Playgroud)

这是高级版的代码片段:

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;
}
Run Code Online (Sandbox Code Playgroud)

要使用它们,只需致电:

var color = '#EEACAE' // this can be any color
pickTextColorBasedOnBgColorSimple(color, '#FFFFFF', '#000000');
Run Code Online (Sandbox Code Playgroud)

另外,感谢Alxchetstone.

  • 请注意,Mark 的 L&gt;0.179 计算假设我们选择白色和黑色作为文本颜色。其他颜色选择需要重新计算此阈值,因此传递任意颜色作为“lightColor”和“darkColor”不太有意义。 (3认同)
  • 我使用了简单的函数,并进一步精简了它:删除了最后 2 个参数并重命名为 `isDark(bgColor)` 我的用法就是 `'color': isDark(color)?'white':'black '` (2认同)

Geo*_*gan 17

这个怎么样(JavaScript代码)?

/**
 * Get color (black/white) depending on bgColor so it would be clearly seen.
 * @param bgColor
 * @returns {string}
 */
getColorByBgColor(bgColor) {
    if (!bgColor) { return ''; }
    return (parseInt(bgColor.replace('#', ''), 16) > 0xffffff / 2) ? '#000' : '#fff';
}
Run Code Online (Sandbox Code Playgroud)

  • 这在大多数情况下都有效,但有些情况像 http://i.imgur.com/3pOUDe5.jpg 看起来很奇怪,背景颜色实际上是 rgb(6, 247, 241); (2认同)

God*_*obo 11

这是我自己的方法,我一直在使用,到目前为止还没有遇到问题

function hexToRgb(hex) {
    const hexCode = hex.charAt(0) === '#' 
                        ? hex.substr(1, 6)
                        : hex;

    const hexR = parseInt(hexCode.substr(0, 2), 16);
    const hexG = parseInt(hexCode.substr(2, 2), 16);
    const hexB = parseInt(hexCode.substr(4, 2), 16);
    // Gets the average value of the colors
    const contrastRatio = (hexR + hexG + hexB) / (255 * 3);

    return contrastRatio >= 0.5
        ? 'black'
        : 'white';
}
Run Code Online (Sandbox Code Playgroud)


mwi*_*rek 8

这是我在Android for Java中的解决方案:

// Put this method in whichever class you deem appropriate
// static or non-static, up to you.
public static int getContrastColor(int colorIntValue) {
    int red = Color.red(colorIntValue);
    int green = Color.green(colorIntValue);
    int blue = Color.blue(colorIntValue);
    double lum = (((0.299 * red) + ((0.587 * green) + (0.114 * blue))));
    return lum > 186 ? 0xFF000000 : 0xFFFFFFFF;
}

// Usage
// If Color is represented as HEX code:
String colorHex = "#484588";
int color = Color.parseColor(colorHex);

// Or if color is Integer:
int color = 0xFF484588;

// Get White (0xFFFFFFFF) or Black (0xFF000000)
int contrastColor = WhateverClass.getContrastColor(color);
Run Code Online (Sandbox Code Playgroud)

  • @mwieczorek 依赖用户生成内容或随机选择颜色的人会这样做。 (3认同)
  • 真的“完美”吗?尝试纯绿色背景,#00FF00。 (2认同)

Fél*_*ard 8

除了算术解决方案外,还可以使用AI神经网络。优点是您可以根据自己的喜好和需要对其进行定制(即,明亮的饱和红色上的灰白色文本看起来不错,并且与黑色一样可读)。

这是一个说明概念的简洁Javascript演示。您还可以在演示中直接生成自己的JS公式。

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

以下是一些图表,可帮助我弄清问题所在。在第一个图表中,亮度是常数128,而色相和饱和度却在变化。在第二张图表中,饱和度为常数255,而色相和明度变化。

在第一个图表中,亮度是常数128,而色相和饱和度却有所不同:

饱和度是常数255,而色相和明度会变化:

  • 这是直观显示选项的绝佳方式 (3认同)

SoB*_*BiT 6

根据 @MarkRansom 的回答,我创建了一个 PHP 脚本,您可以在这里找到:

function calcC($c) {
    if ($c <= 0.03928) {
        return $c / 12.92;
    }
    else {
        return pow(($c + 0.055) / 1.055, 2.4);
    }
}

function cutHex($h) {
    return ($h[0] == "#") ? substr($h, 1, 7) : $h;
}

function hexToR($h) {
    return hexdec(substr(cutHex($h), 0, 2));
}

function hexToG($h) {
    return hexdec(substr(cutHex($h), 2, 2)); // Edited
}

function hexToB($h) {
    return hexdec(substr(cutHex($h), 4, 2)); // Edited
}

function computeTextColor($color) {
    $r = hexToR($color);
    $g = hexToG($color);
    $b = hexToB($color);
    $uicolors = [$r / 255, $g / 255, $b / 255];


    $c = array_map("calcC", $uicolors);

    $l = 0.2126 * $c[0] + 0.7152 * $c[1] + 0.0722 * $c[2];
    return ($l > 0.179) ? '#000000' : '#ffffff';
}
Run Code Online (Sandbox Code Playgroud)


Ger*_*ain 6

如果像我一样您正在寻找考虑 alpha 的 RGBA 版本,那么这里有一个非常适合具有高对比度的版本。

function getContrastColor(R, G, B, A) {
  const brightness = R * 0.299 + G * 0.587 + B * 0.114 + (1 - A) * 255;

  return brightness > 186 ? "#000000" : "#FFFFFF";
}
Run Code Online (Sandbox Code Playgroud)


Ryd*_*ell 5

这是 Mark Ransom 的答案的快速版本,作为 UIColor 的扩展

extension UIColor {

// Get the rgba components in CGFloat
var rgba: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
    var red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0, alpha: CGFloat = 0

    getRed(&red, green: &green, blue: &blue, alpha: &alpha)

    return (red, green, blue, alpha)
}

/// Return the better contrasting color, white or black
func contrastColor() -> UIColor {
    let rgbArray = [rgba.red, rgba.green, rgba.blue]

    let luminanceArray = rgbArray.map({ value -> (CGFloat) in
        if value < 0.03928 {
            return (value / 12.92)
        } else {
            return (pow( (value + 0.55) / 1.055, 2.4) )
        }
    })

    let luminance = 0.2126 * luminanceArray[0] +
        0.7152 * luminanceArray[1] +
        0.0722 * luminanceArray[2]

    return luminance > 0.179 ? UIColor.black : UIColor.white
} }
Run Code Online (Sandbox Code Playgroud)