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
Simply flipping background color to text color won't work with some middle range values, e.g. 0x808080
. I had tried with shifting the color values instead - (v + 0x80) % 0x100
. See a demo here.
Agreeing with the comment from miguel-svq - although expecting to see more detailed algorithms for each calculation step.
It is possible to convert a HEX color using the snippets
function invertColor(color) {
return '#' + ("000000" + (0xFFFFFF ^ parseInt(color.substring(1),16)).toString(16)).slice(-6);
}
This is a simple function that invert an hexadecimal color
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 example
UPDATE: Production-ready code on GitHub.
This is how I'd do it:
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);
}
Example Output:
Advanced Version:
This has a bw
option that will decide whether to invert to black or white; so you'll get more contrast which is generally better for the human eye.
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);
}
Example Output:
Pure CSS implementation of @Onur's answer bw part.
<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>
Simple and elegant.
function invertHex(hex) {
return (Number(`0x1${hex}`) ^ 0xFFFFFF).toString(16).substr(1).toUpperCase()
}
invertHex('00FF00'); // Returns FF00FF