How is CSS color animated - css

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).

Related

What is the difference between rgb() and rgba() opacity?

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:

Create a perfect circle with CSS [duplicate]

This question already has answers here:
How does this CSS produce a circle?
(5 answers)
Closed 4 years ago.
How about friends, I'm new to the topic of CSS. I am trying to perform to pulse effect as you can see in this image.
I would like my menu icon (icon next to word "Home") to have a similar animation.
My problem is that I do not know how to achieve a perfect circle where to achieve this animation. This is my current result:
What I can do?
this is my code:
https://multi-level-side-menu-4bj1tj.stackblitz.io
ion-header button[ion-button].bar-buttons {
border-radius: 10px;
background: transparent;
box-shadow: 0 0 0 0 rgba(90, 153, 212, 0.5);
animation: pulse 1.5s infinite;
}
ion-header button[ion-button].bar-buttons:hover {
animation: none;
}
#keyframes pulse {
0% {
transform: scale(0.9);
}
70% {
transform: scale(1);
box-shadow: 0 1 0 10px rgba(90, 153, 212, 0);
}
100% {
transform: scale(0.9);
box-shadow: 0 0 0 0 rgba(90, 153, 212, 0);
}
}
I share the source code that I am doing, if you want to edit something, you must modify the app/app.css file, to see in real time.
thank you!
In order to achieve a perfectly round shape you'll need to have perfect square to begin with. So, for instance, your button will need to have dimensions like width: 32px; height: 32px. To turn a square into a circle you'll have to apply a border radius of 50% e.g. border-radius: 50%.
To create a perfect circle you need equal width and height as well as border-radius of 50%
width: 50px;
height: 50px;
border-radius: 50%;
The animation you reference is part of Google's Material Design, this is a very sophisticated CSS animation. It is possible to recreate it from scratch but that will take time.
The core of what you need is the circle to grow in size and a box-shadow to pulse out.
I've created a simplified version here
https://codepen.io/suth_a/pen/NBVNXE?editors=1100
you create animations by defining them with #keyframes name
#keyframes pulse{
100%{
box-shadow: 0 0 20px 3px #5a99d4;
transform: scale(1.2);
}
}
on hovering the animation is initiated
div:hover{
animation: pulse 1s ease-in-out infinite alternate;
}
pulse - is the name of the animation I created
1s - is the length of the animation
ease-in-out - is the easing function - https://css-tricks.com/ease-out-in-ease-in-out
infinite - tells the browser to repeat the animation indefinitely
alternate - tells the browser that at the end of each animation it should begin from the ending and work back to the beginning, that way
the animation looks smooth.
You can take my animation and work on it until you get something closer to what you want but if you're really set on that exact animation then add material design to your project and you can create buttons like this in no time
https://materializecss.com/getting-started.html
<a class="btn-floating pulse"><i class="material-icons">menu</i></a>
https://materializecss.com/pulse.html
Add the following css properties to the pulse icon (circle).
height:40px; width:40px; border-radius:50%
If the height and width don't suit your needs then you can increase them proportionally so that they are always equal to each other.

How to use cubic-bezier to change the speed of a keyframe animation?

I am trying to create a #keyframe animation to bring a box up from the bottom of the screen and then have it bounce off the top of the body of the HTML document. The method that I used to do this doesn't allow you to change the speed during the duration of the animation which intern doesn't make it look very realistic (See Code Below).
I have found an answer to my question the only problem is that I really don't understand how cubic-bezier is creating the animation. I would like to make sense of what the code is doing before I go ahead and just slap it into my project. So, yeah I guess the title of this question shouldn't be "How to use cubic-bezier to change the speed of a keyframe animation?" but "How does the cubic-bezier work and how is it working in this instance". I would absolutely appreciate it if someone could explain this a little and even give me a simple example of code to follow and understand.
Note: I have looked at Mozila Developer Network at this property and still don't fully understand how it works in or out of a #keyframe animation.
document.querySelector('#button').addEventListener('click', function() {
document.querySelector('#square').className = 'bounce';
document.querySelector('#square').style.display = 'block';
});
document.querySelector('#square').addEventListener('animationend', function(e) {
if (e.animationName == 'animate-in') {
document.querySelector('#square').removeAttribute('class');
}
});
#button {
display: block;
position: absolute;
left: 75px;
}
#square {
display: none;
position: relative;
width: 50px;
height: 50px;
background-color: tomato;
animation-fill-mode: forwards;
}
.bounce {
animation: animate-in 1.5s;
}
#keyframes animate-in {
20%,
50%,
80%,
100% {
transform: translateY(0);
}
40% {
transform: translateY(-30px);
}
60% {
transform: translateY(-15px);
}
0% {
transform: translateY(100vh);
}
}
<input type="button" id="button" value="Run Animation">
<div id="square"></div>
You may find by playing with the box on here https://matthewlein.com/ceaser/ that you get a decent understanding of cubic bezier.
Imagine a box. If you place a marker on:
bottom left corner of the box, it has a value of (0)
top right corner of the box, it has a value of (1)
But there are 4 values for cubic bezier e.g....
cubic-bezier(0.755, 0.050, 0.855, 0.060);
That is because there are in effect two markers (or start points).
The first two values are obtained from a starting point of the bottom left corner of the box, of which the value is (0,0). As you move the marker to the right, the first value changes, e.g.(0.755, 0.000). As you move the marker up the second value changes e.g.(0.755, 0.050).
The second two values are obtained by a starting point of top right of a box, of which the value is (1,1). As you move the marker to the left, the third value changes, e.g.(0.855, 1.000). As you move the marker down the fourth value changes e.g.(0.855, 0.060).
Values one and three (left and right) control the time, values two and four (up and down) control the animation.
Putting these values together makes (0.755, 0.050, 0.855, 0.060);
I have included a diagram (it does not show the same values as the example above) but should help to understand the information above.

Blend the transparent colour backgrounds of two elements stacked on eachother

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.

Opacity of div's background without affecting contained element in IE 8?

I want to set Opacity of div's background without affecting contained element in IE 8. have a any solution and don't answer to set 1 X 1 .png image and set opacity of that image because I am using dynamic opacity and color admin can change that
I used that but not working in IE 8
#alpha {
filter: alpha(opacity=30);
-moz-opacity: 0.3;
-khtml-opacity: 0.3;
opacity: 0.3;
}
and
rgba(0,0,0,0.3)
also.
The opacity style affects the whole element and everything within it. The correct answer to this is to use an rgba background colour instead.
The CSS is fairly simple:
.myelement {
background: rgba(200, 54, 54, 0.5);
}
...where the first three numbers are the red, green and blue values for your background colour, and the fourth is the 'alpha' channel value, which works the same way as the opacity value.
See this page for more info: http://css-tricks.com/rgba-browser-support/
The down-side, is that this doesn't work in IE8 or lower. The page I linked above also lists a few other browsers it doesn't work in, but they're all very old by now; all browsers in current use except IE6/7/8 will work with rgba colours.
The good news is that you can force IE to work with this as well, using a hack called CSS3Pie. CSS3Pie adds a number of modern CSS3 features to older versions of IE, including rgba background colours.
To use CSS3Pie for backgrounds, you need to add a specific -pie-background declaration to your CSS, as well as the PIE behavior style, so your stylesheet would end up looking like this:
.myelement {
background: rgba(200, 54, 54, 0.5);
-pie-background: rgba(200, 54, 54, 0.5);
behavior: url(PIE.htc);
}
[EDIT]
For what it's worth, as others have mentioned, you can use IE's filter style, with the gradient keyword. The CSS3Pie solution does actually use this same technique behind the scenes, but removes the need for you to mess around directly with IE's filters, so your stylesheets are much cleaner. (it also adds a whole bunch of other nice features too, but that's not relevant to this discussion)
it's simple only you have do is to give
background: rgba(0,0,0,0.3)
& for IE use this filter
background: transparent;
zoom: 1;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#4C000000,endColorstr=#4C000000); /* IE 6 & 7 */
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#4C000000,endColorstr=#4C000000)"; /* IE8 */
you can generate your rgba filter from here http://kimili.com/journal/rgba-hsla-css-generator-for-internet-explorer/
opacity on parent element sets it for the whole sub DOM tree
You can't really set opacity for certain element that wouldn't cascade to descendants as well. That's not how CSS opacity works I'm afraid.
What you can do is to have two sibling elements in one container and set transparent one's positioning:
<div id="container">
<div id="transparent"></div>
<div id="content"></div>
</div>
then you have to set transparent position: absolute/relative so its content sibling will be rendered over it.
rgba can do background transparency of coloured backgrounds
rgba colour setting on element's background-color will of course work, but it will limit you to only use colour as background. No images I'm afraid. You can of course use CSS3 gradients though if you provide gradient stop colours in rgba. That works as well.
But be advised that rgba may not be supported by your required browsers.
Alert-free modal dialog functionality
But if you're after some kind of masking the whole page, this is usually done by adding a separate div with this set of styles:
position: fixed;
width: 100%;
height: 100%;
z-index: 1000; /* some high enough value so it will render on top */
opacity: .5;
filter: alpha(opacity=50);
Then when you display the content it should have a higher z-index. But these two elements are not related in terms of siblings or anything. They're just displayed as they should be. One over the other.
Try setting the z-index higher on the contained element.
What about this approach:
<head>
<style type="text/css">
div.gradient {
color: #000000;
width: 800px;
height: 200px;
}
div.gradient:after {
background: url(SOME_BACKGROUND);
background-size: cover;
content:'';
position:absolute;
top:0;
left:0;
width:inherit;
height:inherit;
opacity:0.1;
}
</style>
</head>
<body>
<div class="gradient">Text</div>
</body>
It affects the whole child divs when you use the opacity feature with positions other than absolute. So another way to achieve it not to put divs inside each other and then use the position absolute for the divs. Dont use any background color for the upper div.
Maybe there's a more simple answer, try to add any background color you like to the code, like background-color: #fff;
#alpha {
background-color: #fff;
opacity: 0.8;
filter: alpha(opacity=80);
}
Use RGBA or if you hex code then change it into rgba. No need to do some presodu element css.
function hexaChangeRGB(hex, alpha) {
var r = parseInt(hex.slice(1, 3), 16),
g = parseInt(hex.slice(3, 5), 16),
b = parseInt(hex.slice(5, 7), 16);
if (alpha) {
return "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")";
} else {
return "rgb(" + r + ", " + g + ", " + b + ")";
}
}
hexaChangeRGB('#FF0000', 0.2);
css ---------
background-color: #fff;
opacity: 0.8;
OR
mycolor = hexaChangeRGB('#FF0000', 0.2);
document.getElementById("myP").style.background-color = mycolor;

Resources