web-dev-qa-db-fra.com

Comment puis-je générer la couleur opposée en fonction de la couleur actuelle?

J'essaie de créer une couleur opposée à la couleur actuelle. Je veux dire si la couleur actuelle est black, alors je dois générer white.

En fait, j'ai un texte (la couleur de ce texte est dynamique, sa couleur peut être faite au hasard). Ce texte est dans un div et je dois définir la couleur opposée de ce texte pour le background-color de div. Je voudrais que le texte soit clair dans div(perspective colorimétrique).

La couleur opposée signifie: Dark/Bright

J'ai la couleur actuelle du texte et je peux le transmettre à cette fonction:

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)

Y a-t-il une idée pour créer la fonction create_opp_color()?

35
stack

UPDATE: code prêt à la production sur GitHub .


Voici comment je le ferais: 

  1. Convertir HEX en RVB
  2. Inverser les composants R, G et B
  3. Reconvertir chaque composant en HEX
  4. Tapotez chaque composant avec des zéros et une sortie.
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);
}

Exemple de sortie: 

 enter image description here

Version avancée: 

Ceci a une option bw qui décidera s'il faut inverser en noir ou blanc; vous obtiendrez ainsi plus de contraste, ce qui est généralement meilleur pour l'œil humain. 

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

Exemple de sortie:

 enter image description here

99
Onur Yıldırım

Un moyen simple d'y parvenir avec CSS:

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

Dans ma compréhension de votre question, par couleur opposée, vous voulez dire une couleur inversée.

InvertedColorComponent = 0xFF - ColorComponent

Donc, pour la couleur rouge (# FF0000), cela signifie: R = 0xFF ou 255 G = 0x00 ou 0 B = 0x00 ou 0

la couleur inversée rouge (# 00FFFF) est:

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

Un autre exemple:

Noir (# 000000) devient blanc (#FFFFFF).

Orange (# FFA500) devient # 005AFF

4
dn Fer

Attention à l'accessibilité (AA/AAA). Le contraste de couleur en soi est inutile. Des couleurs vraiment différentes ne peuvent pas avoir de contraste du tout pour les daltoniens . À mon humble avis, un calcul pour une telle couleur pourrait se présenter comme suit:

(Utilisez "HLS" pour plus de simplicité)

  • Faites pivoter la teinte de 180 ° pour obtenir le contraste de couleur maximal (peut-être inutile)
  • Calculer la différence de luminosité.
  • (Calculer la différence de couleur ... inutile, c'est maximal ou presque)
  • Calculer le rapport de contraste.
  • Si la couleur résultante est conforme, le calcul des exigences se termine, si ce n’est pas le cas, boucle:
    • Si la différence de luminosité n'est pas assez, augmentez ou diminuez la luminosité de couleur calculée (L) d'une certaine valeur ou d'un certain ratio (augmentation ou diminution selon la luminosité de couleur d'origine:> ou <par rapport à la valeur moyenne).
    • Vérifiez si cela répond à vos exigences, si le calcul se termine.
    • si la luminosité peut être augmentée (ou réduite), il n’existe aucune couleur valide pour répondre aux exigences. Essayez simplement en noir et blanc, prenez "la meilleure" de celles-ci (probablement celle avec le plus grand rapport de contraste) et terminez.
4
miguel-svq

Simple et élégant.

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

invertHex('00FF00'); // FF00FF
1
Gerard Lamusse

Basculer simplement la couleur d'arrière-plan en couleur de texte ne fonctionnera pas avec certaines valeurs moyennes, par exemple. 0x808080. J'avais essayé de décaler les valeurs de couleur - (v + 0x80) % 0x100. Voir une démo ici .

Je suis d’accord avec le commentaire de miguel-svq - bien que nous attendions de voir des algorithmes plus détaillés pour chaque étape de calcul. 

1
jason_zhuyx

Fonction pour inverser la couleur de l'élément. Obtient la luminosité de chacun et s'ils sont proches, inverse la couleur du texte. 

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

La couleur "Classe" ci-dessous. Accepte les valeurs hex, rgb, rgba (même avec des pourcentages) et peut également être reproduit. Explorer aura besoin de polyfills pour String.padStart et String.startsWith et la chaîne interpolée dans la méthode toString () devra être modifiée à l'aide de 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
Derek Ziemba