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

时间:2022-05-13 20:01:39

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.

我正在寻找一种插件或技术,它可以根据父类背景图像或-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..).

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

What do you think, know about this idea? Is there something similar out there already? script-examples?

你对这个想法了解多少?有类似的东西吗?脚本示例?

Cheers, J.

干杯,J。

7 个解决方案

#1


124  

Interesting resources for this:

有趣的参考资料:

Here's the W3C algorithm (with JSFiddle demo too):

下面是W3C算法(还有JSFiddle demo):

var rgb = [255, 0, 0];

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

function setContrast() {
  // randomly update
  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
  var o = Math.round(((parseInt(rgb[0]) * 299) +
                      (parseInt(rgb[1]) * 587) +
                      (parseInt(rgb[2]) * 114)) / 1000);
  var fore = (o > 125) ? 'black' : 'white';
  var back = 'rgb(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ')';
  $('#bg').css('color', fore); 
  $('#bg').css('background-color', back);
  

}
#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>

#2


32  

This article on 24 ways about Calculating Color Contrast might 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){
    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';
}

#3


14  

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+')');

#4


4  

I've found the BackgroundCheck script 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.

它检测背景的超亮度(无论是背景图像还是颜色),并根据背景的亮度将类应用到指定的文本元素(背景——亮还是暗)。

It can be applied to still and moving elements.

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

(Source)

(源)

#5


3  

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();
        }
        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 normalise 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'.

然后每个图标看起来像“保存”+ 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,且溢出未被隐藏),这是行不通的。要让它工作起来要复杂得多。

#6


2  

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-trick . /css- techniquesand -effects-for knockout-text/

#7


1  

If you are using ES6, convert hex to RBG then can use this:

如果您正在使用ES6,那么将十六进制转换为RBG,然后可以使用以下方法:

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))

#1


124  

Interesting resources for this:

有趣的参考资料:

Here's the W3C algorithm (with JSFiddle demo too):

下面是W3C算法(还有JSFiddle demo):

var rgb = [255, 0, 0];

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

function setContrast() {
  // randomly update
  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
  var o = Math.round(((parseInt(rgb[0]) * 299) +
                      (parseInt(rgb[1]) * 587) +
                      (parseInt(rgb[2]) * 114)) / 1000);
  var fore = (o > 125) ? 'black' : 'white';
  var back = 'rgb(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ')';
  $('#bg').css('color', fore); 
  $('#bg').css('background-color', back);
  

}
#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>

#2


32  

This article on 24 ways about Calculating Color Contrast might 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){
    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';
}

#3


14  

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+')');

#4


4  

I've found the BackgroundCheck script 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.

它检测背景的超亮度(无论是背景图像还是颜色),并根据背景的亮度将类应用到指定的文本元素(背景——亮还是暗)。

It can be applied to still and moving elements.

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

(Source)

(源)

#5


3  

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();
        }
        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 normalise 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'.

然后每个图标看起来像“保存”+ 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,且溢出未被隐藏),这是行不通的。要让它工作起来要复杂得多。

#6


2  

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-trick . /css- techniquesand -effects-for knockout-text/

#7


1  

If you are using ES6, convert hex to RBG then can use this:

如果您正在使用ES6,那么将十六进制转换为RBG,然后可以使用以下方法:

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))