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

我正在寻找一个插件或技术,改变文本的颜色或之间的转换预定义的图像/图标取决于平均亮度的覆盖像素的父母的背景-图像或-颜色。

如果它的背景覆盖区域相当黑暗,使文字白色或切换图标。

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

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

114870 次浏览

有趣的问题。我的第一反应就是把背景的颜色反过来作为文本。这涉及到简单地解析背景和反转其 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+')');

有趣的资源:

下面是 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>

这篇关于 计算颜色对比度的24种方法的文章可能会引起你的兴趣。忽略第一组函数,因为它们是错误的,但是 YIQ 公式将帮助您确定是否使用浅色或深色的前景色。

一旦获得了元素的(或祖先的)背景颜色,就可以使用本文中的函数来确定合适的前景颜色:

function getContrastYIQ(hexcolor){
var r = parseInt(hexcolor.substring(1,3),16);
var g = parseInt(hexcolor.substring(3,5),16);
var b = parseInt(hexcolor.substring(5,7),16);
var yiq = ((r*299)+(g*587)+(b*114))/1000;
return (yiq >= 128) ? 'black' : 'white';
}

这是我的尝试:

(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,并且没有隐藏溢出) ,这将不起作用。要做到这一点要复杂得多。

我发现 背景调查脚本非常有用。

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

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

(来源)

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月) : 下面是一个很好的教程,解释了所有不同类型的模式/实现: < a href = “ https://css-trick s.com/css-technologies-and-effect-for-淘汰-text/”rel = “ norefrer”> https://css-tricks.com/css-techniques-and-effects-for-knockout-text/

如果您正在使用 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))

通过组合这些答案[@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>

在 es6中,六进制字符的颜色字符串(# 123456)的对比度可以用这个一行程序来计算:

const contrastColor = c=>["black","white"][~~([1,3,5].map(p=>parseInt(c.substr(p,2),16)).reduce((r,v,i)=>[.299,.587,.114][i]*v+r,0)<128)];

下面是可读的详细版本:

const contrastColor = color =>
{
const lum = [1,3,5].map(pos => //get RGB colors array from the string at positions 1, 3 and 5 (0 = # character)
{
// return converted hex value into decimal for each R, G, and B
return parseInt(color.substr(pos, 2), 16);
}).reduce((result, value, index) =>
{
// with reduce() we can convert an array of numbers into a single number
// result = previous result returned by this function
// value = Red, Green or Blue value of the color
// index = current position index in the array
// y = https://www.w3.org/TR/AERT/#color-contrast


const y = [.299 /*red*/,.587 /*green*/,.114 /*blue*/][index];
return result + y * value // return sum of previous results
}
, 0 /* result = 0 */);
  

const isDark = lum < 128;
const index = ~~isDark; // convert boolean into 0 or 1
return ["black", "white"][index];
}


function setColors()
{


for(let i = 0; i < 70; i++)
{
const bg = "#" + (~~(Math.random() * 16777216)).toString(16).padStart(6, 0),
color = contrastColor(bg);
node = test.children[i] || document.createElement("span");
node.style.backgroundColor = bg;
node.style.color = color;
node.textContent = bg;
if (!node.parentNode)
test.appendChild(node);
}
}


setColors();
#test
{
display: flex;
flex-wrap: wrap;
font-family: monospace;
}
#test > *
{
padding: 0.3em;
}
<button id="click" onclick="setColors()">change</button>
<div id="test"></div>