【问题标题】:Change text color based on brightness of the covered background area?根据覆盖的背景区域的亮度更改文本颜色?
【发布时间】:2012-08-05 17:48:07
【问题描述】:

我正在寻找一种插件或技术,它可以根据其父背景图像或颜色的覆盖像素的平均亮度来改变文本的颜色或在预定义的图像/图标之间切换。

如果它的背景被覆盖的区域很暗,请将文本设置为白色或切换图标。

此外,如果脚本能够注意到父级是否没有定义背景颜色或 -image 然后继续搜索最近的(从父元素到其父元素..),那就太好了。

你怎么看,知道这个想法吗?那里已经有类似的东西了吗?例子?

【问题讨论】:

  • 只是一个想法而不是一个答案。可能有一种方法可以使用 HSL 设置颜色,然后查看亮度值。如果该值高于某个值,则应用 css 规则。
  • 您可以想象将元素的背景颜色解析为 R、G、B(和可选的 alpha)值,如果 alpha 通道设置为零,则对 DOM 树进行处理。但是,尝试确定背景图像的颜色完全是另一回事。
  • @Pascal 非常相似,并且输入很好..但这不是我问题的确切答案。

标签: javascript jquery html css sass


【解决方案1】:

有趣的资源:

这是 W3C 算法(JSFiddle demo too):

const rgb = [255, 0, 0];

// Randomly change to showcase updates
setInterval(setContrast, 1000);

function setContrast() {
  // Randomly update colours
  rgb[0] = Math.round(Math.random() * 255);
  rgb[1] = Math.round(Math.random() * 255);
  rgb[2] = Math.round(Math.random() * 255);

  // http://www.w3.org/TR/AERT#color-contrast
  const brightness = Math.round(((parseInt(rgb[0]) * 299) +
                      (parseInt(rgb[1]) * 587) +
                      (parseInt(rgb[2]) * 114)) / 1000);
  const textColour = (brightness > 125) ? 'black' : 'white';
  const backgroundColour = 'rgb(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ')';
  $('#bg').css('color', textColour); 
  $('#bg').css('background-color', backgroundColour);
}
#bg {
  width: 200px;
  height: 50px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="bg">Text Example</div>

【讨论】:

  • 可以缩短为以下内容,前提是您传递一个对象 :::: const setContrast = rgb => (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000 > 125 ? “黑色”:“白色”
  • 你需要jquery来改变css吗?
  • @bluejayke 不,还有其他方法 ;-)
【解决方案2】:

这篇关于 Calculating Color Contrast 的 24 种方式的文章可能会让您感兴趣。忽略第一组函数,因为它们是错误的,但 YIQ 公式将帮助您确定是使用浅色还是深色前景色。

获得元素(或祖先)的背景颜色后,您可以使用文章中的此函数来确定合适的前景色:

function getContrastYIQ(hexcolor){
    hexcolor = hexcolor.replace("#", "");
    var r = parseInt(hexcolor.substr(0,2),16);
    var g = parseInt(hexcolor.substr(2,2),16);
    var b = parseInt(hexcolor.substr(4,2),16);
    var yiq = ((r*299)+(g*587)+(b*114))/1000;
    return (yiq >= 128) ? 'black' : 'white';
}

【讨论】:

  • 谢谢,这真的很有帮助.. 这取决于设置的背景颜色.. 但是您知道如何通过遍历每个像素(如循环)来获得图像的平均颜色?
  • 在 es6 中你可以这样做:const getContrastYIQ = hc =&gt; { const [r, g, b] = [0, 2, 4].map( p =&gt; parseInt( hc.substr( p, 2 ), 16 ) ); return ((r * 299) + (g * 587) + (b * 114)) / 1000 &gt;= 128; }
  • 我采用了这个函数并对其进行了一些扩展,以便您可以返回两种自定义颜色,而不是总是黑色和白色。请注意,如果两种颜色靠得很近,您可能仍然会遇到对比度问题,但这是返回绝对颜色的一个很好的替代方法jsfiddle.net/1905occv/1
  • 这个很酷,我只是将 yiq 调整为 >= 160,对我来说效果更好。
【解决方案3】:

mix-blend-mode 成功了:

header {
  overflow: hidden;
  height: 100vh;
  background: url(https://www.w3schools.com/html/pic_mountain.jpg) 50%/cover;
}

h2 {
  color: white;
  font: 900 35vmin/50vh arial;
  text-align: center;
  mix-blend-mode: difference;
  filter: drop-shadow(0.05em 0.05em orange);
}
<header>
  <h2 contentEditable role='textbox' aria-multiline='true' >Edit me here</h2>
</header>

新增内容(2018 年 3 月): 接下来,一个很好的教程解释了所有不同类型的模式/实现:https://css-tricks.com/css-techniques-and-effects-for-knockout-text/

【讨论】:

    【解决方案4】:

    有趣的问题。我的直接想法是将背景颜色反转为文本。这涉及简单地解析背景并反转其 RGB 值。

    类似这样的:http://jsfiddle.net/2VTnZ/2/

    var rgb = $('#test').css('backgroundColor');
    var colors = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
    var brightness = 1;
    
    var r = colors[1];
    var g = colors[2];
    var b = colors[3];
    
    var ir = Math.floor((255-r)*brightness);
    var ig = Math.floor((255-g)*brightness);
    var ib = Math.floor((255-b)*brightness);
    
    $('#test').css('color', 'rgb('+ir+','+ig+','+ib+')');
    

    【讨论】:

    • 您可能希望通过平均倒置的 R、G、B 值并将它们设置为彼此相等来降低“倒置”颜色的饱和度。但是,此解决方案是从字符串中获取其基色,而不是从元素的 CSS 属性中获取。为了可靠,该解决方案必须动态获取背景颜色,这通常返回 rgb() 或 rgba() 值,但可能因浏览器而异。
    • 是的。为了便于解析,我只使用了一个十六进制值。我更新了小提琴以包括从 CSS 中获取元素的颜色。我更新了小提琴并包含了一种亮度控制(我对颜色数学一无所知,所以它可能不是真正的亮度)。
    • 如果背景颜色是#808080!?
    • @NathanMacInnes 它仍然会反转它,碰巧反转光谱中间的某些东西会导致它本身。此代码只是反转颜色,这是有其局限性的。
    【解决方案5】:

    我发现BackgroundCheck 脚本非常有用。

    它检测背景的整体亮度(无论是背景图像还是颜色),并根据背景的亮度将一个类应用于指定的文本元素(background--lightbackground--dark)。

    它可以应用于静止和移动的元素。

    (Source)

    【讨论】:

    • 这适用于背景颜色吗?我已经快速阅读了脚本,但看不到它使用背景颜色来检查亮度。只有图片。
    • 您好 Jørgen,我认为 colourBrightness 脚本可能会达到您的目的:github.com/jamiebrittain/colourBrightness.js
    【解决方案6】:

    如果您使用的是 ES6,请将十六进制转换为 RGB,然后可以使用:

    const hexToRgb = hex => {
        // turn hex val to RGB
        const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
        return result
            ? {
                  r: parseInt(result[1], 16),
                  g: parseInt(result[2], 16),
                  b: parseInt(result[3], 16)
              }
            : null
    }
    
    // calc to work out if it will match on black or white better
    const setContrast = rgb =>
        (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000 > 125 ? 'black' : 'white'
    
    const getCorrectColor = setContrast(hexToRgb(#ffffff))
    

    【讨论】:

      【解决方案7】:

      通过结合答案 [@alex-ball,@jeremyharris],我发现这对我来说是最好的方法:

              $('.elzahaby-bg').each(function () {
                  var rgb = $(this).css('backgroundColor');
                  var colors = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
      
                  var r = colors[1];
                  var g = colors[2];
                  var b = colors[3];
      
                  var o = Math.round(((parseInt(r) * 299) + (parseInt(g) * 587) + (parseInt(b) * 114)) /1000);
      
                  if(o > 125) {
                      $(this).css('color', 'black');
                  }else{
                      $(this).css('color', 'white');
                  }
              });
      *{
          padding: 9px;
      }
      <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
      <div class='elzahaby-bg' style='background-color:#000'>color is white</div>
      
      <div class='elzahaby-bg' style='background-color:#fff'>color is black</div>
      <div class='elzahaby-bg' style='background-color:yellow'>color is black</div>
      <div class='elzahaby-bg' style='background-color:red'>color is white</div>

      【讨论】:

        【解决方案8】:

        这是我的尝试:

        (function ($) {
            $.fn.contrastingText = function () {
                var el = this,
                    transparent;
                transparent = function (c) {
                    var m = c.match(/[0-9]+/g);
                    if (m !== null) {
                        return !!m[3];
                    }
                    else return false;
                };
                while (transparent(el.css('background-color'))) {
                    el = el.parent();
                }
                var parts = el.css('background-color').match(/[0-9]+/g);
                this.lightBackground = !!Math.round(
                    (
                        parseInt(parts[0], 10) + // red
                        parseInt(parts[1], 10) + // green
                        parseInt(parts[2], 10) // blue
                    ) / 765 // 255 * 3, so that we avg, then normalize to 1
                );
                if (this.lightBackground) {
                    this.css('color', 'black');
                } else {
                    this.css('color', 'white');
                }
                return this;
            };
        }(jQuery));
        

        然后使用它:

        var t = $('#my-el');
        t.contrastingText();
        

        这将立即使文本根据需要变为黑色或白色。做图标:

        if (t.lightBackground) {
            iconSuffix = 'black';
        } else {
            iconSuffix = 'white';
        }
        

        那么每个图标可能看起来像'save' + iconSuffix + '.jpg'

        请注意,这在任何容器溢出其父级的情况下都不起作用(例如,如果 CSS 高度为 0,并且溢出未隐藏)。要让它发挥作用会复杂得多。

        【讨论】:

          猜你喜欢
          • 2017-09-17
          • 2016-06-02
          • 1970-01-01
          • 1970-01-01
          • 2019-01-08
          • 2015-12-31
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多