自动更改文本颜色以确保可读性

问题描述 投票:0回答:10

用户可以通过接受RGB十六进制表示法的文本框设置按钮的背景颜色:

ff00ff
ccaa22
等。所以我需要将文本颜色设置为相反的颜色。不确定术语(相反颜色),但想法是确保可读性。

javascript text colors background
10个回答
52
投票

您可以反转背景颜色并将其用作前景色。以下算法产生的结果与 Photoshop 中的“图像 > 调整 > 反转”颜色命令相同:

function invertColor(hexTripletColor) {
    var color = hexTripletColor;
    color = color.substring(1);           // remove #
    color = parseInt(color, 16);          // convert to integer
    color = 0xFFFFFF ^ color;             // invert three bytes
    color = color.toString(16);           // convert to hex
    color = ("000000" + color).slice(-6); // pad with leading zeros
    color = "#" + color;                  // prepend #
    return color;
}
/*
 * Demonstration
 */
function randomColor() {
    var color;
    color = Math.floor(Math.random() * 0x1000000); // integer between 0x0 and 0xFFFFFF
    color = color.toString(16);                    // convert to hex
    color = ("000000" + color).slice(-6);          // pad with leading zeros
    color = "#" + color;                           // prepend #
    return color;
}
$(function() {
    $(".demolist li").each(function() {
        var c1 = randomColor();
        var c2 = invertColor(c1);
        $(this).text(c1 + " " + c2).css({
            "color": c1,
            "background-color": c2
        });
    });
});
body { font: bold medium monospace; }
.demolist { margin: 0; padding: 0; list-style-type: none; overflow: hidden; }
.demolist li { float: left; width: 5em; height: 5em; text-align: center; }
<ul class="demolist">
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
</ul>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

请注意,这不是万无一失的解决方案。接近 50% 亮度和/或饱和度的颜色将无法产生足够的对比度。

jsFiddle 上的演示


13
投票

Salaman 的代码很好,但有时他的反演可读性不够。 我使用YCbCr,只是改变灰度。

function invertColor(rgb) {
    var yuv = rgb2yuv(rgb);
    var factor = 180;
    var threshold = 100;
    yuv.y = clamp(yuv.y + (yuv.y > threshold ? -factor : factor));
    return yuv2rgb(yuv);
}

jsfiddle 演示


5
投票

我在评论中将另一个问题链接到该主题。
JS函数计算补色?

正如Tejasva所说,你需要将RGB转换为HSL,补充色调并将其转换回来。

我将链接的答案作为示例实现。如果这对您有帮助,请为原贴点赞,因为他们实际上提供了解决方案。

样品
http://jsfiddle.net/pLZ89/2/


5
投票

我曾经遇到过同样的问题,并使用 Salman A 答案在互联网上收集了信息,我想出了这个功能,它支持十六进制,rgb 和 rgba

var invertColor = function (color) {
            var hex   = '#';
            if(color.indexOf(hex) > -1){
                color = color.substring(1);           
                color = parseInt(color, 16);         
                color = 0xFFFFFF ^ color;            
                color = color.toString(16);           
                color = ("000000" + color).slice(-6); 
                color = "#" + color; 
            }else{
                color = Array.prototype.join.call(arguments).match(/(-?[0-9\.]+)/g);
                for (var i = 0; i < color.length; i++) {
                    color[i] = (i === 3 ? 1 : 255) - color[i];
                }
                if(color.length === 4){
                    color = "rgba("+color[0]+","+color[1]+","+color[2]+","+color[3]+")";
                }else{
                    color = "rgb("+color[0]+","+color[1]+","+color[2]+")";
                }
            }         
            return color;
        }

但我不认为这就是你所需要的,我发现了一些更有趣的东西,下面的函数将返回白色或黑色,它将决定女巫在给定颜色上更具可读性。

var getContrastYIQ = function (color){
            var hex   = '#';
            var r,g,b;
            if(color.indexOf(hex) > -1){
                r = parseInt(color.substr(0,2),16);
                g = parseInt(color.substr(2,2),16);
                b = parseInt(color.substr(4,2),16);
            }else{
                color = color.match(/\d+/g);
                r = color[0];
                g = color[1];
                b = color[2];
            }

            var yiq = ((r*299)+(g*587)+(b*114))/1000;
            return (yiq >= 128) ? 'black' : 'white';
        }

我不会将这一切归功于自己,我只是受到启发并根据自己的需求进行了修改。

来源:YIQ 函数解释


2
投票

聚会有点晚了,但我认为所有文字都应该是浅色或深色的。彩色文本用于链接。

这是我编写的一个咖啡脚本函数,用于决定使用哪个:

is_light = (hex_color) ->
  c = hex_color.replace(/^#/,'')
  sum = parseInt(c[0]+c[1], 16)
  sum += parseInt(c[2]+c[3], 16)
  sum += parseInt(c[4]+c[5], 16)  
  log "sum is #{sum}"
  sum > 382.6

2
投票

var getContrastYIQ = function(color) {
  var hex = '#';
  var r, g, b;
  if (color.indexOf(hex) > -1) {
    r = parseInt(color.substr(1, 2), 16);
    g = parseInt(color.substr(3, 2), 16);
    b = parseInt(color.substr(5, 2), 16);
  } else {
    color = color.match(/\d+/g);
    r = color[0];
    g = color[1];
    b = color[2];
  }

  var yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000;
  return (yiq >= 128) ? 'black' : 'white';
}

感谢 ZetCoby 的帖子!必须调整你的“color.substr(”数组位置来解释最初的“#”;然后它工作得很好!你也可以在 if 块中使用 color.replace('#',''); ...


1
投票

您可以使用这个简单的模式来实现该目标。只需将颜色从 RGB 形式转换为 HSV 形式即可。您可以使用这个link。 然后使用这个伪代码;

rr = (color>>16)&0xFF;
gg = (color>>8)&0xFF;
bb = color & 0xFF;

someBrightColor = 0xFFFFFF;
someDarkColor = 0x000000;

hsvColor = rgbToHsv( rr, gg, bb );
//
//hsv is array: [h,s,v]...all values in [0,1]
//
//color is from dark range, if hsv < 0.5, so we need bright color to draw text, because    in dark color bright color 'will be more visible'.  
if( hsvColor[2] <= 0.5 )
  textColor = someBrightColor ;
//this is opposite case , when in more bright color, the dark color 'will be more visible'
else
  textColor = someDarkColor ;

您还可以将 [0,1] 范围划分为更多部分。并且不要定义 2 种颜色 (someBrightColor,someDarkColor) ,而是定义更多颜色。我建议的方法是“背景颜色有多亮,文本颜色就必须有多暗,反之亦然”。


1
投票

这里有一个非常小的方法来补十六进制值 //十六进制值,如“aa00cc”

function complementHex(hexValue){
    var reqHex = "";
    for(var i=0;i<6;i++){
        reqHex = reqHex + (15-parseInt(hexValue[i],16)).toString(16);
    }
    return reqHex;
}

0
投票

var getContrastYIQ = function(color) {
  var hex = '#';
  var r, g, b;
  if (color.indexOf(hex) > -1) {
    r = parseInt(color.substr(1, 2), 16);
    g = parseInt(color.substr(3, 2), 16);
    b = parseInt(color.substr(5, 2), 16);
  } else {
    color = color.match(/\d+/g);
    r = color[0];
    g = color[1];
    b = color[2];
  }

  var yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000;
  return (yiq >= 128) ? 'black' : 'white';
}

var getContrastYIQ = function(color) {
  var hex = '#';
  var r, g, b;
  if (color.indexOf(hex) > -1) {
    r = parseInt(color.substr(1, 2), 16);
    g = parseInt(color.substr(3, 2), 16);
    b = parseInt(color.substr(5, 2), 16);
  } else {
    color = color.match(/\d+/g);
    r = color[0];
    g = color[1];
    b = color[2];
  }

  var yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000;
  return (yiq >= 128) ? 'black' : 'white';
}


0
投票

您希望在开始颜色和结束颜色之间至少保留一些差异。对于中心的 rgb 值来说,这成为一个问题,如果您采用相反的颜色,因此对于这些值来说,采用相反的值是一个坏主意,因为对比度会下降,越接近中间(127- 128)。因此,这里有一些代码牢记这一点,以便始终保持起始数字和结果之间至少有一个设定的差异,如果不能遵守设定的最小亮度差异,则将采用 0 或 255,对于r g b 值有问题...

假设我们有带有值的颜色

{ r: 216, g: 67, b: 130 }

下面的函数将返回

{ r: 39, g: 195, b: 2 }
作为结果。

如果黑白模式设置为 true,则仅返回黑色或白色。

堆栈闪电战

function getGoodContrastColor(options) {
  // check if black or white mode is enabled then check if total brightness values is greater than 255 * 3 / 2, if so, take black, else take white
  let r = options.blackOrWhiteMode == true ? options.r + options.g + options.b > 255 * 3 / 2 ? 0 : 255 : null;
  let g = options.blackOrWhiteMode == true ? options.r + options.g + options.b > 255 * 3 / 2 ? 0 : 255 : null;
  let b = options.blackOrWhiteMode == true ? options.r + options.g + options.b > 255 * 3 / 2 ? 0 : 255 : null;
  
  console.log('rgb values after the first condition', { r, g, b });

  // check if the oposite color respects the minimum brightness difference, if so, take that
  r = r != null ? r : Math.abs(options.r - (255 - options.r)) >= options.minimumBrightnessDifference ? 255 - options.r : null;
  g = g != null ? g : Math.abs(options.g - (255 - options.g)) >= options.minimumBrightnessDifference ? 255 - options.g : null;
  b = b != null ? b : Math.abs(options.b - (255 - options.b)) >= options.minimumBrightnessDifference ? 255 - options.b : null;

  console.log('rgb values after the second condition', { r, g, b });

  // check if the color + minimum brightness difference is smaller or equal to 255, if so, take that
  r = r != null ? r : options.r + options.minimumBrightnessDifference <= 255 ? options.r + options.minimumBrightnessDifference : null;
  g = g != null ? g : options.g + options.minimumBrightnessDifference <= 255 ? options.g + options.minimumBrightnessDifference : null;
  b = b != null ? b : options.b + options.minimumBrightnessDifference <= 255 ? options.b + options.minimumBrightnessDifference : null;

  console.log('rgb values after the third condition', { r, g, b });

  // check if the color - minimum brightness difference is greater or equal to 0, if so, take that
  r = r != null ? r : options.r - options.minimumBrightnessDifference >= 0 ? options.r - options.minimumBrightnessDifference : null;
  g = g != null ? g : options.g - options.minimumBrightnessDifference >= 0 ? options.g - options.minimumBrightnessDifference : null;
  b = b != null ? b : options.b - options.minimumBrightnessDifference >= 0 ? options.b - options.minimumBrightnessDifference : null;

  console.log('rgb values after the fourth condition', { r, g, b });
  
  // check if the color is greater than 127, if so, take 0, else take 255
  r = r != null ? r : options.r > 127 ? 0 : 255;
  g = g != null ? g : options.g > 127 ? 0 : 255;
  b = b != null ? b : options.b > 127 ? 0 : 255;

  console.log('rgb values after the fifth condition', { r, g, b });
  
  return { r: r, g: g, b: b };
}

getGoodContrastColor({ r: 216, g: 67, b: 130, minimumBrightnessDifference: 128 });
getGoodContrastColor({ r: 216, g: 67, b: 130, minimumBrightnessDifference: 128, blackOrWhiteMode: true });

© www.soinside.com 2019 - 2024. All rights reserved.