javascriptcsscolorshexalpha

In JS, find the color as if it had 0.5 opacity on a white background?


  1. I have an initial color: #3F92DF (blue).

  2. I can reduce its opacity, which leads to a lighter blue (if on a white background): rgba(63, 146, 223, 0.5).

  3. This color with opacity on a white background, if I color pick it, I get: #A5CAEF.

The question is: how in JS, can I find #A5CAEF (3) from #3F92DF (1)? I.e. finding the color as if it had 0.5 opacity on a white background?

I tried to play with the RGB values of the initial color (by increasing them toward 255), but I can't achieve to get the expected color (the one I got were more like turquoise).

var initialColor = "#3F92DF";
var colorWithOpacity = "rgba(63, 146, 223, 0.5)";
var colorWithoutOpacity = "#A5CAEF";

document.getElementById("d1").style.backgroundColor = initialColor;
document.getElementById("d2").style.backgroundColor = colorWithOpacity;
document.getElementById("d3").style.backgroundColor = colorWithoutOpacity;
div {
  width: 100px;
  height: 100px;
  border: solid 1px white;
  float: left;
}
<div id="d1"></div>
<div id="d2"></div>
<div id="d3"></div>


Solution

  • You would need to use color mixing in this case using the standard formula:

    newComponent = floor(oldComponent x alpha + backgroundComponent x (1 - alpha))
    

    The resulting values are typically floored (decimal cut off).

    However, that being said, the actual value depends on a couple of things: one being of course minor rounding errors, but also the system and how the browser handles gamma (the system as to the actual gamma value).

    In general, mixing should always be done in linear color-space (i.e. no gamma applied). For these reasons the actual resulting value could be different from what you obtain on your system and in the browser you're using.

    If the resulting color on the right below differs from the middle color then it indicates that the browser doesn't handle gamma correctly and you would have to decode and re-encode gamma manually (not shown here) for example using sRGB for approximation as we would have to guess the system's actual gamma. The process would then be: decode using inverse gamma, mix, re-encode using gamma.

    In any case, for simplicity you can ignore the above section about gamma. With the formula above applied with no gamma handling which should suffer in most cases in newer browsers we would get:

    var initialColor = "#3F92DF";
    var colorWithOpacity = "rgba(63, 146, 223, 0.5)";
    
    // mix with white background:
    var a = 0.5;
    var r = Math.floor(0x3F * a + 0xff * (1 - a));
    var g = Math.floor(0x92 * a + 0xff * (1 - a));
    var b = Math.floor(0xDF * a + 0xff * (1 - a));
    
    var colorWithoutOpacity = "#" + (r<<16 | g<<8 | b).toString(16);
    
    // show result
    document.getElementById("d1").style.backgroundColor = initialColor;
    document.getElementById("d2").style.backgroundColor = colorWithOpacity;
    document.getElementById("d3").style.backgroundColor = colorWithoutOpacity;
    div {
      width: 100px;
      height: 100px;
      border: solid 1px white;
      float: left;
    }
    <div id="d1"></div><div id="d2"></div><div id="d3"></div>