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.
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.
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)
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>
have you tried with gradient for background
background: linear-gradient(direction, color-stop1, color- stop2, ...);
Not sure if it's possible to calculate it. Though we can bruteforce it :D
Consider a canvas element A and canvas element B.
User can input color A(#9B0506) and color B(rgb(0, 0, 0, 0.75)) then a js loop will try every single color(rgba) on top of color B til and output the closest match to color A.
I'll try to make a program in jsfiddle.
Related
I am trying to make the background color of a row change on hover with only the area of the cursor changing color/being highlighted.
I have a white background color set, and would like to have the area of the cursor highlighted with a yellow feathered circle when hovering over the background.
I can't seem to find the proper code for it, but only finding codes to change the complete background on hover.
Is this something that's possible to do in CSS?
.vc_row {
-webkit-transition:all 1s;
transition:all 1s;
}
.vc_row:hover {
background: -webkit-gradient(
radial, 500 25%, 20, 500 25%, 40, from(#faf9f4), to(#cef230)
);
}
Even through my predisposition to using JavaScript (it is where my skills lie), I believe you can't just do this in CSS, but also need JavaScript to do this. There might be a way, but I don't know it, and I am curious for someone else to answer with a magical full CSS solution and blow our minds. :D
For one approach of doing this, you need to use ::after to create the hover-element inside the row. You can then use CSS variables to pass your mouse position (gathered through JavaScript) into the hover-element, making it track the mouse position. Here is an example:
<!-- HTML -->
<div class="row">
</div>
/* CSS */
.row {
width: 300px;
height: 300px;
margin: 30px 30px;
position: relative;
overflow: hidden;
background: white;
}
.row::after {
content: "";
position: absolute;
top: calc(var(--y, 0) * 1px - 50px);
left: calc(var(--x, 0) * 1px - 50px);
width: 100px;
height: 100px;
opacity: 0;
background: radial-gradient(#cef230, #ffffff00 80%);
transition: opacity 1s;
}
.row:hover::after {
opacity: 1;
}
// JavaScript
const element = document.querySelector(".row");
element.addEventListener("mousemove", (e) => {
const { x, y } = element.getBoundingClientRect();
element.style.setProperty("--x", e.clientX - x);
element.style.setProperty("--y", e.clientY - y);
});
Key elements are the ::after to create the hover-element, the use of position: absolute; to allow for "top" and "left" attributes to position the hover-element, and applying overflow: hidden; to the row: in my testing the hover-element kept the mouse-move event firing even outside the row, unless overflow was hidden.
On my project, users have the possibility to select an accent color for their profile page (var(--color-main)). Is there a possibility to create a gradient background using only that main color, for example by using the main color + a % applied to this color to make it darker (or lighter) and use this as second color to make the gradient. Is that possible?
.TabsHeader-module--wrapper--BMiDm .TabsHeader-module--bgBlock--qXkLH {
background-color: var(--color-main);
border-radius: 0 0 20rem 0;
height: 21.6rem;
position: absolute;
top: 0;
width: 100%;
}
This is an example with two custom properties defined:
--color is your main color
--alpha is the opacity quota (0-1) applied to --color for having the second gradient color
The background-image style attribute is set using a gradient shading from --color to --color(alpha)
That was made possible with rgba to define colors MDN
:root {
--color: 240, 0, 0;
--alpha: .5;
}
.gradient{
background-image:
linear-gradient(
to right,
rgba(var(--color), 1),
rgba(var(--color), var(--alpha))
);
width: 100%;
height: 200px;
text-align: center;
}
<div class="gradient"></div>
I have found that you can use variable colors with opacity control only if you give the value as RGB decimals, which are 3 numbers (e.g. 240, 240, 240). And later you can give it a 4th value, which will control the opacity of the color (i.e. will make it darker or lighter).
Here is an example:
:root {
--color: 190,190,190;
}
div {
background: linear-gradient(to right, rgba(var(--color), 0.8), rgba(var(--color), 0.3));
}
Thanks to Thankful Teira from codegrepper.com
I found another question on SO about rgb vs rgba that is very similar, but it's missing an answer about the usage of rgb with opacity.
I know the difference between both – rgba is just rgb but with alpha for opacity. The thing is, it has been months or even years that I am using rgb with opacity values. It has always worked for me. rgb(255, 0, 255, 0.5)
Makes me wonder if there's an advantage to use one if both works the same? rgb has been there longer so browser compatibility I suppose is better? Also I was told by a coworker that rgba value will only work for background colors, but then again, I did some tests in codepen and it works on Edge and Chrome.
(I know both are Chrome based both these are the one I have downloaded)
Related question : What are differences between RGB vs RGBA other than 'opacity'
Here is my snippet
/* texts */
.one {
color: rgba(255, 200, 0, .5);
}
.oneFive {
color: rgb(255, 200, 0, .5);
}
/* backgrounds */
.two {
background-color: rgb(255, 0, 255, 0.5);
}
.three {
background-color: rgba(0, 0, 255, 0.5);
}
/* */
/* settings */
/* */
.two, .three {
height: 50px;
}
.two {
margin-top: 30px;
}
.two, .three, .zero {
color: white;
}
.one, .oneFive {
height: 50px;
font-weight: bold;
font-size: 2em;
padding-left: 40px;
padding-top: 20px;
}
body {
background-color: #444;
color: white;
}
.zero {
background-color: darkgreen;
width: 300px;
height: 350px;
position: absolute;
top: 35px;
z-index: -1;
}
dark grey 100% opacity
<div class="zero">dark green 100% opacity</div>
<div class="oneFive">rgb yellow text 70% opacity</div>
<div class="one">rgba yellow text 70% opacity</div>
<div class="two">rgb 50% background opacity</div>
<div class="three">rgba 50% background opacity</div>
Answer as requested:
I'm going to go out on a limb and say it's the browser translating what is essentially an "incorrect" value set in rgb with an opacity value.
If you look in the browser dev tools under the computed tab, you'll notice that the rgb values are computed to rgba (at least in Firefox).
I'm thinking that any browser that supports CSS3 will "fix" the property.
Also I was told by a coworker that rgba value will only work for background colors: Your coworker is wrong.
rgb has been there longer so browser compatibility I suppose is better? I wouldn't say that. You'll never notice a performance hit, but you'll make your browser do less work if it doesn't have to "fix" your incorrect values being passed to the rgb set. Update: rgba is an alias for rgb, so it's really not fixing anything, it's simply passing to rgb anyway.
Here is some documentation on rgb and rgba - specifically the aliasing of the functions:
https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#rgb_colors
Makes me wonder if there's an advantage to use one if both works the same?
It's not about advantage but this is something new defined in the Specification
rgb() and rgba(), and hsl() and hsla() are now aliases of each other (all of them have an optional alpha). ref
And
Also for legacy reasons, an rgba() function also exists, with an identical grammar and behavior to rgb(). ref
So rgba() is meant to disappear and only rgb() should be used but this won't happen because it will create a lot of issues and conflit so rgba() will still be considered and will simply have the same syntax as rgb()
Also note that the new syntax no more contain comma:
rgb() = rgb( <percentage>{3} [ / <alpha-value> ]? ) |
rgb( <number>{3} [ / <alpha-value> ]? )
<alpha-value> = <number> | <percentage>
You should write rgb(255 65 40) or rgb(255 65 40 / 80%) for example but still for legacy reasons the comma syntax is still supported:
For legacy reasons, rgb() also supports an alternate syntax that separates all of its arguments with commas:
I am wondering if anyone knows how exactly text color (or background-color) is animated using CSS transitions. Lets say we have:
.box {
background-color: red;
transition: background-color 2s ease-out;
}
.box:hover {
background-color: green;
}
So during two seconds of hovering the box will change color from red to green going through some brownish color.
What I want to know is what values are exactly being manipulated and how. Is it rgba? HEX? If so, how are these values changing? Going from rgb(255, 0, 0) through rgb(123, 122, 0) to rgb(0, 255, 0) linearly or something?
My main aim (apart from simple curiosity) is to be able to control the progress of a color change, stating that at time A the color should be 30% of the change, while at time B it should have 70% of the new color.
Hard to google as I just keep getting tutorials for CSS animations...
edit
To clarify I want to be able to stop the animation at a certain point/color depending on the app state, not just cycle through. The only way to do this will be if I know how the browser implementations work.
The interpolation between two colors during a transtion or an animation is done the same way like creating a gradient between the same two colors. The easiest way to understand it is to draw the gradient.
Here is an example to illustrate:
.box {
background-color: red;
width:20px;
height:50px;
margin-top:-5px;
animation: change 2s infinite alternate linear;
}
.container {
height:50px;
width:400px;
background:linear-gradient(to right,red,green);
}
#keyframes change {
to {
background-color:green;
transform:translateX(380px);
}
}
<div class="container">
</div>
<div class="box">
</div>
If you pick some colors you will see that the interpolation is quite easy and it's done in the RGB space. First we write our both color using rgb. In our case we have:
red = rgb(255,0,0)
green = rgb(0,128,0) /* and not rgb(0,255,0) */
Then we simply interpolate each color alone (R, G and B) to obtain something like:
rgb(255,0,0)
rgb(254,2,0)
rgb(253,4,0)
rgb(252,6,0)
....
rgb(1,126,0)
rgb(0,128,0)
The below is a simple approximation but to be more accurate you need to either consider the duration or the size of the gradient. If we consider our gradient, we have defined 400px of width so we will have 400 different colors for each pixel. For the red we are moving from 255 to 0 so we have 256 values that we divide by 400 thus our step will be 0.64. For the green we will have a step of 0.3225.
The color of each pixel will be rgb(255 - n*0.64,0 + n*0.3225,0) where n is the pixel number from 1 to 400.
We do the same logic for the transition but we consider the time instead of width. We have 2s and if we suppose that the browser draw each 0.01s, we will need 200 values and so on ..
In addition, you should consider the rounding of the values which may not be the same for each browser. You should also know the granularity when it comes to times. I considered 0.01s as an example to illustrate but I don't know the real value. Most important, you should know the rgb value for each color defined by a keyword. A green may not be the same across browsers.
To illustrate the above calculation here is an example where I will draw the gradient based on both color and it will reflect the transition/animation
var sR = (250 - 10) / 400;
var sG = (30 - 80) / 400;
var sB = (150 - 255) / 400;
var canvas = document.querySelector('.container');
var ctx = canvas.getContext('2d');
for (var i = 0; i <= 400; i++) {
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(i, 0);
ctx.lineTo(i, 50);
ctx.strokeStyle = "rgb(" + (250 - i * sR) + "," + (30 - i * sG) + "," + (150 - i * sB) + ")";
ctx.stroke();
}
.box {
background-color: rgb(250, 30, 150);
width: 20px;
height: 50px;
margin-top: -10px;
animation: change 2s infinite alternate linear;
}
#keyframes change {
to {
background-color: rgb(10, 80, 255);
transform: translateX(380px);
}
}
<canvas class="container" width="400" height="50"></canvas>
<div class="box">
</div>
Edit:
Browser implementation varies depending on the browser. Since you clarified that your main aim is to be able to control the progress of a color change, I addressed that in this answer below with a solution.
Beyond that, you may want to take a look at this CSS property, transition-timing-function.
Futhermore, a quote from MDN on Using CSS transitions:
With CSS transitions enabled, changes occur at time intervals that follow an acceleration curve, all of which can be customized.
Animations that involve transitioning between two states are often called implicit transitions as the states in between the start and final states are implicitly defined by the browser.
Original answer:
It's true that CSS animations are one way to go here. Besides that you might use javascript for this kind of fine-tuned control.
So for example, you can set up an animation like this:
#keyframes specialFade {
0% {
background-color: rgb(255, 0, 0);
}
20% {
background-color: rgb(175, 80, 0)
}
50% {
background-color: rgb(80, 175, 0)
}
100% {
background-color: rgb(0, 255, 0)
}
}
I calculated these rgb values myself, based on what I'd call "about 30% and 70%" of the color change.
In a 5 second animation-duration, the 20%, 50%, etc would refer to the 1 second mark and 2.5 second mark respectively. No way to set up specific timing in CSS (hence my mention of JS above).
I want to change the highlight color used by pdf.js
https://mozilla.github.io/pdf.js/web/viewer.html
Press Ctrl + F and find any word any in thid doc
I can do that by changing color in pdf js's style file.
.textLayer .highlight.selected {
background-color: rgb(0, 100, 0);
}
I would like this color to be non-transparent. if you see highlighted words is transparent.
I get the reason for making it transparent is so that underlying pdf content is visible. Pdf.js just renders transparent text over the original pdf content. It uses this transparent text for searching and highlighting.
Is there anyway I can highlight the word in a solid color?
In viewer.css the class textLayer, you can change the opacity. To make it solid, you can remove opacity or set to 1, but you will not be able to see the text. I find 0.4 looks pretty good
.textLayer {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
overflow: hidden;
opacity: 1; /* 0.4 looks nice, but 1 answers your question */
}