【问题标题】:Calculating contrasting colours in javascript在javascript中计算对比色
【发布时间】:2010-10-12 17:03:40
【问题描述】:

在我们目前正在处理的其中一个页面上,用户可以更改所显示文本的背景。

我们希望自动更改前景色以保持文本的合理对比度。

我们还希望颜色范围可以自行决定。例如,如果背景以 255 个增量从白色变为黑色,我们不希望看到 255 种前景色。在这种情况下,可能是 2 到 4,只是为了保持合理的对比度。

是否有任何 UI/设计/色彩专家/画家来制定公式?

【问题讨论】:

    标签: javascript color-scheme


    【解决方案1】:

    您可能想要改变色调,而不是饱和度或值。

    因此,将您的 RGB 值转换为 HSV,将 180 度添加到 H(当然是模 360 度),然后转换回 RGB。

    Conversion forumlas are here.

    【讨论】:

    • 呃,这是个糟糕的主意。变化的色调充其量会让你一团糟(木棕色+深蓝色),最坏的情况是让你头疼(红色+绿色)。更安全的做法是转移价值。
    【解决方案2】:

    就纯粹的可读性而言,您希望在任何背景上使用黑白文本。因此将 RGB 转换为 HSV,只需检查 V 是否

    先尝试一下,看看你是否觉得它有吸引力。

    如果你不这样做,那么当你的背景太亮或太暗时,你可能希望白色和黑色不要太鲜明。要将其调低,请保持相同的色调和饱和度,并将这些值用于亮度:

    background V  foreground V
    0.0-0.25      0.75
    0.25-0.5      1.0
    0.5-0.75      0.0
    0.75-1.0      0.25
    

    在中等颜色上,您仍会看到清晰易读的黑色或白色文本。在深色或浅色上,您会看到相同的颜色文本,但亮度至少相差 3/4,因此仍然可读。我希望它看起来不错:)

    【讨论】:

    • 无论出于何种原因,HSV 都没有达到预期的效果。另一方面,HSL 除了少数饱和颜色外,即使是纯黑白(略微偏向黑色)也能很好地完成这项工作。
    • 好吧,也许 HSL 是我真正的意思 :) 我不完全确定。
    【解决方案3】:

    由于 javascript 处理十进制值的方式,实现起来有点复杂。 为此,我发现让背景更改任何颜色但文本只是在黑白之间切换会更好。 如果你使用对比色,很多组合将很难忍受。另请注意,有些人是色盲,因此从可访问性的角度来看,这不是一个好主意。

    【讨论】:

      【解决方案4】:

      试试this example,它只是根据 r、g 和 b 值的平均值将其设置为黑色或白色。也适合测试!如果发现效果不佳的情况,请在其中替换更好的算法。

      <html> 
      <head> 
      <script> 
      function rgbstringToTriplet(rgbstring)
      {
          var commadelim = rgbstring.substring(4,rgbstring.length-1);
      var strings = commadelim.split(",");
      var numeric = [];
      for(var i=0; i<3; i++) { numeric[i] = parseInt(strings[i]); }
      return numeric;
      }
      
      function adjustColour(someelement)
      {
         var rgbstring = someelement.style.backgroundColor;
         var triplet = rgbstringToTriplet(rgbstring);
         var newtriplet = [];
         // black or white:
         var total = 0; for (var i=0; i<triplet.length; i++) { total += triplet[i]; } 
         if(total > (3*256/2)) {
           newtriplet = [0,0,0];
         } else {
       newtriplet = [255,255,255];
         }
         var newstring = "rgb("+newtriplet.join(",")+")";
         someelement.style.color = newstring;
         return true;
      }
      
      function randomiseBackground(someelement)
      {
       var vals = [];
       for(var i=0; i<3; i++) { vals[i]=Math.floor(Math.random()*256+1); }
       someelement.style.backgroundColor="rgb("+vals.join(",")+")";
       return true;
      }
      </script> 
      </head> 
      <body onload="adjustColour(document.getElementById('mypara'));"> 
      <p id="mypara" style="background-color:#2287ea">Some text</p> 
      <form> 
          <input type=button onclick="var elem=document.getElementById('mypara'); randomiseBackground(elem); adjustColour(elem);" value="randomise background" /> 
      </form> 
      </body> 
      </html>
      

      【讨论】:

        【解决方案5】:

        根据亮度做出黑白决定对我来说效果很好。亮度是 R、G 和 B 值的加权和,根据人类对相对亮度的感知进行调整,这在视频应用中显然很常见。亮度的官方定义随着时间的推移而改变,具有不同的权重;见这里:http://en.wikipedia.org/wiki/Luma_(video)。我使用 Rec 获得了最好的结果。 709 版本,如下面的代码所示。 165 左右的黑白阈值似乎不错。

        function contrastingColor(color)
        {
            return (luma(color) >= 165) ? '000' : 'fff';
        }
        function luma(color) // color can be a hx string or an array of RGB values 0-255
        {
            var rgb = (typeof color === 'string') ? hexToRGBArray(color) : color;
            return (0.2126 * rgb[0]) + (0.7152 * rgb[1]) + (0.0722 * rgb[2]); // SMPTE C, Rec. 709 weightings
        }
        function hexToRGBArray(color)
        {
            if (color.length === 3)
                color = color.charAt(0) + color.charAt(0) + color.charAt(1) + color.charAt(1) + color.charAt(2) + color.charAt(2);
            else if (color.length !== 6)
                throw('Invalid hex color: ' + color);
            var rgb = [];
            for (var i = 0; i <= 2; i++)
                rgb[i] = parseInt(color.substr(i * 2, 2), 16);
            return rgb;
        }
        

        【讨论】:

          【解决方案6】:

          如果你使用的是d3.js,你可以做一些判断

          d3.hsl(d3.color("black")).l &gt; 0.5 ? "#000" : "fff"(简单但未必完美)

          getLuma(r, g, b, fmt) &gt; 165 ? "#000" : "#fff" 见示例 2

          示例1

          <script src="https://d3js.org/d3.v7.min.js"></script>
          <script>
            const bgColorList = ["black", "purple", "#cc1515", "green", "blue", "red", "yellow", "white"]
            window.onload = () => {
              d3.select("body").append("section")
                .selectAll("div")
                .data(bgColorList)
                .enter().append("div")
                .text((bgColor, idx, arr) => {
                  const div = arr[idx]
                  const {h, l} = d3.hsl(d3.color(bgColor))
                  const foreColor = l > 0.5 ? "#000" : "#fff"
                  div.outerHTML = `<div style="width:100px;height:50px;
          background-color: ${bgColor};
          color:${foreColor}
          ">Hello world</div>`
                })
            }
          </script>

          但是当l等于0.5(例如:黄色、蓝色)时,就会有争议。

          示例2

          <script src="https://d3js.org/d3.v7.min.js"></script>
          
          <table>
            <tr>
              <th>601</th>
              <th>709</th>
              <th>240</th>
            </tr>
            <tr id="output"></tr>
          </table>
          
          <script>
            /**
             * https://en.wikipedia.org/wiki/Luma_%28video%29
             * @param {"601"|"709"|"240"|"145"} format
             */
            function getLuma(r, g, b, format) {
              switch (format) {
                case "601":
                  return 0.2999 * r + 0.587 * g + 0.114 * b
                case "709":
                  return 0.2126 * r + 0.7152 * g + 0.0722 * b
                case "145":
                case "240":
                  return 0.212 * r + 0.701 * g + 0.087 * b
              }
            }
          
            const bgColorList = [...Array(100).keys()].map(t => d3.scaleSequential(d3.interpolateTurbo)(t / 100))
              .concat(["black", "purple", "#cc1515", "green", "blue", "red", "white", "yellow"])
            window.onload = () => {
              const tdArr = []
              d3.select("#output")
                .selectAll("td")
                .data(["601", "709", "240"])
                .enter().append("td")
                .text((fmt, _idx, _arr) => {
                  const td = _arr[_idx]
                  tdArr.push([td, fmt])
                })
          
              tdArr.forEach(([td, fmt]) => {
                d3.select(td).append("section")
                  .selectAll("div")
                  .data(bgColorList)
                  .enter().append("div")
                  .text((bgColor, idx, arr) => {
                    const div = arr[idx]
                    const {r, g, b} = d3.color(bgColor)
                    const foreColor = getLuma(r, g, b, fmt) > 165 ? "#000" : "#fff"
                    // const coefficient = [0.2126, 0.7152, 0.0722]
                    // const foreColor = [r, g, b].reduce((sum, color, i) => sum + color * coefficient[i], 0) > 165 ? "#000" : "#fff"
                    div.outerHTML = `<div style="width:100px;height:26px;
          background-color: ${bgColor};
          color:${foreColor}
          ">Hello</div>`
                  })
              })
            }
          </script>

          这和enigment's answer一样

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2019-04-03
            • 1970-01-01
            • 2019-02-05
            • 2011-10-06
            • 2011-08-04
            • 2015-09-04
            • 2020-10-03
            相关资源
            最近更新 更多