Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Blend the transparent colour backgrounds of two elements stacked on eachother

Tags:

css

colors

I'm wondering if there is a way to blend two transparent colours laid over eachother, to achieve a predetermined colour.

I have a menu bar. The background colour of the bar is rgb(0, 0, 0, 0.75). The logo on the top-left has a solid red background of #9B0506. You can check it out live at http://www.phoenixwebdev.com.au/about-our-services/ecommerce/. The site is a work in progress.

enter image description here

I want to make this red partially transparent, but achieve the exact same red, visually, when there is white behind the menu bar. The transparent black is behind the red and will affect the colour.

Is there a way to calculate the hex value of the red to achieve this? I don't even know how to achieve this with a single transparent item against a solid background let alone with the black complicating things. I can't eyeball it, as I'm colourblind. Even if I could a mathematical solution would nag at me.

So for my situation I'm looking for a method to solve mystery transparent red colour stacked on rgb(0, 0, 0, 0.75) stacked on white = #9B0506

I had a read about css blending at https://css-tricks.com/basics-css-blend-modes/. However this doesn't do what I'm talking about.

like image 871
James Jones Avatar asked Mar 14 '23 17:03

James Jones


2 Answers

First of all, it's easier to work with colors in rgba than in hexa.

So, your requested result is 9b0506 -> rgb(155, 5, 6)

Next, the formula for any channel is

(f * a) + (b * (1-a))

where f is the foreground value, b the background value for the channel

Applying this formula for the first 2 layers, white and the black with opacity of 0.75, gives

0 * 0.75 + (255 * 0.25) = 63

Thus the base is rgb (63, 63, 63)

Now, the upper layer can have any alpha that you want ... But for the green channel, the expected result is 5, and the contribution of the base layer alone will be 63 * ( 1 - a). Thus, a value of (1 -a ) greater than 0.08 will contribute to the green chanel more than 5, exceding the total result.

Since the values can not be negative, the minimum alpha for the result is (1 - 0.08) = 0.92.

Now, we can calculate the r g b values:

r = (155 - (63 * 0.08)) / 0.92 = 163

b = (6 - (63 * 0.08)) / 0.92 = 1

(the green channel, as dicussed before, is 0)

So the result is rgba (163, 0, 1, 0.92).

If you want higher transparencies, you need to lower the green channel restrictions (or the green channel result goes higher, or the base color goes lower.. this would be achieved making the black layer have higher opacity)

like image 90
vals Avatar answered May 16 '23 06:05

vals


Based on experimentation, I managed to get the exact color using rgba(163,0,2,.92). The below demo renders a box filled with the colours stacked on each other, giving #9B0506 as the overall color.

Also, you don't need to rely on your eyesight to test theoretical values, free applications such as ColorPic and many others allow you to inspect pixels on your screen real time, and get their HEX/RGB color values directly.

I understand that this does not provide any means of calculating it programmatically, but it could serve as a reference point if someone's trying to test an algorithm for this.

.a { z-index: 1; background: white }
.b { z-index: 2; background: rgba(0,0,0,.75) }
.c { z-index: 3; background: rgba(163,0,2,.92) }

.a, .b, .c {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}
<div class="a"></div>
<div class="b"></div>
<div class="c"></div>

As per your request, I've tried reproducing the color with a lower opacity value. I've found that rgba(171,0,0,.85) is very close to the target color and it has slightly more opacity as well. At this point I'm fairly certain the exact color can't be achieved at any other value than that mentioned before, but this should be a close enough approximation that there won't be much of a difference. The demo below has the old color and the new one next to each other, with the color code they produce written on each half.

.a { z-index: 1; background: white }
.b { z-index: 2; background: rgba(0,0,0,.75) }
.c { z-index: 3; background: rgba(163,0,2,.92) }
.d { z-index: 3; background: rgba(171,0,0,.85) }

.a, .b, .c, .d {
  position: absolute;
  top: 0;
  height: 100%;
}
.a, .b {
  left: 0;
  width: 100%;
}
.c, .d {
  color: #fff;
  font-size: 3em;
  font-family: "Consolas", monospace;
  display: flex;
  justify-content: center;
  align-items: center;
  width: 50%;
}
.c { left: 0 }
.d { right: 0 }
<div class="a"></div>
<div class="b"></div>
<div class="c"><span>#9B0506</span></div>
<div class="d"><span>#9B0A0A</span></div>
like image 38
SeinopSys Avatar answered May 16 '23 07:05

SeinopSys