Як я можу створити протилежний колір відповідно до поточного кольору?


81

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

Насправді у мене є текст (колір цього тексту динамічний, його можна зробити навмання) . Цей текст в 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()функцію?


Можливий дублікат stackoverflow.com/questions/1664140 / ...
mplungjan

Темний / Яскравий? Тож червоний (# FF0000) навпроти - це ... Чорний (# 000000)? Для Ч / Б "вісь" проста, але мати справу з кольорами може бути складно, якщо бажаною метою є отримання "контрасту", а не "доповнення" кольору чи чогось подібного.
miguel-svq

@ miguel-svq Хороший момент. Моя мета - зробити текст читабельним (кольорова перспектива) , тому, якщо колір тексту червоний , то колір тла майже може бути будь-яким чорним, білим, синім ..
стек

Є справді хороші модулі для маніпулювання кольорами. Погляньте, наприклад, на tinycolor ( github.com/bgrins/TinyColor ), який має mostReadableфункцію. Я думаю, що це краще, ніж варити самостійно.
Ельмар Зандер,

Відповіді:


216

ОНОВЛЕННЯ : готовий до виробництва код на 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);
}

Приклад результату:

введіть тут опис зображення

Розширена версія:

Тут є 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);
}

Приклад результату:

введіть тут опис зображення


Ця відповідь на "протилежне" питання, задаючи колір переднього плану кольором тла, який майже однаковий. Зміна скрипки відповідно до вихідного питання може призвести до низькоконтрастного кольору (без "bw") або до заднього та білого фонів jsfiddle.net/cffcd5bj/5 . Сподіваюся @stack адаптувати його, щоб уникнути небажаних низькоконтрастних кольорових пар.
miguel-svq

Ви створили бібліотеку функції і поставили її на github? :-)Круто
Шафізаде,

1
Так. Це називається мікробібліотекою. Більш ремонтопридатний, охоплює SRP тощо.
Onur Yıldırım

Добре .. Тільки одне, я створив редактор, який також підтримує напрямок rtl, і подібного редактора подібного немає. Як я можу зробити це як бібліотеку? Іншими словами, як я можу зробити його таким для завантаження npm install myEditor --save? Де я повинен знаходити свої коди, щоб їх можна було отримати через Інтернет за допомогою npm?
Шафізаде

@Shafizadeh, якщо це кінцевий продукт, npm тут не місце. Якщо це бібліотека JS / Node / компонент do npm publish. Для цього дивіться документи npm.
Онур Йылдирим

30

Просто і елегантно.

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

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

2
Не уявляю, що це робить і як працює, але це дійсно просто і елегантно :)
Jeremy Thille

Я був би дуже радий, якби хтось пояснив, як це працює.
Ar2zee

4
@ Ar2 Number(0x1 $ {hex} )Спочатку він приймає задане значення hex (рядок) і перетворює його в HEX, ^ 0xFFFFFFпотім виконує побічне виконання цього значення, з 0xFFFFFFяким я можу пояснити ось так, якщо ви хочете інвертувати число якомога швидше, напр. 3> 7, 8> 2, 1> 9 тощо просто віднімаємо з числом 10 і абсолютуємо його. Це те, що робить ця частина, крім значень HEX. Решта - це в основному форматування та скидання першого значення, яке є переповненням рівняння.
Жерардламо,

Дійсно приємно та просто, але зауважте, що він "відображає середину кольору", тому кольори, близькі до середини, отримують колір, дуже близький до нього. наприклад invertHex ('808080'); виробляє '7F7F7F', який є майже однаковим кольором.
MoonLite

18

Простий спосіб досягти цього за допомогою CSS:

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

2
Застереження: режим змішування-змішування наразі не підтримується! E або Microsoft Edge, серед іншого, і, залежно від вашого варіанту використання, навряд чи вийде елегантний збій.
Ден Дівайн

11

Чиста реалізація CSS з @ Onur в відповідь м.т. частини.

  <input type="color" oninput="['--r','--g','--b'].forEach((k,i)=>this.nextElementSibling.style.setProperty(k,parseInt(event.target.value.slice(1+i*2,3+i*2),16)))" />
 
  <div style="--r: 0; --g: 0; --b: 0; --c: calc(-1 * ((var(--r) * 0.299 + var(--g) * 0.587 + var(--b) * 0.114) - 186) * 255)">
    <div style="background-color: rgb(var(--r), var(--g), var(--b)); color: rgb(var(--c), var(--c), var(--c))">Test</div>
  </div>


5

Слідкуйте за доступністю (AA / AAA). Кольоровий контраст сам по собі марний. Дійсно різні кольори можуть взагалі не мати контрасту для дальтоніків. ІМХО розрахунок для такого кольору може йти так:

(Використовуйте "HLS" для простоти)

  • Поверніть відтінок на 180º, щоб отримати (можливо, марний) максимальний контраст кольору
  • Обчислити різницю яскравості.
  • (Обчислити різницю кольорів ... непотрібно, воно максимальне або майже)
  • Обчисліть коефіцієнт контрастності.
  • Якщо отриманий колір відповідає вимогам, обчислення закінчується, якщо ні, цикл:
    • Якщо різниця яскравості не є достатньою, збільште або зменште обчислену яскравість кольору (L) на певну величину або співвідношення (вгору або вниз залежно від вихідної яскравості кольору:> або <ніж середнє значення)
    • Перевірте, чи відповідає він вашим вимогам, чи обчислення закінчується.
    • якщо світність можна більше збільшувати (або зменшувати), немає жодного дійсного кольору, щоб відповідати вимогам, просто спробуйте чорно-білий, візьміть "найкращий" із них (можливо, той, що має більший коефіцієнт контрастності) і закінчіть.

4

Наскільки я розумію ваше запитання, під протилежним кольором ви маєте на увазі перевернутий колір.

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


Я б також використовував "зворотний", але пам'ятайте, що "протилежний" може означати також "протилежний на кольоровому колі".
інженер

2

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

Погоджуючись з коментарем від miguel-svq - хоча очікуємо побачити більш детальні алгоритми для кожного кроку розрахунку.


2

Це проста функція, яка інвертує шістнадцятковий колір

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


1

Функція інвертування кольору елемента. Отримує світність кожного, і якщо вони близькі, інвертує колір тексту.

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

0

Для любителів машинопису ось що я використовую:

invertHex(hex: string) {
  if (hex.indexOf('#') === 0) {
    hex = hex.slice(1);
  }

  if (hex.length != 6) {
    console.warn('Hex color must be six hex numbers in length.');
    return '#' + hex;
  }

  hex = hex.toUpperCase();
  const splitNum = hex.split('');
  let resultNum = '';
  const simpleNum = 'FEDCBA9876'.split('');
  const complexNum = {
    A: '5', B: '4', C: '3', D: '2', E: '1', F: '0'
  };

  for (let i = 0; i < 6; i++) {
    if (!isNaN(Number(splitNum[i]))) {
      resultNum += simpleNum[splitNum[i]];
    } else if (complexNum[splitNum[i]]) {
      resultNum += complexNum[splitNum[i]];
    } else {
      console.warn('Hex colors must only include hex numbers 0-9, and A-F');
      return '#' + hex;
    }
  }

  return '#' + resultNum;
}

0

Перетворити шістнадцятковий колір можна за допомогою фрагментів

function invertColor(color) {
      return '#' + ("000000" + (0xFFFFFF ^ parseInt(color.substring(1),16)).toString(16)).slice(-6);
  }

0

Варіанти відповіді Онура на Python:

def hex_to_rgb(value):
    value = value.lstrip('#')
    lv = len(value)
    return tuple(int(value[i:i + lv // 3], 16) for i in range(0, lv, lv // 3))

def invertColor(color, bw=False):
    # strip the # from the beginning
    color = color.lstrip('#')

    # convert the string into hex
    color = int(color, 16)

    # invert the three bytes
    # as good as substracting each of RGB component by 255(FF)
    comp_color = 0xFFFFFF ^ color

    # convert the color back to hex by prefixing a #
    comp_color = "#%06X" % comp_color

    rgb_color = hex_to_rgb(comp_color)
    
    if (bw):
        # http://stackoverflow.com/a/3943023/112731
        bw_value = rgb_color[0]*0.299 + rgb_color[0]*0.587 + rgb_color[0]*0.114
        if (bw_value>186):
            comp_color = "#FFFFFF"
        else:
            comp_color = "#000000"

    # return the result
    return comp_color

color = "#fffff1"

print invertColor(color, bw=True)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.