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

Javascript 如何根据当前颜色生成相反的颜色?,javascript,jquery,html,css,colors,Javascript,Jquery,Html,Css,Colors,我正在尝试创建一种与当前颜色相反的颜色。我的意思是,如果当前颜色是黑色,那么我需要生成白色 实际上我有一个文本(这个文本的颜色是动态的,它的颜色可以随意设置)。该文本被放入div中,我需要为div的背景色设置该文本的相反颜色。我希望div(颜色透视图)中的文本清晰 相反的颜色表示:暗/亮 我有文本的当前颜色,我可以将其传递给此函数: var TextColor = #F0F0F0; // for example (it is a bright color) function create

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

实际上我有一个文本(这个文本的颜色是动态的,它的颜色可以随意设置)。该文本被放入
div
中,我需要为
div的
背景色设置该文本的相反颜色。我希望
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\u opp\u color()
函数?

注意可访问性(AA/AAA)。颜色对比本身是无用的。对于色盲的人来说,不同的颜色完全没有对比。 我想这种颜色的计算可以是这样的:

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

  • 将色调旋转180º以获得(可能无用的)最大颜色对比度
  • 计算亮度差
  • (计算色差…不必要,它是最大的或几乎)
  • 计算对比度
  • 如果生成的颜色符合要求,则计算结束,如果不符合,则循环:
    • 如果亮度差不够,则增加或 将计算出的颜色亮度(L)减少一定量或比率(向上或向下) 取决于原始颜色亮度:>或
    • 检查它是否符合您的要求,如果符合,计算结束
    • 如果亮度可以增加(或减少),没有符合要求的有效颜色,只需尝试黑色和白色,选择其中的“最佳颜色”(可能是对比度较大的颜色)并结束

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

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

      倒红色(#00FFFF)为:

      另一个例子:

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


      橙色(#FFA500)变为#005AFF

      更新:生产就绪代码开启。


      我会这样做:

    • 将十六进制转换为RGB
    • 反转R、G和B分量
    • 将每个组件转换回十六进制
    • 用零填充每个组件并输出
    • 函数反转颜色(十六进制){
      if(十六进制索引of('#')==0){
      十六进制=十六进制切片(1);
      }
      //将3位十六进制转换为6位。
      如果(十六进制长度===3){
      十六进制=十六进制[0]+十六进制[0]+十六进制[1]+十六进制[1]+十六进制[2]+十六进制[2];
      }
      如果(十六进制长度!==6){
      抛出新错误(“十六进制颜色无效”);
      }
      //反转颜色分量
      var r=(255-parseInt(十六进制切片(0,2,16)).toString(16),
      g=(255-parseInt(十六进制切片(2,4,16)).toString(16),
      b=(255-parseInt(十六进制切片(4,6,16)).toString(16);
      //用零填充每个字符并返回
      返回“#”+padZero(r)+padZero(g)+padZero(b);
      }
      函数padZero(str,len){
      len=len | | 2;
      var zeros=新数组(len).join('0');
      返回(零+str).slice(-len);
      }
      
      示例输出:

      高级版本:

      这有一个
      bw
      选项,将决定是反转为黑色还是白色;因此,你会得到更多的对比度,这通常对人眼更有利

      函数反转颜色(十六进制,bw){
      if(十六进制索引of('#')==0){
      十六进制=十六进制切片(1);
      }
      //将3位十六进制转换为6位。
      如果(十六进制长度===3){
      十六进制=十六进制[0]+十六进制[0]+十六进制[1]+十六进制[1]+十六进制[2]+十六进制[2];
      }
      如果(十六进制长度!==6){
      抛出新错误(“十六进制颜色无效”);
      }
      var r=parseInt(十六进制切片(0,2,16),
      g=parseInt(十六进制切片(2,4,16),
      b=parseInt(十六进制切片(4,6,16));
      如果(bw){
      // http://stackoverflow.com/a/3943023/112731
      回报率(r*0.299+g*0.587+b*0.114)>186
      ? '#000000'
      :“#FFFFFF”;
      }
      //反转颜色分量
      r=(255-r).toString(16);
      g=(255-g).toString(16);
      b=(255-b).toString(16);
      //用零填充每个字符并返回
      返回“#”+padZero(r)+padZero(g)+padZero(b);
      }
      
      示例输出:


      简单地将背景颜色翻转为文本颜色对于某些中等范围的值不起作用,例如
      0x808080
      。我尝试过改变颜色值-
      (v+0x80)%0x100
      。看一个演示


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

      使用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();
          }
      }
      
      功能调整颜色(元件){
      var style=window.getComputedStyle(元素);
      var background=新颜色(样式['background-Color']);
      var text=新颜色(样式['Color']);
      if(Math.abs(background.luma-text.luma)<100){
      element.style.color=text.inversed.toString();
      }
      }
      
      下面是颜色“类”。接受十六进制、rgb、rgba(即使有百分比),也可以输出到任意一个。Explorer将需要和的多边形填充,而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;
      }());
      
      const Color=(函数(){
      函数toHex(num,padding){return num.toString(16).padStart(padding | | 2)}
      函数解析部分(值){
      var perc=value.lastIndexOf('%');
      返回perc<0?值:value.substr(0,perc);
      }
      功能颜色(数据){
      如果(arguments.length>1){
      此[0]=参数[0];
      此[1]=参数[1];
      此[2]=参数[2];
      如果(arguments.length>3){this[3]=arguments[3];}
      }否则,如果(数据仪表)
      
      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;
      }());
      
      function invertHex(hex) {
        return (Number(`0x1${hex}`) ^ 0xFFFFFF).toString(16).substr(1).toUpperCase()
      }
      
      invertHex('00FF00'); // Returns FF00FF
      
      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
      }
      
      
      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;
      }
      
      function invertColor(color) {
            return '#' + ("000000" + (0xFFFFFF ^ parseInt(color.substring(1),16)).toString(16)).slice(-6);
        }
      
      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)