【问题标题】:How can I generate the opposite color according to current color?如何根据当前颜色生成相反的颜色?
【发布时间】:2016-06-28 10:27:33
【问题描述】:

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

其实我有一个文字(这个文字的颜色是动态的,颜色可以随意制作)。该文本位于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()函数的想法?

【问题讨论】:

  • 暗/亮?所以对面的红色(#FF0000)是......黑色(#000000)?对于黑白,“轴”很容易,但如果想要获得“对比度”而不是“互补”颜色或类似的东西,处理颜色可能会很棘手。
  • @miguel-svq 好点.. 我的目标是使文本可读(颜色透视),所以如果文本的颜色是红色 ,那么背景的颜色几乎可以是任何黑色、白色、蓝色 ..
  • 那里有非常好的颜色处理模块。举个例子看看 tinycolor (github.com/bgrins/TinyColor),它有一个 mostReadable 函数。我认为这比自己酿造更好。
  • 为什么要添加零填充,为什么要删除...有人解释一下..

标签: javascript jquery html css colors


【解决方案1】:

更新:生产就绪代码在GitHub


这就是我的做法:

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

示例输出:

高级版:

这有一个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);
}

示例输出:

【讨论】:

  • 这个对“相反”问题的回答,将颜色设置为具有背景颜色的前景,几乎相同。根据原始问题更改小提琴可能会导致低对比度颜色(没有“bw”)或背面和白色背景jsfiddle.net/cffcd5bj/5。希望@stack 对其进行调整以避免不希望的低对比度颜色对。
  • 你做了一个函数库,放到github上? :-)
  • 是的。这就是所谓的微图书馆。更易于维护,包含 SRP 等。
  • 我使用内置的 .padStart 函数进行返回。 return "#" + r.padStart(2, '0') + g.padStart(2, '0') + b.padStart(2, '0'); developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
  • @OnurYıldırım 添加了学分。不过提醒一下。
【解决方案2】:

简洁优雅。

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

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

【讨论】:

  • 不知道它的作用或工作原理,但它确实简单而优雅:)
  • 如果有人能解释它是如何工作的,我会非常高兴。
  • @Ar2 Number(0x1${hex}) 首先它采用给定的十六进制(字符串)值并将其转换为十六进制 ^ 0xFFFFFF 然后对该值执行按位执行使用0xFFFFFF,我现在只能这样解释,如果你想尽快反转一个数字,例如。 3 > 7, 8 > 2, 1 > 9 等等。简单地用 10 减去数字并绝对它。这就是该部分所做的,除了 HEX 值。其余的基本上是格式化和删除公式溢出的第一个值。
  • 真的很好很简单,但请注意它“反映在颜色的中间”,所以靠近中间的颜色会得到非常接近它的颜色。例如反转十六进制('808080');产生几乎相同颜色的“7F7F7F”。
  • 令人印象深刻!说明:按位^ 如果两个位中只有一个为 1,则将每个位设置为 1; toString(16) 数字将显示为十六进制值; substr(1) 返回结果字符串,但跳过第一项; toUpperCase()这很明显。
【解决方案3】:

使用 CSS 实现这一目标的简单方法:

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

【讨论】:

  • 注意事项:!E 或 Microsoft Edge 等目前不支持 mix-blend-mode,并且根据您的用例,可能不太可能正常失败。
【解决方案4】:

@Onur 的 answer 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>

【讨论】:

    【解决方案5】:

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

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

    • 将 Hue 旋转 180º 以获得(可能没用的)最大颜色对比度
    • 计算亮度差异。
    • (计算色差...不必要,它是最大或几乎)
    • 计算对比度。
    • 如果结果颜色符合要求,则计算结束,如果不符合,则循环:
      • 如果亮度差异不足以增加或 将计算的颜色亮度 (L) 减少一定的量或比率(向上或 down 取决于原始颜色亮度:> 或
      • 检查它是否符合您的要求,如果计算结束。
      • 如果亮度可以再增加(或减少),则没有符合要求的有效颜色,只需尝试黑白,取其中“最好的一个”(可能是对比度更大的那个)并结束。

    【讨论】:

      【解决方案6】:

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

      InvertedColorComponent = 0xFF - ColorComponent
      

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

      反色红色 (#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
      

      另一个例子:

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

      橙色 (#FFA500) 变为 #005AFF

      【讨论】:

      • 我也会使用“inverse”,但请记住,“opposite”也可以表示“色轮上的相反”。
      【解决方案7】:

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

      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
      }
      
      

      Codepen example

      【讨论】:

        【解决方案8】:

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

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

        【讨论】:

          【解决方案9】:

          怎么样,CSS filter: invert(1),它有一个不错的 cross-browser compatibility,它可以处理文本和图像或任何你的内容。

          对于黑白反色添加更多过滤器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>

          【讨论】:

          • 这个方案在正面是最优的。
          • 这个我找了很久了。你saturate(0) grayscale(1) brightness(.7) contrast(1000%) invert(1) 的解决方案太棒了。
          【解决方案10】:

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

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

          下面的颜色“类”。接受 hex、rgb、rgba(即使是百分比),也可以输出到任何一个。 Explorer 需要为 String.padStartString.startsWith 使用 polyfill,并且需要使用 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;
          }());
          

          【讨论】:

            【解决方案11】:

            可以使用 sn-ps 转换 HEX 颜色

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

            【讨论】:

            • 这很好,这是获得实用的反转的快速方法
            【解决方案12】:

            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)
            

            【讨论】:

            • 这不能回答 OP 的问题,因为它被标记为 HTML 和 Javascript
            【解决方案13】:

            对于 Typescript 爱好者,这里是我使用的:

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2021-07-20
              • 2018-03-16
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-06-03
              相关资源
              最近更新 更多