Javascript 根据覆盖背景区域的亮度更改文本颜色?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11867545/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Change text color based on brightness of the covered background area?
提问by James Cazzetta
I've thought about the following for a while already, so now I want to know your opinions, possible solutions, and so on.
我已经考虑了一段时间,所以现在我想知道您的意见,可能的解决方案等等。
I am looking for a plugin or technique that changes a text's color or switches between predefined images/icons depending on the average brightness of the covered pixels of it's parent's background-image or -color.
我正在寻找一种插件或技术,可以根据其父背景图像或颜色的覆盖像素的平均亮度来更改文本颜色或在预定义图像/图标之间切换。
If the covered area of it's background is rather dark, make the text white or switch the icons.
如果背景的覆盖区域比较暗,请将文本设为白色或切换图标。
Additionally, it'd be great if the script would notice if the parent has no defined background-color or -image and then continue to search for the most nearest (from parent element to it's parent element..).
此外,如果脚本会注意到父元素是否没有定义的背景颜色或图像,然后继续搜索最近的(从父元素到它的父元素......),那就太好了。
What do you think, know about this idea? Is there something similar out there already? script-examples?
你怎么看,知道这个想法吗?已经有类似的东西了吗?脚本示例?
Cheers, J.
干杯,J。
回答by Alex Ball
Interesting resources for this:
有趣的资源:
- W3C - Ensure that foreground and background color combinations provide sufficient contrast
- Calculating the Perceived Brightness of a Color
Here's the W3C algorithm (with JSFiddle demo too):
这是 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>
回答by cyang
This article on 24 ways about Calculating Color Contrastmight be of interest to you. Ignore the first set of functions because they're wrong, but the YIQ formula will help you determine whether or not to use a light or dark foreground color.
这篇关于计算颜色对比度的24 种方法的文章可能会让您感兴趣。忽略第一组函数,因为它们是错误的,但 YIQ 公式将帮助您确定是否使用浅色或深色前景色。
Once you obtain the element's (or ancestor's) background color, you can use this function from the article to determine a suitable foreground color:
获得元素的(或祖先的)背景颜色后,您可以使用文章中的此函数来确定合适的前景色:
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';
}
回答by jeremyharris
Interesting question. My immediate thought was to invert the color of the background as the text. This involves simply parsing the background and inverting its RGB value.
有趣的问题。我的直接想法是将背景颜色反转为文本。这涉及简单地解析背景并反转其 RGB 值。
Something like this: http://jsfiddle.net/2VTnZ/2/
像这样的东西: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+')');
回答by James Cazzetta
mix-blend-mode
does the trick:
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>
Addition (March 2018): Following, a nice tutorial explaining all different types of modes/implementations: https://css-tricks.com/css-techniques-and-effects-for-knockout-text/
添加(2018 年 3 月):以下是一个很好的教程,解释了所有不同类型的模式/实现:https: //css-tricks.com/css-techniques-and-effects-for-knockout-text/
回答by Luke Robertson
If you are using ES6, convert hex to RGB then can use this:
如果您使用的是 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))
回答by cptstarling
I've found the BackgroundCheckscript to be very useful.
我发现BackgroundCheck脚本非常有用。
It detects the overal brightness of the background (be it a background image or a color), and applies a class to the assigned text-element (background--light
or background--dark
), dependent on the brightness of the background.
它检测背景的整体亮度(无论是背景图像还是颜色),并将类应用于指定的文本元素(background--light
或background--dark
),具体取决于背景的亮度。
It can be applied to still and moving elements.
它可以应用于静止和移动的元素。
(Source)
(来源)
回答by Nathan MacInnes
Here's my attempt:
这是我的尝试:
(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));
Then to use it:
然后使用它:
var t = $('#my-el');
t.contrastingText();
This will straight away, make the text either black or white as appropriate. To do the icons:
这将立即使文本根据需要变为黑色或白色。做图标:
if (t.lightBackground) {
iconSuffix = 'black';
} else {
iconSuffix = 'white';
}
Then each icon could look like 'save' + iconSuffix + '.jpg'
.
然后每个图标可能看起来像'save' + iconSuffix + '.jpg'
。
Note that this won't work where any container overflows its parent (for example, if the CSS height is 0, and overflow isn't hidden). To get that working would be a lot more complex.
请注意,当任何容器溢出其父容器时,这将不起作用(例如,如果 CSS 高度为 0,并且溢出未隐藏)。要让它工作起来会复杂得多。
回答by A. El-zahaby
By combining the answers [ @alex-ball , @jeremyharris ] I found this to be the best way for me:
通过结合答案 [ @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>