I\'m trying to create a color opposite of current color. I mean if current color is black, then I need to generate white.
Actually I have a text
For Typescript lovers, here what I use:
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;
}
In my understanding of your question, by opposite color you mean inverted color.
InvertedColorComponent = 0xFF - ColorComponent
So for the color red (#FF0000) this means: R = 0xFF or 255 G = 0x00 or 0 B = 0x00 or 0
inverted color red (#00FFFF) is:
R = 0xFF - 0xFF = 0x00 or 255 - 255 = 0
G = 0xFF - 0x00 = 0xFF or 255 - 0 = 255
B = 0xFF - 0x00 = 0xFF or 255 - 0 = 255
Another examples:
Black (#000000) becomes White (#FFFFFF).
Orange (#FFA500) becomes #005AFF
Simple way to achieve this with CSS:
mix-blend-mode: difference;
color:white;
Watch out Accesibility (AA/AAA). Colour contrast by itself is useless. Really different colors can have no contrast at all for colour blind people. IMHO a calculation for such a color could go like this:
(Use "HLS" for simplicity)
Function to Invert Color of Element. Gets the luminosity of each and if they are close, inverts text color.
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();
}
}
The Color "Class" below. Accepts hex, rgb, rgba (even with percents), and can output to either one as well. Explorer will need polyfills for String.padStart and String.startsWith and the interpolated string in the toString() method will need to be modified using concat instead.
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;
}());