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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35969656/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 18:27:59  来源:igfitidea点击:

How can I generate the opposite color according to current color?

javascriptjqueryhtmlcsscolors

提问by stack

I'm trying to create a color opposite of current color. I mean if current color is black, then I need to generate white.

我正在尝试创建与当前颜色相反的颜色。我的意思是如果当前颜色是黑色,那么我需要生成白色

Actually I have a text (the color of this text is dynamic, its color can be made at random). That text is into a divand I need to set the opposite color of that text for the background-colorof div. I would like that text be clearin the div(color perspective).

其实我有一个文本(这个文本的颜色是动态的,它的颜色可以随意制作)。这是文成div,我需要设置文本的相反颜色background-colordiv。我希望该文本在(颜色透视)中清晰div

The opposite colormeans: Dark / Bright

相反的颜色表示:暗/亮

I have the current color of text and I can pass it to this function:

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

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)

Is there any idea to create create_opp_color()function?

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

回答by Onur Y?ld?r?m

UPDATE: Production-ready code on GitHub.

更新GitHub 上的生产就绪代码。



This is how I'd do it:

这就是我要做的:

  1. Convert HEX to RGB
  2. Invert the R,G and B components
  3. Convert each component back to HEX
  4. Pad each component with zeros and output.
  1. 将十六进制转换为 RGB
  2. 反转 R、G 和 B 分量
  3. 将每个组件转换回 HEX
  4. 用零和输出填充每个组件。
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);
}

Example Output:

示例输出:

enter image description here

在此处输入图片说明

Advanced Version:

进阶版:

This has a bwoption that will decide whether to invert to black or white; so you'll get more contrast which is generally better for the human eye.

这有一个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) {
        // http://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);
}

Example Output:

示例输出:

enter image description here

在此处输入图片说明

回答by Gerardlamo

Simple and elegant.

简单而优雅。

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

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

回答by raphadko

Simple way to achieve this with CSS:

使用 CSS 实现此目的的简单方法:

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

回答by Jamesgt

Pure CSS implementation of @Onur's answerbw part.

@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>

回答by miguel-svq

Watch out Accesibility (AA/AAA). Colour contrast by itself is useless. Really different colors can have no contrast at all for colour blind people. IMHO a calculation for such a color could go like this:

注意可访问性 (AA/AAA)。颜色对比本身是无用的。对于色盲的人来说,真正不同的颜色根本没有对比。恕我直言,这种颜色的计算可能是这样的:

(Use "HLS" for simplicity)

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

  • Rotate Hue 180o to get the (maybe useless) maximal color contrast
  • Calculate Brightness Difference.
  • ( Calculate Colour Difference... unnecesary, it's maximal or almost )
  • Calculate Contrast Ratio.
  • If the resulting color complies the requirements calculation ends, if not, loop:
    • If Brightness Difference is not enought increase or decrese calculated color luminosity (L) by a certain amount or ratio (up or down depending on the original colour brightness: > or < than the mid value)
    • Check if it complies your requirements, if it does calculation ends.
    • if luminosity can be increased (or decrased) any more there is no valid color to comply the requirements, just try black and white, take "the best one" of those (probably the one with bigger contrast ratio) and end.
  • 将 Hue 旋转 180o 以获得(也许没用)最大的色彩对比度
  • 计算亮度差异。
  • (计算色差......不必要,它是最大或几乎)
  • 计算对比度。
  • 如果生成的颜色符合要求,计算结束,如果不符合,则循环:
    • 如果亮度差不够,则将计算出的颜色亮度 (L) 增加或减少一定数量或比例(根据原始颜色亮度增加或减少:> 或 < 比中间值)
    • 检查它是否符合您的要求,如果计算结束。
    • 如果亮度可以再增加(或降低),则没有符合要求的有效颜色,只需尝试黑色和白色,选择其中“最好的一个”(可能是对比度较大的那个)并结束。

回答by DigiLive

In my understanding of your question, by opposite color you mean inverted color.

根据我对你的问题的理解,相反的颜色是指反转的颜色。

InvertedColorComponent = 0xFF - ColorComponent

So for the color red (#FF0000) this means: R = 0xFF or 255 G = 0x00 or 0 B = 0x00 or 0

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

inverted color red (#00FFFF) is:

反色红色(#00FFFF)是:

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

Another examples:

另一个例子:

Black (#000000) becomes White (#FFFFFF).

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

Orange (#FFA500) becomes #005AFF

橙色 (#FFA500) 变成 #005AFF

回答by jason_zhuyx

Simply flipping background color to text color won't work with some middle range values, e.g. 0x808080. I had tried with shifting the color values instead - (v + 0x80) % 0x100. See a demo here.

简单地将背景颜色翻转为文本颜色不适用于某些中间范围值,例如0x808080. 我曾尝试改变颜色值 - (v + 0x80) % 0x100在此处查看演示。

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

同意miguel-svq的评论- 尽管希望看到每个计算步骤的更详细算法。

回答by Supah

This is a simple function that invert an hexadecimal color

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

const invertColor = (col) => {
  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
}

Codepen example

代码笔示例

回答by Derek Ziemba

Function to Invert Color of Element. Gets the luminosity of each and if they are close, inverts text color.

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

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();
    }
}

The Color "Class" below. Accepts hex, rgb, rgba (even with percents), and can output to either one as well. Explorer will need polyfills for String.padStartand String.startsWithand the interpolated string in the toString() method will need to be modified using concat instead.

下面的颜色“类”。接受十六进制、rgb、rgba(甚至带有百分比),并且也可以输出到任何一个。Explorer 将需要String.padStartString.startsWith 的polyfills,并且需要使用 concat 修改 toString() 方法中的内插字符串。

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;
}());

回答by abd0991

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;
}