Изменить цвет текста на основе яркости покрытой области фона?

Я уже некоторое время думал об этом, поэтому теперь хочу узнать ваше мнение, возможные решения и т.д.

Я ищу плагин или метод, который изменяет цвет текста или переключает между предопределенными изображениями/значками в зависимости от средней яркости покрытых пикселей его родительского фонового изображения или -цвет.

Если покрытая область его фона довольно темная, сделайте текст белым или переключите значки.

Кроме того, было бы замечательно, если бы script заметил бы, если родитель не имеет определенного фонового цвета или -изображения, а затем продолжит поиск ближайшего (от родительского элемента к нему родительского элемента..).

Как вы думаете, знаете об этой идее? Есть ли что-то подобное там уже? script -examples?

Приветствия, Дж.

Ответ 1

Интересные ресурсы для этого:

Здесь алгоритм 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

Эта статья о 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';
}

Ответ 3

Интересный вопрос. Моя непосредственная мысль заключалась в том, чтобы инвертировать цвет фона как текст. Это предполагает просто анализ фона и инвертирование его значения 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+')');

Ответ 4

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>

Ответ 5

Я нашел BackgroundCheck script, чтобы быть очень полезным.

Он обнаруживает избыточную яркость фона (будь то фоновое изображение или цвет) и применяет класс к назначенному текстовому элементу (background--light или background--dark), в зависимости от яркости фона.

Он может применяться к неподвижным и движущимся элементам.

(Источник)

Ответ 6

Здесь моя попытка:

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

Затем, чтобы использовать его:

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

Это сразу, сделайте текст черным или белым, если необходимо. Чтобы сделать значки:

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

Затем каждый значок может выглядеть как 'save' + iconSuffix + '.jpg'.

Обратите внимание, что это не будет работать, когда какой-либо контейнер переполняет его родительский элемент (например, если высота CSS равна 0, а переполнение не скрыто). Получить эту работу было бы намного сложнее.

Ответ 7

Если вы используете ES6, конвертируйте hex в 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))