web-dev-qa-db-ja.com

現在の色に従って反対色を生成するにはどうすればよいですか?

現在の色と反対の色を作成しようとしています。現在の色がblackの場合、whiteを生成する必要があります。

実際、私はテキストを持っています(このテキストの色は動的で、その色はランダムに作ることができます)。そのテキストはdivにあり、divの_background-color_に対してそのテキストの反対の色を設定する必要があります。テキストはclear in div(color perspective)にしたいです。

反対の色意味:暗い/明るい

現在のテキストの色があり、この関数に渡すことができます。

_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()関数を作成するアイデアはありますか?

46
stack

[〜#〜] update [〜#〜]:Production-readycode on 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

124

CSSでこれを実現する簡単な方法:

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

シンプルでエレガント。

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

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

あなたの質問の私の理解では、反対の色とは、反転色を意味します。

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になります

4
dn Fer

アクセシビリティ(AA/AAA)に注意してください。色のコントラスト自体は役に立たない。色覚異常の人々にとって、本当に異なる色はまったくコントラストを持たないことがあります。私見では、このような色の計算は次のようになります。

(簡単にするために「HLS」を使用します)

  • (おそらく役に立たない)最大の色のコントラストを得るためにHue180ºを回転させます
  • 輝度差を計算します。
  • (色差の計算...不要、最大またはほぼ)
  • コントラスト比を計算します。
  • 結果の色が適合している場合、要件の計算は終了し、そうでない場合は、ループ:
    • 明るさの差が十分でない場合、計算された色の明度(L)を特定の量または比率で増加または減少させます(元の色の輝度に応じて上下:中間値よりも>または<)
    • 計算が終了する場合、要件を満たしているかどうかを確認します。
    • 明度をこれ以上上げる(または下げる)ことができる場合は、要件を満たす有効な色がありません。黒と白を試して、それらのうち「最高のもの」(おそらくコントラスト比が大きいもの)を取得して終了します。
4
miguel-svq

背景色をテキスト色に単純に反転しても、一部の中間範囲の値では機能しません。 0x808080。私は代わりに色の値をシフトしようとしました-(v + 0x80) % 0x100。デモをご覧ください こちら

miguel-svq -からのコメントに同意しますが、各計算ステップのより詳細なアルゴリズムが表示されることを期待しています。

2
jason_zhuyx

要素の色を反転する関数。それぞれの明度を取得し、近い場合はテキストの色を反転します。

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

下の「クラス」の色。 16進、rgb、rgbaを受け入れ(パーセントを含む)、どちらにも出力できます。 Explorerは String.padStart および String.startsWith のポリフィルを必要とし、代わりにconcatを使用してtoString()メソッドの補間された文字列を変更する必要があります。

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