我想展示一些像这个例子的图片
填充颜色由数据库中颜色为十六进制的字段决定(例如:ClassX -> color: #66FFFF)。 现在,我想显示上面的数据与所选的颜色填充(如上图),但我需要知道如果颜色是暗或光,所以我知道如果文字应该在白色或黑色。 有办法吗?谢谢大家
我想展示一些像这个例子的图片
填充颜色由数据库中颜色为十六进制的字段决定(例如:ClassX -> color: #66FFFF)。 现在,我想显示上面的数据与所选的颜色填充(如上图),但我需要知道如果颜色是暗或光,所以我知道如果文字应该在白色或黑色。 有办法吗?谢谢大家
我从来没有做过这样的事情,但是写一个函数来检查每个颜色的值与十六进制7F (FF / 2)的中位数颜色。如果三种颜色中有两种大于7F,那么你正在使用较深的颜色。
以我对类似问题的回答为基础。
您需要将十六进制代码分解为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指南相关联。如果你发现结果不是你喜欢的,试试上面更简单的公式。
这只是一个示例,它将在单击元素时更改SVG复选标记的颜色。它将根据所单击元素的背景色将复选标记颜色设置为黑色或白色。
checkmarkColor: function(el) {
var self = el;
var contrast = function checkContrast(rgb) {
// @TODO check for HEX value
// Get RGB value between parenthesis, and remove any whitespace
rgb = rgb.split(/\(([^)]+)\)/)[1].replace(/ /g, '');
// map RGB values to variables
var r = parseInt(rgb.split(',')[0], 10),
g = parseInt(rgb.split(',')[1], 10),
b = parseInt(rgb.split(',')[2], 10),
a;
// if RGBA, map alpha to variable (not currently in use)
if (rgb.split(',')[3] !== null) {
a = parseInt(rgb.split(',')[3], 10);
}
// calculate contrast of color (standard grayscale algorithmic formula)
var contrast = (Math.round(r * 299) + Math.round(g * 587) + Math.round(b * 114)) / 1000;
return (contrast >= 128) ? 'black' : 'white';
};
$('#steps .step.color .color-item .icon-ui-checkmark-shadow svg').css({
'fill': contrast($(self).css('background-color'))
});
}
onClickExtColor: function(evt) {
var self = this;
self.checkmarkColor(evt.currentTarget);
}
https://gist.github.com/dcondrey/183971f17808e9277572
这个(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';
}
以下是我用Java编写的Android解决方案:
// 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);
我使用这个JavaScript函数将rgb/rgba转换为“白色”或“黑色”。
function getTextColor(rgba) {
rgba = rgba.match(/\d+/g);
if ((rgba[0] * 0.299) + (rgba[1] * 0.587) + (rgba[2] * 0.114) > 186) {
return 'black';
} else {
return 'white';
}
}
你可以输入这些格式中的任何一种它会输出"黑"或"白"
rgb (255,255,255) rgba (255,255,255,0.1) 色彩:rgba (255,255,255,0.1) 255,255,255,0.1
我不认为这段代码是我的功劳,因为它不是我的,但我把它留在这里,让其他人将来很快就能找到:
根据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。
根据@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';
}
@SoBiT,我在看你的答案,看起来不错,但有一个小错误。你的函数hexToG和hextoB需要一个小的编辑。substr中的最后一个数字是字符串的长度,所以在这种情况下,它应该是“2”,而不是4或6。
function hexToR($h) {
return hexdec(substr(cutHex($h), 0, 2));
}
function hexToG($h) {
return hexdec(substr(cutHex($h), 2, 2));
}
function hexToB($h) {
return hexdec(substr(cutHex($h), 4, 2));
}
LESS有一个很好的对比度()函数,对我来说效果很好,请参阅http://lesscss.org/functions/#color-operations-contrast
“在两种颜色中选择一种颜色与另一种颜色形成最大的对比。 这对于确保颜色在背景下是可读的很有用,这对于可访问性遵从也很有用。此函数的工作方式与Compass for SASS中的对比函数相同。根据WCAG 2.0,颜色是用伽马校正的亮度值来比较的,而不是它们的亮度。”
例子:
p {
a: contrast(#bbbbbb);
b: contrast(#222222, #101010);
c: contrast(#222222, #101010, #dddddd);
d: contrast(hsl(90, 100%, 50%), #000000, #ffffff, 30%);
e: contrast(hsl(90, 100%, 50%), #000000, #ffffff, 80%);
}
输出:
p {
a: #000000 // black
b: #ffffff // white
c: #dddddd
d: #000000 // black
e: #ffffff // white
}
除了算术解决方案,还可以使用人工智能神经网络。这样做的好处是,你可以根据自己的口味和需求来定制它。灰白色的文字在明亮的饱和红色上看起来很好,和黑色一样可读)。
下面是一个简洁的Javascript演示,演示了这个概念。你也可以在演示中生成自己的JS公式。
https://harthur.github.io/brain/
下面是一些帮助我解决这个问题的图表。 在第一个图表中,亮度是一个常数128,而色调和饱和度变化。在第二张图中,饱和度是恒定的255,而色调和亮度变化。
马克的详细回答非常有用。下面是一个javascript实现:
function lum(rgb) {
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';
}
然后可以调用这个函数lum([111, 22, 255])来获得白色或黑色。
从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回答的iOS Objective-c版本代码:
- (UIColor *)contrastForegroundColor {
CGFloat red = 0, green = 0, blue = 0, alpha = 0;
[self getRed:&red green:&green blue:&blue alpha:&alpha];
NSArray<NSNumber *> *rgbArray = @[@(red), @(green), @(blue)];
NSMutableArray<NSNumber *> *parsedRGBArray = [NSMutableArray arrayWithCapacity:rgbArray.count];
for (NSNumber *item in rgbArray) {
if (item.doubleValue <= 0.03928) {
[parsedRGBArray addObject:@(item.doubleValue / 12.92)];
} else {
double newValue = pow((item.doubleValue + 0.055) / 1.055, 2.4);
[parsedRGBArray addObject:@(newValue)];
}
}
double luminance = 0.2126 * parsedRGBArray[0].doubleValue + 0.7152 * parsedRGBArray[1].doubleValue + 0.0722 * parsedRGBArray[2].doubleValue;
return luminance > 0.179 ? UIColor.blackColor : UIColor.whiteColor;
}
这是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
} }
根据来自链接的不同输入,使前景颜色黑色或白色取决于背景和这个线程,我为颜色做了一个扩展类,为您提供所需的对比色。
代码如下:
public static class ColorExtension
{
public static int PerceivedBrightness(this Color c)
{
return (int)Math.Sqrt(
c.R * c.R * .299 +
c.G * c.G * .587 +
c.B * c.B * .114);
}
public static Color ContrastColor(this Color iColor, Color darkColor,Color lightColor)
{
// Counting the perceptive luminance (aka luma) - human eye favors green color...
double luma = (iColor.PerceivedBrightness() / 255);
// Return black for bright colors, white for dark colors
return luma > 0.5 ? darkColor : lightColor;
}
public static Color ContrastColor(this Color iColor) => iColor.ContrastColor(Color.Black);
public static Color ContrastColor(this Color iColor, Color darkColor) => iColor.ContrastColor(darkColor, Color.White);
// Converts a given Color to gray
public static Color ToGray(this Color input)
{
int g = (int)(input.R * .299) + (int)(input.G * .587) + (int)(input.B * .114);
return Color.FromArgb(input.A, g, g, g);
}
}
用所有24位的颜色测试怎么样?
请注意,YIQ方法将返回1.9:1的最小对比度,这不会通过AA和AAA WCAG2.0测试,假设阈值为128。
对于W3C方法,它将返回最小对比度4.58:1,通过AA和AAA测试的大文本,AA测试的小文本,它不会通过AAA测试的小文本的每一种颜色。
如果你像我一样正在寻找一个考虑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";
}
下面是我基于Mark的惊人回答编写的Java Swing代码:
public static Color getColorBasedOnBackground(Color background, Color darkColor, Color lightColor) {
// Calculate foreground color based on background (based on https://stackoverflow.com/a/3943023/)
Color color;
double[] cL = new double[3];
double[] colorRGB = new double[] {background.getRed(), background.getGreen(), background.getBlue()};
for (int i = 0; i < colorRGB.length; i++)
cL[i] = (colorRGB[i] / 255.0 <= 0.03928) ? colorRGB[i] / 255.0 / 12.92 :
Math.pow(((colorRGB[i] / 255.0 + 0.055) / 1.055), 2.4);
double L = 0.2126 * cL[0] + 0.7152 * cL[1] + 0.0722 * cL[2];
color = (L > Math.sqrt(1.05 * 0.05) - 0.05) ? darkColor : lightColor;
return color;
}
这是马克·兰森的答案的R版本,只使用R基。
hex_bw <- function(hex_code) {
myrgb <- as.integer(col2rgb(hex_code))
rgb_conv <- lapply(myrgb, function(x) {
i <- x / 255
if (i <= 0.03928) {
i <- i / 12.92
} else {
i <- ((i + 0.055) / 1.055) ^ 2.4
}
return(i)
})
rgb_calc <- (0.2126*rgb_conv[[1]]) + (0.7152*rgb_conv[[2]]) + (0.0722*rgb_conv[[3]])
if (rgb_calc > 0.179) return("#000000") else return("#ffffff")
}
> hex_bw("#8FBC8F")
[1] "#000000"
> hex_bw("#7fa5e3")
[1] "#000000"
> hex_bw("#0054de")
[1] "#ffffff"
> hex_bw("#2064d4")
[1] "#ffffff"
> hex_bw("#5387db")
[1] "#000000"
我正在使用tinyColor库,它也可以做这项工作。
import { TinyColor } from '@ctrl/tinycolor'
// ...
getColorContrast(color = '#66FFFF'): string {
if(new TinyColor(color).getLuminance() > 0.179) { // 0.179 -> Mark Ransom answer
return '#000'
} else {
return '#fff'
}
}
此方法也接受rgb颜色,如rgb(102,255,255)
我在@SudoPlz提出的高级函数的基础上做了一个函数,它也考虑了浅色和深色:
function getTextColor (bgColor, lightColor = '#FFFFFF', darkColor = '#000000') {
const getLuminance = function (hexColor) {
var color = (hexColor.charAt(0) === '#') ? hexColor.substring(1, 7) : hexColor
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 => col <= 0.03928 ? col / 12.92 : ((col + 0.055) / 1.055) ** 2.4)
return (0.2126 * c[0]) + (0.7152 * c[1]) + (0.0722 * c[2]);
}
var L = getLuminance(bgColor)
var L1 = getLuminance(lightColor)
var L2 = getLuminance(darkColor)
return (L > Math.sqrt((L1 + 0.05) * (L2 + 0.05)) - 0.05) ? darkColor : lightColor;
}
因此,如果深色文本不是黑色而是栗色,灰色背景上的推荐文本颜色会变成白色:
getTextColor('#808080')
"#000000"
getTextColor('#808080', '#FFFFFF', '#800000')
"#FFFFFF"
当使用androidx. composer .ui.graphics. color时,接受的答案在Android上从未工作过。然后我发现在Android Jetpack Compose中实际上有内置的luminance()函数,该函数返回[0,1]之间的亮度值。文档说明:“基于WCAG 2.0中定义的相对亮度公式,W3C推荐标准2008年12月11日。”
以下是官方源代码。
使用示例:
fun Color.generateOnColor()
: Color {
return if (luminance() > 0.5f) {
Color.Black.copy(alpha = .8f)
} else {
Color.White
}
}
以防有人关心Mark Ransom回答的SCSS版本:
@use 'sass:color' as *;
@use 'sass:math' as *;
@function col_r($color) {
@if $color <= 0.03928 {
@return $color / 12.92;
} @else {
@return pow((($color + 0.055) / 1.055), (2.4));
}
}
@function pickTextColorBasedOnBgColorAdvanced(
$bgColor,
$lightColor,
$darkColor
) {
$r: red($bgColor);
$g: green($bgColor);
$b: blue($bgColor);
$ui_r: $r / 255;
$ui_g: $g / 255;
$ui_b: $b / 255;
$ui_r_c: col_r($ui_r);
$ui_g_c: col_r($ui_g);
$ui_b_c: col_r($ui_b);
$L: (0.2126 * $ui_r_c) + (0.7152 * $ui_g_c) + (0.0722 * $ui_b_c);
@if ($L > 0.179) {
@return $darkColor;
} @else {
@return $lightColor;
}
}