根据覆盖的背景区域的亮度更改文本颜色?


114

我已经考虑了以下内容,所以现在我想知道您的意见,可能的解决方案等等。

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

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

此外,如果脚本会注意到父级没有定义的background-color或-image,然后继续搜索最接近的值(从父元素到其父元素),那将是很好的选择。

您对此想法有什么看法?已经有类似的东西了吗?脚本示例?

干杯J.


1
只是想法而不是答案。可能有一种方法可以使用HSL设置颜色,然后查看亮度值。如果该值高于某个值,则应用css规则。
斯科特·布朗

1
您可以想象将元素的背景色解析为R,G,B(和可选的alpha)值,如果alpha通道设置为零,则可以处理DOM树。但是,尝试确定背景图像的颜色完全是另一回事。
jackwanders 2012年


@Pascal非常相似,并且输入很好。.但这不是我问题的确切答案。
James Cazzetta 2013年

Answers:


175

有趣的资源:

这是W3C算法(也带有JSFiddle演示):

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>


费利克斯你是对的!我现在不在了,但是可以肯定的是,什么时候回来我会更新答案
亚历克斯·鲍尔

1
可以缩写为以下内容,只要为它传递一个对象:::: const setContrast = rgb =>(rgb.r * 299 + rgb.g * 587 + rgb.b * 114)/ 1000> 125?'黑色':'白色'
卢克·罗伯逊,

您是否仅需要jquery来更改CSS?
bluejayke

@bluejayke不,还有其他方法;-)
亚历克斯·鲍尔

62

您可能会对这篇关于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';
}

谢谢,这真的很有帮助。这取决于设置的背景色。但是您知道如何通过遍历每个像素(如循环)来获取图像的平均颜色吗?
詹姆斯·卡泽塔

4
在es6中,您可以执行以下操作:const getContrastYIQ = hc => { const [r, g, b] = [0, 2, 4].map( p => parseInt( hc.substr( p, 2 ), 16 ) ); return ((r * 299) + (g * 587) + (b * 114)) / 1000 >= 128; }
Centril 2015年

我采用了此功能,并对其进行了扩展,以便您可以返回两种自定义颜色,而不是始终返回黑白。请注意,如果两种颜色靠得很
Hanna

1
这个很酷,我只是将yiq调整为> = 160,对我来说效果更好。
Arturo

15

有趣的问题。我立即想到的是将背景颜色转换为文本。这包括简单地解析背景并反转其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()值,但根据浏览器而有所不同。
jackwanders 2012年

是。为了便于解析,我只使用了十六进制值。我更新了小提琴,使其包括从CSS中获取元素的颜色。我更新了小提琴,并添加了一种亮度控制(我对颜色数学一无所知,因此可能并不是真正的亮度)。
jeremyharris


2
如果背景色是#808080!怎么办?
内森·麦金尼斯

1
@NathanMacInnes仍然会对其进行反转,以至于恰好在频谱中间反转某些内容会导致其自身反转。这段代码只是反转颜色,这有其局限性。
jeremyharris 2012年

9

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/


5

我发现BackgroundCheck脚本非常有用。

它检测背景的总体亮度(可以是背景图像还是彩色),并根据背景的亮度将一个类应用于所分配的文本元素(background--lightbackground--dark)。

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

来源


感谢您的贡献!
James Cazzetta 2015年

这对背景颜色有用吗?我已经快速阅读了该脚本,但看不到它使用背景色来检查亮度。仅图像。
耶尔SKÄR费

1
您好Jørgen,我认为colourBrightness脚本可能会满足您的目的:github.com/jamiebrittain/colourBrightness.js
cptstarling

5

如果您使用的是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))

4

这是我的尝试:

(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,并且没有隐藏溢出)。要使该工作更加复杂。


1

通过结合答案[@ 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>

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.