如何根据当前颜色生成相反的颜色?

我试图创建一个颜色相反的目前的颜色。我的意思是,如果当前的颜色是 黑色,那么我需要生成 白色

其实我有一个文本 (这个文本的颜色是动态的,它的颜色可以随机制作)。该文本是一个 div和我需要设置的 divbackground-color的文本相反的颜色。我希望文字是 div (色彩透视)中的 安全

相反的颜色 表示: 深色/亮色

我有当前文本的颜色,我可以把它传递给这个函数:

var TextColor = #F0F0F0;    // for example (it is a bright color)


function create_opp_color(current color) {


// create opposite color according to current color


}


create_opp_color(TextColor); // this should be something like "#202020" (or a dark color)

有没有创建 create_opp_color()函数的想法?

95626 次浏览

小心无障碍网页(AA/AAA)。色彩对比本身是没有用的。对于色盲的人来说,真正不同的颜色根本没有对比度。 IMHO a calculation for such a color could go like this:

(为简单起见,请使用“ HLS”)

  • 旋转色相180o 以获得(可能无用的)最大的颜色对比度
  • 计算亮度差。
  • (计算颜色差... 不必要,它是最大值或几乎)
  • 计算对比度。
  • 如果生成的颜色符合要求,计算结束,如果不符合,循环:
    • 如果亮度差不够增加或 将计算出的颜色亮度(L)减少一定数量或比率(上升或下降) 下降取决于原来的颜色亮度: > 或 < 比中间 价值)
    • 检查它是否符合您的要求,是否计算结束。
    • 如果光度可以增加(或减少) ,没有有效的颜色符合要求,只是尝试黑色和白色,采取“最好的”的那些(可能是一个更大的对比度)和结束。

根据我对你问题的理解,你所说的反色是指反色。

InvertedColorComponent = 0xFF - ColorComponent

因此,对于红色(# FF0000) ,这意味着: R = 0xFF 或255 G = 0x00或0 B = 0x00或0

inverted color red (#00FFFF) is:

R = 0xFF - 0xFF = 0x00 or 255 - 255 = 0
G = 0xFF - 0x00 = 0xFF or 255 - 0 = 255
B = 0xFF - 0x00 = 0xFF or 255 - 0 = 255

另一个例子:

黑色(# 000000)变成白色(# FFFFFF)。

Orange (#FFA500) becomes #005AFF

更新 : GitHub上的生产准备 < strong > 代码。


我是这么做的:

  1. Convert HEX to RGB
  2. 反转 R,G 和 B 的成分
  3. 将每个组件转换回 HEX
  4. Pad each component with zeros and output.
function invertColor(hex) {
if (hex.indexOf('#') === 0) {
hex = hex.slice(1);
}
// convert 3-digit hex to 6-digits.
if (hex.length === 3) {
hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
}
if (hex.length !== 6) {
throw new Error('Invalid HEX color.');
}
// invert color components
var r = (255 - parseInt(hex.slice(0, 2), 16)).toString(16),
g = (255 - parseInt(hex.slice(2, 4), 16)).toString(16),
b = (255 - parseInt(hex.slice(4, 6), 16)).toString(16);
// pad each with zeros and return
return '#' + padZero(r) + padZero(g) + padZero(b);
}


function padZero(str, len) {
len = len || 2;
var zeros = new Array(len).join('0');
return (zeros + str).slice(-len);
}

示例输出:

enter image description here

高级版:

这有一个 bw选项,将决定是否转换为黑色或白色,所以你会得到更多的对比度,这通常是更好的人眼。

function invertColor(hex, bw) {
if (hex.indexOf('#') === 0) {
hex = hex.slice(1);
}
// convert 3-digit hex to 6-digits.
if (hex.length === 3) {
hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
}
if (hex.length !== 6) {
throw new Error('Invalid HEX color.');
}
var r = parseInt(hex.slice(0, 2), 16),
g = parseInt(hex.slice(2, 4), 16),
b = parseInt(hex.slice(4, 6), 16);
if (bw) {
// https://stackoverflow.com/a/3943023/112731
return (r * 0.299 + g * 0.587 + b * 0.114) > 186
? '#000000'
: '#FFFFFF';
}
// invert color components
r = (255 - r).toString(16);
g = (255 - g).toString(16);
b = (255 - b).toString(16);
// pad each with zeros and return
return "#" + padZero(r) + padZero(g) + padZero(b);
}

示例输出:

enter image description here

简单地将背景颜色转换为文本颜色不适用于某些中等范围的值,例如 0x808080。我已经尝试改变颜色值代替-(v + 0x80) % 0x100。请参见演示 给你

Agreeing with the comment from miguel-svq - although expecting to see more detailed algorithms for each calculation step.

通过 CSS 实现这一点的简单方法:

mix-blend-mode: difference;
color:white;

函数来反转元素的颜色。获取每个元素的亮度,如果它们关闭,则反转文本颜色。

function adjustColor(element) {
var style = window.getComputedStyle(element);
var background = new Color(style['background-color']);
var text = new Color(style['color']);
if (Math.abs(background.luma - text.luma) < 100) {
element.style.color = text.inverted.toString();
}
}

下面的“类”颜色。接受十六进制、 rgb、 rgba (甚至带有百分比) ,也可以输出到其中任何一个。资源管理器将需要用于 开始字符串的多重填充,而 toString ()方法中插入的字符串将需要使用 concat 进行修改。

const Color = (function () {
function toHex(num, padding) { return num.toString(16).padStart(padding || 2); }
function parsePart(value) {
var perc = value.lastIndexOf('%');
return perc < 0 ? value : value.substr(0, perc);
}
function Color(data) {
if (arguments.length > 1) {
this[0] = arguments[0];
this[1] = arguments[1];
this[2] = arguments[2];
if (arguments.length > 3) { this[3] = arguments[3]; }
} else if (data instanceof Color || Array.isArray(data)) {
this[0] = data[0];
this[1] = data[1];
this[2] = data[2];
this[3] = data[3];
} else if (typeof data === 'string') {
data = data.trim();
if (data[0] === "#") {
switch (data.length) {
case 4:
this[0] = parseInt(data[1], 16); this[0] = (this[0] << 4) | this[0];
this[1] = parseInt(data[2], 16); this[1] = (this[1] << 4) | this[1];
this[2] = parseInt(data[3], 16); this[2] = (this[2] << 4) | this[2];
break;
case 9:
this[3] = parseInt(data.substr(7, 2), 16);
//Fall Through
case 7:
this[0] = parseInt(data.substr(1, 2), 16);
this[1] = parseInt(data.substr(3, 2), 16);
this[2] = parseInt(data.substr(5, 2), 16);
break;
}
} else if (data.startsWith("rgb")) {
var parts = data.substr(data[3] === "a" ? 5 : 4, data.length - (data[3] === "a" ? 6 : 5)).split(',');
this.r = parsePart(parts[0]);
this.g = parsePart(parts[1]);
this.b = parsePart(parts[2]);
if (parts.length > 3) { this.a = parsePart(parts[3]); }
}
}
}
Color.prototype = {
constructor: Color,
0: 255,
1: 255,
2: 255,
3: 255,
get r() { return this[0]; },
set r(value) { this[0] = value == null ? 0 : Math.max(Math.min(parseInt(value), 255), 0); },
get g() { return this[1]; },
set g(value) { this[1] = value == null ? 0 : Math.max(Math.min(parseInt(value), 255), 0); },
get b() { return this[2]; },
set b(value) { this[2] = value == null ? 0 : Math.max(Math.min(parseInt(value), 255), 0); },
get a() { return this[3] / 255; },
set a(value) { this[3] = value == null ? 255 : Math.max(Math.min(value > 1 ? value : parseFloat(value) * 255, 255), 0); },
get luma() { return .299 * this.r + .587 * this.g + .114 * this.b; },
get inverted() { return new Color(255 - this[0], 255 - this[1], 255 - this[2], this[3]); },
toString: function (option) {
if (option === 16) {
return '#' + toHex(this.r) + toHex(this.g) + toHex(this.b) + (this[3] === 255 ? '' : toHex(this[3]));
} else if (option === '%') {
if (this.a !== 1) {
return `rgba(${this.r / 255 * 100}%, ${this.b / 255 * 100}%, ${this.g / 255 * 100}%, ${this.a / 255})`;
} else {
return `rgb(${this.r / 255 * 100}%, ${this.b / 255 * 100}%, ${this.g / 255 * 100})%`;
}
} else {
if (this.a !== 1) {
return `rgba(${this.r}, ${this.b}, ${this.g}, ${this.a})`;
} else {
return `rgb(${this.r}, ${this.b}, ${this.g})`;
}
}
}
};


return Color;
}());

Simple and elegant.

function invertHex(hex) {
return (Number(`0x1${hex}`) ^ 0xFFFFFF).toString(16).substr(1).toUpperCase()
}


invertHex('00FF00'); // Returns FF00FF

这是一个简单的反转十六进制颜色的函数

const invertColor = (col) => {
col = col.toLowerCase();
const colors = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f']
let inverseColor = '#'
col.replace('#','').split('').forEach(i => {
const index = colors.indexOf(i)
inverseColor += colors.reverse()[index]
})
return inverseColor
}


代码化的例子

For Typescript lovers, here what I use:

invertHex(hex: string) {
if (hex.indexOf('#') === 0) {
hex = hex.slice(1);
}


if (hex.length != 6) {
console.warn('Hex color must be six hex numbers in length.');
return '#' + hex;
}


hex = hex.toUpperCase();
const splitNum = hex.split('');
let resultNum = '';
const simpleNum = 'FEDCBA9876'.split('');
const complexNum = {
A: '5', B: '4', C: '3', D: '2', E: '1', F: '0'
};


for (let i = 0; i < 6; i++) {
if (!isNaN(Number(splitNum[i]))) {
resultNum += simpleNum[splitNum[i]];
} else if (complexNum[splitNum[i]]) {
resultNum += complexNum[splitNum[i]];
} else {
console.warn('Hex colors must only include hex numbers 0-9, and A-F');
return '#' + hex;
}
}


return '#' + resultNum;
}

@ Onur 的 回答 bw 部分的纯 CSS 实现。

  <input type="color" oninput="['--r','--g','--b'].forEach((k,i)=>this.nextElementSibling.style.setProperty(k,parseInt(event.target.value.slice(1+i*2,3+i*2),16)))" />
 

<div style="--r: 0; --g: 0; --b: 0; --c: calc(-1 * ((var(--r) * 0.299 + var(--g) * 0.587 + var(--b) * 0.114) - 186) * 255)">
<div style="background-color: rgb(var(--r), var(--g), var(--b)); color: rgb(var(--c), var(--c), var(--c))">Test</div>
</div>

可以使用代码片段转换 巫术颜色

function invertColor(color) {
return '#' + ("000000" + (0xFFFFFF ^ parseInt(color.substring(1),16)).toString(16)).slice(-6);
}

Onur 回答的 Python 替代方案:

def hex_to_rgb(value):
value = value.lstrip('#')
lv = len(value)
return tuple(int(value[i:i + lv // 3], 16) for i in range(0, lv, lv // 3))


def invertColor(color, bw=False):
# strip the # from the beginning
color = color.lstrip('#')


# convert the string into hex
color = int(color, 16)


# invert the three bytes
# as good as substracting each of RGB component by 255(FF)
comp_color = 0xFFFFFF ^ color


# convert the color back to hex by prefixing a #
comp_color = "#%06X" % comp_color


rgb_color = hex_to_rgb(comp_color)
    

if (bw):
# http://stackoverflow.com/a/3943023/112731
bw_value = rgb_color[0]*0.299 + rgb_color[0]*0.587 + rgb_color[0]*0.114
if (bw_value>186):
comp_color = "#FFFFFF"
else:
comp_color = "#000000"


# return the result
return comp_color


color = "#fffff1"


print invertColor(color, bw=True)

怎么样,CSS filter: invert(1),它有一个体面的 跨浏览器兼容性和它的工作与文字和图像或任何你的内容。

对于黑色和白色倒置的颜色添加一些更多的滤镜 filter: saturate(0) grayscale(1) brightness(.7) contrast(1000%) invert(1)

const div = document.querySelector("div");
const b = document.querySelector("b");
const input = document.querySelector("input");


input.oninput = (e) => {
const color = e.target.value;
div.style.background = color;
b.style.color = color;
b.innerText = color;
}
body {
font-family: Arial;
background: #333;
}


div {
position: relative;
display: inline-flex;
justify-content: center;
align-items: center;
min-width: 100px;
padding: .5em 1em;
border: 2px solid #FFF;
border-radius: 15px;
background: #378ad3;
font-style: normal;
}


b {
/* Inverting the color */
/* ᐯᐯᐯᐯᐯᐯᐯᐯᐯᐯᐯᐯ */
filter: saturate(0) grayscale(1) brightness(.7) contrast(1000%) invert(1);
}


input {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
cursor: pointer;
}
<div>
<b>#378ad3</b>
<input type="color" value="#378ad3"/>
</div>