Wie kann ich die entgegengesetzte Farbe entsprechend der aktuellen Farbe erzeugen?

76

Ich versuche, eine Farbe zu erstellen, die der aktuellen Farbe entgegengesetzt ist. Ich meine, wenn die aktuelle Farbe Schwarz ist , muss ich Weiß erzeugen .

Eigentlich habe ich einen Text (die Farbe dieses Textes ist dynamisch, seine Farbe kann zufällig gemacht werden) . Dieser Text ist in a divund ich muss die entgegengesetzte Farbe dieses Textes für das background-colorvon einstellen div. Ich möchte, dass der Text in der (Farbperspektive) klar ist .div

Die entgegengesetzte Farbe bedeutet: Dunkel / Hell

Ich habe die aktuelle Textfarbe und kann sie an diese Funktion übergeben:

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)

Gibt es eine Idee, eine create_opp_color()Funktion zu erstellen ?

Stapel
quelle
Mögliches Duplikat von stackoverflow.com/questions/1664140/…
mplungjan
Dunkel hell? Also ist rot (# FF0000) gegenüber ... Schwarz (# 000000)? Für S / W ist "Achse" einfach, aber der Umgang mit Farben kann schwierig sein, wenn das gewünschte Ziel darin besteht, "Kontrast" zu erhalten, und nicht die "Komplementär" -Farbe oder ähnliches.
Miguel-SVQ
@ miguel-svq Guter Punkt .. Mein Ziel ist es, diesen Text lesbar zu machen (Farbperspektive) . Wenn also die Farbe des Textes rot ist , kann die Farbe des Hintergrunds fast alles schwarz, weiß, blau sein ..
Stapel
Es gibt wirklich gute Module zum Manipulieren von Farben. Schauen Sie sich zB tinycolor ( github.com/bgrins/TinyColor ) an, das eine mostReadableFunktion hat. Ich denke, das ist besser, als selbst einen zu brauen.
Elmar Zander

Antworten:

207

UPDATE : Produktionsbereiter Code auf GitHub .


So würde ich es machen:

  1. Konvertieren Sie HEX in RGB
  2. Invertieren Sie die Komponenten R, G und B.
  3. Konvertieren Sie jede Komponente zurück in HEX
  4. Füllen Sie jede Komponente mit Nullen auf und geben Sie sie aus.
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);
}

Beispielausgabe:

Geben Sie hier die Bildbeschreibung ein

Erweiterte Version:

Dies hat eine bwOption, die entscheidet, ob in Schwarz oder Weiß invertiert werden soll. So erhalten Sie mehr Kontrast, was für das menschliche Auge im Allgemeinen besser ist.

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

Beispielausgabe:

Geben Sie hier die Bildbeschreibung ein

Onur Yıldırım
quelle
Diese Antwort auf die "entgegengesetzte" Frage, bei der die Farbe auf den Vordergrund mit einer Hintergrundfarbe gesetzt wird, ist fast dieselbe. Das Ändern der Geige entsprechend der ursprünglichen Frage kann zu kontrastarmer Farbe (ohne "bw") oder zu rückseitigen und weißen Hintergründen führen . Jsfiddle.net/cffcd5bj/5 . Hope @stack passt es an, um unerwünschte kontrastarme Farbpaare zu vermeiden.
Miguel-SVQ
Sie haben eine Bibliothek einer Funktion erstellt und auf Github gestellt? :-)Cool
Shafizadeh
Ja. Das nennt man Mikrobibliothek. Mehr wartbar, umfasst SRP, etc ..
Onur Yıldırım
Gut. Nur eine Sache, ich habe einen Editor erstellt, der auch die RTL-Richtung unterstützt, und es gibt keinen ähnlichen Editor wie diesen. Wie kann ich es wie eine Bibliothek machen? Mit anderen Worten, wie kann ich es so herunterladen npm install myEditor --save? Wo soll ich meine Codes finden, um über das Internet zugänglich zu sein npm?
Shafizadeh
@Shafizadeh Wenn es ein Endprodukt ist, ist npm nicht der richtige Ort. Wenn es sich um eine JS / Node-Bibliothek / -Komponente handelt, tun Sie dies npm publish. Siehe hierzu die npm-Dokumente.
Onur Yıldırım
27

Einfach und elegant.

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

invertHex('00FF00'); // Returns FF00FF
Gerardlamo
quelle
2
Keine Ahnung, was es tut oder wie es funktioniert, aber es ist in der Tat einfach und elegant :)
Jeremy Thille
Ich würde mich sehr freuen, wenn jemand erklären würde, wie es funktioniert.
Ar2zee
4
@ Ar2 Number(0x1 $ {hex} )Zuerst wird der angegebene hexadezimale Wert (String) verwendet und in HEX konvertiert. ^ 0xFFFFFFAnschließend wird der Wert bitweise ausgeführt, mit 0xFFFFFFdem ich dies jetzt nur so erklären kann, wenn Sie eine Zahl invertieren möchten so schnell wie möglich zB. 3> 7, 8> 2, 1> 9 usw. einfach mit der Zahl mit 10 subtrahieren und absolut. Das macht dieser Teil mit Ausnahme der HEX-Werte. Der Rest besteht im Wesentlichen darin, den ersten Wert zu formatieren und zu löschen, der einen Überlauf der Gleichung darstellt.
Gerardlamo
Wirklich schön und einfach, aber beachten Sie, dass es "über die Mitte der Farbe spiegelt", so dass Farben in der Nähe der Mitte eine Farbe erhalten, die sehr nahe daran liegt. zB invertHex ('808080'); erzeugt '7F7F7F', das fast die gleiche Farbe hat.
MoonLite
18

Einfacher Weg, um dies mit CSS zu erreichen:

mix-blend-mode: difference;
color:white;
Raphadko
quelle
2
Ein Hinweis zur Vorsicht: Der Mix-Blend-Modus wird derzeit unter anderem von! E oder Microsoft Edge nicht unterstützt. Je nach Anwendungsfall ist es unwahrscheinlich, dass er ordnungsgemäß fehlschlägt.
Dan Devine
11

Reine CSS-Implementierung von @ Onurs Antwort bw Teil.

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

Jamesgt
quelle
4

Achten Sie auf die Zugänglichkeit (AA / AAA). Farbkontrast an sich ist nutzlos. Wirklich unterschiedliche Farben können für farbenblinde Menschen überhaupt keinen Kontrast haben. IMHO könnte eine Berechnung für eine solche Farbe so aussehen:

(Verwenden Sie der Einfachheit halber "HLS")

  • Drehen Sie den Farbton um 180 °, um den (möglicherweise unbrauchbaren) maximalen Farbkontrast zu erhalten
  • Helligkeitsunterschied berechnen.
  • (Farbdifferenz berechnen ... unnötig, maximal oder fast)
  • Kontrastverhältnis berechnen.
  • Wenn die resultierende Farbe der Anforderungsberechnung entspricht, endet die Schleife: Wenn nicht:
    • Wenn der Helligkeitsunterschied nicht ausreicht, erhöhen oder verringern Sie die berechnete Farbhelligkeit (L) um einen bestimmten Betrag oder ein bestimmtes Verhältnis (nach oben oder unten, abhängig von der ursprünglichen Farbhelligkeit:> oder <als der Mittelwert).
    • Überprüfen Sie, ob es Ihren Anforderungen entspricht, wenn die Berechnung endet.
    • Wenn die Leuchtkraft nicht mehr erhöht (oder verringert) werden kann, gibt es keine gültige Farbe, um die Anforderungen zu erfüllen. Versuchen Sie es einfach mit Schwarzweiß, nehmen Sie "die beste" (wahrscheinlich die mit dem größeren Kontrastverhältnis) und beenden Sie sie.
miguel-svq
quelle
4

Nach meinem Verständnis Ihrer Frage meinen Sie mit entgegengesetzter Farbe die umgekehrte Farbe.

InvertedColorComponent = 0xFF - ColorComponent

Für die Farbe Rot (# FF0000) bedeutet dies also: R = 0xFF oder 255 G = 0x00 oder 0 B = 0x00 oder 0

Die umgekehrte Farbe Rot (# 00FFFF) ist:

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

Ein weiteres Beispiel:

Schwarz (# 000000) wird Weiß (#FFFFFF).

Orange (# FFA500) wird zu # 005AFF

DigiLive
quelle
Ich hätte auch "invers" verwendet, aber denken Sie daran, dass "entgegengesetzt" auch "entgegengesetzt im Farbkreis" bedeuten kann.
Ingenieur
2

Das einfache Umblättern der Hintergrundfarbe in die Textfarbe funktioniert bei einigen Werten im mittleren Bereich nicht, z 0x808080. Ich hatte stattdessen versucht, die Farbwerte zu verschieben - (v + 0x80) % 0x100. Hier finden Sie eine Demo hier .

Ich stimme dem Kommentar von miguel-svq zu - erwarte jedoch detailliertere Algorithmen für jeden Berechnungsschritt.

jason_zhuyx
quelle
2

Dies ist eine einfache Funktion, die eine hexadezimale Farbe invertiert

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 Beispiel

Supah
quelle
1

Funktion zum Umkehren der Farbe des Elements. Ruft die Helligkeit jedes einzelnen ab und invertiert die Textfarbe, wenn sie nahe beieinander liegen.

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

Die Farbe "Klasse" unten. Akzeptiert hex, rgb, rgba (auch mit Prozenten) und kann auch an beide ausgegeben werden. Der Explorer benötigt Polyfills für String.padStart und String.startsWith, und der interpolierte String in der toString () -Methode muss stattdessen mit concat geändert werden.

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;
}());
Derek Ziemba
quelle
0

Für Typescript-Liebhaber, hier was ich benutze:

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;
}
abd0991
quelle
0

Mit den Snippets kann eine HEX- Farbe konvertiert werden

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