Как я могу создать противоположный цвет в соответствии с текущим цветом?

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

На самом деле у меня есть текст (цвет этого текста является динамическим, его цвет может быть сделан наугад). Этот текст находится в div и мне нужно установить противоположный цвет этого текста для background-color div. Я хотел бы, чтобы этот текст был четким в div (цветная перспектива).

Противоположный цвет означает: темный/яркий

У меня есть текущий цвет текста, и я могу передать его этой функции:

var TextColor = #F0F0F0;    // for example (it is a bright color)

function create_opp_color(current color) {

    // create opposite color according to current color

}

create_opp_color(TextColor); // this should be something like "#202020" (or a dark color)

Есть ли идея создать create_opp_color()?

Ответы

Ответ 1

UPDATE: готовый к выпуску код на GitHub.


Вот как я это сделаю:

  1. Преобразование HEX в RGB
  2. Инвертировать компоненты R, G и B
  3. Преобразование каждого компонента обратно в HEX
  4. Поместите каждый компонент с нулями и выводами.
function invertColor(hex) {
    if (hex.indexOf('#') === 0) {
        hex = hex.slice(1);
    }
    // convert 3-digit hex to 6-digits.
    if (hex.length === 3) {
        hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
    }
    if (hex.length !== 6) {
        throw new Error('Invalid HEX color.');
    }
    // invert color components
    var r = (255 - parseInt(hex.slice(0, 2), 16)).toString(16),
        g = (255 - parseInt(hex.slice(2, 4), 16)).toString(16),
        b = (255 - parseInt(hex.slice(4, 6), 16)).toString(16);
    // pad each with zeros and return
    return '#' + padZero(r) + padZero(g) + padZero(b);
}

function padZero(str, len) {
    len = len || 2;
    var zeros = new Array(len).join('0');
    return (zeros + str).slice(-len);
}

Пример:

enter image description here

Расширенная версия:

У этого есть опция bw, которая решит, следует ли инвертировать черное или белое; поэтому вы получите больше контраста, который обычно лучше для человеческого глаза.

function invertColor(hex, bw) {
    if (hex.indexOf('#') === 0) {
        hex = hex.slice(1);
    }
    // convert 3-digit hex to 6-digits.
    if (hex.length === 3) {
        hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
    }
    if (hex.length !== 6) {
        throw new Error('Invalid HEX color.');
    }
    var r = parseInt(hex.slice(0, 2), 16),
        g = parseInt(hex.slice(2, 4), 16),
        b = parseInt(hex.slice(4, 6), 16);
    if (bw) {
        // http://stackoverflow.com/a/3943023/112731
        return (r * 0.299 + g * 0.587 + b * 0.114) > 186
            ? '#000000'
            : '#FFFFFF';
    }
    // invert color components
    r = (255 - r).toString(16);
    g = (255 - g).toString(16);
    b = (255 - b).toString(16);
    // pad each with zeros and return
    return "#" + padZero(r) + padZero(g) + padZero(b);
}

Пример:

enter image description here

Ответ 2

Простой способ добиться этого с помощью CSS:

mix-blend-mode: difference;
color:white;

Ответ 3

Просто и элегантно.

function invertHex(hex) {
  return (Number('0x1${hex}') ^ 0xFFFFFF).toString(16).substr(1).toUpperCase()
}

invertHex('00FF00'); // Returns FF00FF

Ответ 4

Остерегайтесь доступности (AA/AAA). Цветовой контраст сам по себе бесполезен. На самом деле разные цвета могут не иметь никакого контраста для цветных слепых людей. ИМХО расчет для такого цвета может идти следующим образом:

(Для простоты используйте "HLS")

  • Поверните Hue на 180º, чтобы получить (возможно, бесполезный) максимальный цветовой контраст
  • Рассчитайте разницу яркости.
  • (Рассчитайте разницу цветов... ненужный, максимальный или почти)
  • Вычислить коэффициент контрастности.
  • Если итоговый цвет соответствует завершению расчета требований, если нет, цикл:
    • Если разница яркости недостаточно, увеличивайте или уменьшайте расчетную яркость цвета (L) на определенную величину или соотношение (вверх или вниз в зависимости от исходной яркости цвета:> или <чем среднее значение)
    • Проверьте, соответствует ли он вашим требованиям, заканчивается ли расчет.
    • если светимость может быть увеличена (или уменьшена), то не будет подходящего цвета для соответствия требованиям, просто попробуйте сделать черно-белый, возьмите "лучший" из них (возможно, тот, у кого больше контрастность) и закончите.

Ответ 5

В моем понимании вашего вопроса, противоположным цветом вы имеете в виду перевернутый цвет.

InvertedColorComponent = 0xFF - ColorComponent

Поэтому для красного цвета (# FF0000) это означает: R = 0xFF или 255 G = 0x00 или 0 B = 0x00 или 0

перевернутый цвет красный (# 00FFFF):

R = 0xFF - 0xFF = 0x00 or 255 - 255 = 0
G = 0xFF - 0x00 = 0xFF or 255 - 0 = 255
B = 0xFF - 0x00 = 0xFF or 255 - 0 = 255

Другие примеры:

Черный (# 000000) становится белым (#FFFFFF).

Оранжевый (# FFA500) становится # 005AFF

Ответ 6

Простое перемещение цвета фона в цвет текста не будет работать с некоторыми значениями среднего диапазона, например 0x808080. Вместо этого я попытался изменить значения цвета - (v + 0x80) % 0x100. См. Демонстрацию здесь.

Соглашаясь с комментарием от miguel-svq - хотя ожидаем увидеть более подробные алгоритмы для каждого шага расчета.

Ответ 7

Функция для инвертирования цвета элемента. Получает яркость каждого и, если они близки, инвертирует цвет текста.

function adjustColor(element) {
    var style = window.getComputedStyle(element);
    var background = new Color(style['background-color']);
    var text = new Color(style['color']);
    if (Math.abs(background.luma - text.luma) < 100) {
        element.style.color = text.inverted.toString();
    }
}

Цвет "Класс" ниже. Принимает hex, rgb, rgba (даже с процентами), а также может выводить любой из них. Для String.padStart и String.startsWith обозревателю потребуются полифилы, а интерполированную строку в методе toString() необходимо будет изменить с помощью concat.

const Color = (function () {
    function toHex(num, padding) { return num.toString(16).padStart(padding || 2); }
    function parsePart(value) {
        var perc = value.lastIndexOf('%');
        return perc < 0 ? value : value.substr(0, perc);
    }
    function Color(data) {
        if (arguments.length > 1) {
            this[0] = arguments[0];
            this[1] = arguments[1];
            this[2] = arguments[2];
            if (arguments.length > 3) { this[3] = arguments[3]; }
        } else if (data instanceof Color || Array.isArray(data)) {
            this[0] = data[0];
            this[1] = data[1];
            this[2] = data[2];
            this[3] = data[3];
        } else if (typeof data === 'string') {
            data = data.trim();
            if (data[0] === "#") {
                switch (data.length) {
                    case 4:
                        this[0] = parseInt(data[1], 16); this[0] = (this[0] << 4) | this[0];
                        this[1] = parseInt(data[2], 16); this[1] = (this[1] << 4) | this[1];
                        this[2] = parseInt(data[3], 16); this[2] = (this[2] << 4) | this[2];
                        break;
                    case 9:
                        this[3] = parseInt(data.substr(7, 2), 16);
                    //Fall Through
                    case 7:
                        this[0] = parseInt(data.substr(1, 2), 16);
                        this[1] = parseInt(data.substr(3, 2), 16);
                        this[2] = parseInt(data.substr(5, 2), 16);
                        break;
                }
            } else if (data.startsWith("rgb")) {
                var parts = data.substr(data[3] === "a" ? 5 : 4, data.length - (data[3] === "a" ? 6 : 5)).split(',');
                this.r = parsePart(parts[0]);
                this.g = parsePart(parts[1]);
                this.b = parsePart(parts[2]);
                if (parts.length > 3) { this.a = parsePart(parts[3]); }
            }
        }
    }
    Color.prototype = {
        constructor: Color,
        0: 255,
        1: 255,
        2: 255,
        3: 255,
        get r() { return this[0]; },
        set r(value) { this[0] = value == null ? 0 : Math.max(Math.min(parseInt(value), 255), 0); },
        get g() { return this[1]; },
        set g(value) { this[1] = value == null ? 0 : Math.max(Math.min(parseInt(value), 255), 0); },
        get b() { return this[2]; },
        set b(value) { this[2] = value == null ? 0 : Math.max(Math.min(parseInt(value), 255), 0); },
        get a() { return this[3] / 255; },
        set a(value) { this[3] = value == null ? 255 : Math.max(Math.min(value > 1 ? value : parseFloat(value) * 255, 255), 0); },
        get luma() { return .299 * this.r + .587 * this.g + .114 * this.b; },
        get inverted() { return new Color(255 - this[0], 255 - this[1], 255 - this[2], this[3]); },
        toString: function (option) {
            if (option === 16) {
                return '#' + toHex(this.r) + toHex(this.g) + toHex(this.b) + (this[3] === 255 ? '' : toHex(this[3]));
            } else if (option === '%') {
                if (this.a !== 1) {
                    return 'rgba(${this.r / 255 * 100}%, ${this.b / 255 * 100}%, ${this.g / 255 * 100}%, ${this.a / 255})';
                } else {
                    return 'rgb(${this.r / 255 * 100}%, ${this.b / 255 * 100}%, ${this.g / 255 * 100})%';
                }
            } else {
                if (this.a !== 1) {
                    return 'rgba(${this.r}, ${this.b}, ${this.g}, ${this.a})';
                } else {
                    return 'rgb(${this.r}, ${this.b}, ${this.g})';
                }
            }
        }
    };

    return Color;
}());

Ответ 8

Это простая функция, которая инвертирует esadecimal цвет

const invertColor = (col) => {
  const colors = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f']
  let inverseColor = '#'
  col.replace('#','').split('').forEach(i => {
    const index = colors.indexOf(i)
    inverseColor += colors.reverse()[index]
  })
  return inverseColor
}

Пример Codepen