CSS - Improve opacity animation performance in conic gradient - css

I have a CSS animation that has terrible performance if it's size is large, about 800px X 800px
or more, the animation can only be run in newest versions of Chrome or Edge.
See example code. If example is not slow enough add more circles or increase the example size.
The real animation is very similar to this one, this is just a simplified example.
I would like to know if there's a way to improve the performance of this animation.
The conic gradient maybe can be simplified but must look the same!
#property --opacity {
syntax: '<percentage>';
initial-value: 100%;
inherits: false;
}
.test {
display: inline-block;
position: absolute;
border-radius: 100%;
background-image: conic-gradient(
red var(--opacity),
red 10%,
rgba(255, 0, 0, var(--opacity)),
transparent,
transparent
);
will-change: transform, background-image;
width: 800px;
height: 800px;
mask:radial-gradient(circle, transparent 47%, white calc(47% + 1px));
-webkit-mask:radial-gradient(circle, transparent 47%, white calc(47% + 1px));
animation:
conic-gradient
4.5s
ease-out
0s
infinite
none
running;
}
.a {
position: absolute;
right: -10%;
top: 20%;
}
.b {
position: absolute;
right: -10%;
top: 40%;
}
#keyframes conic-gradient {
50% {
--opacity: 0%;
}
85% {
--opacity: 100%;
}
}
<div class="test"></div>
<div class="test a"></div>
<div class="test b"></div>
Is there a way to improve the performance?

Related

CSS3 Animation: How do I create smooth movement of background image? Seems to be a Chrome only issue

Trying to smoothly animate a div's background image #bg2 over a short pixel distance (while a clip path animates over it). I'm not able to get the image to move smoothly, it jitters and judders. The clip path animation is fine.
I've tried different easing (linear / ease-in-out etc) suggested in another SO thread, and also extending the distance it needs to move, but it still seems to jump pixel by pixel (sort of), rather than move smoothly. (Although, extending the move distance isn't an option in the actual use case).
How can smooth movement of the cat background image #bg2 be accomplished? Thanks.
** Edit: It's totally smooth for me in Firefox, for me it's jittery in Chrome 91.0.4472.114 on Mojave 10.14.6, and less jittery in Safari. For other it seems to be smooth on Chrome also. Hmmm...
var clickTag = "#";
#main-container {
position: absolute;
width: 970px;
height: 250px;
left:-200px;
box-sizing: border-box;
background: #333;
overflow:hidden; perspective: 800px;
border:1px solid #ccc;
}
div, img {
position: absolute;
background-repeat:no-repeat;
width: 970px;
height: 250px;
z-index: 4;
background-size: 970px 250px;
}
#bg2{
width: 970px;
height: 250px;
z-index:2;
background-image:url('https://i.stack.imgur.com/6EcDu.jpg');
-webkit-clip-path: circle(9% at 682px 110px);
clip-path: circle(9% at 682px 110px);
transform: translateY(20px);
background-position: -5px -10px;
}
#bg2{animation: grow 2.5s 2.5s cubic-bezier(0.215, 0.610, 0.355, 1.000) forwards;-webkit-animation: groww 2.5s 2.5s cubic-bezier(0.215, 0.610, 0.355, 1.000) forwards;}
#-webkit-keyframes groww {
0% {opacity:1;transform: translateY(20px);clip-path: circle(9% at 682px 110px);-webkit-clip-path: circle(9% at 682px 110px);background-position: -5px -10px;}
100% {opacity:1;transform: translateY(-4px);clip-path: circle(15% at 682px 128px);-webkit-clip-path: circle(15% at 682px 128px);background-position: 0px 0px;}
}
#keyframes grow {
0% {opacity:1;transform: translateY(20px);clip-path: circle(9% at 682px 110px);background-position: -5px -10px;}
100% {opacity:1;transform: translateY(-4px);clip-path: circle(15% at 682px 128px);background-position: 0px 0px;}
}
<a href="javascript:window.open(window.clickTag)">
<div id="main-container" class="animate">
<div id="bg2"></div>
</div>
</a>
I'm a bit curious about why having a large banner while not displaying it all.
Anyways, I provide another way of animating, basically just changing the height. Hopefully that could give some ideas.
I removed the width to make it slightly more responsive.
The animation somewhat jittery in this solution, but I guess that it depends on your bezier curve. So perhaps that's the issue all along?
var clickTag = "#";
#main-container {
position: relative;
height: 250px;
box-sizing: border-box;
border: 1px solid #ccc;
background-color: #333;
}
#bg2 {
position: absolute;
left: 75%;
top: 50%;
transform: translate(-50%, -50%);
height: 40%;
aspect-ratio: 1;
border-radius: 50%;
background-image: url('https://i.stack.imgur.com/6EcDu.jpg');
background-position: right 25% center;
animation: grow 2.5s 2.5s cubic-bezier(0.215, 0.610, 0.355, 1.000) forwards;
}
#keyframes grow {
to { height: 80%; }
}
<a href="javascript:window.open(window.clickTag)">
<div id="main-container">
<div id="bg2"></div>
</div>
</a>

CSS: repeated animated background

I'm trying to create a repeated background existing out of two parts. Each part is a gradient and while the one moves up, the other moves down.
The best I got is this:
html {
background: black;
color: #4c4c4c;
}
body {
margin: 30vh auto;
max-width: 80vw;
}
.wave {
background: none;
height: 1rem;
width: 50%;
position: absolute;
z-index: 2;
animation: move 700ms 0ms steps(2) infinite both;
}
.color::after,
.color::before {
content: "";
position: absolute;
left: 0;
right: 0;
height: 100%;
top: 0;
}
.color {
background-image: linear-gradient(#fe0000 50%, #6531ff 0 100%);
}
.color::after {
background: linear-gradient(to bottom, #f4e04d, #3bceac 20%, rgba(22, 22, 22, 0) 100%), linear-gradient(to right, #042a2b 3rem, transparent 3rem, transparent 6rem);
}
.wave,
.color::after,
.color::before {
background-size: 5rem 1rem;
background-repeat: repeat-x;
}
#keyframes move {
0% {
margin-top: -3rem;
}
100% {
margin-top: -3.25rem;
}
}
<div class="color wave"></div>
I get why this doesn't work, but not sure how to proceed.
Since it is difficult to describe, here is an image of what I'm looking for:
At first (position 1), all odd blocks are higher than the even blocks. After the first animation, it's the other way around (position 2) and so on.
Maybe like below:
.box {
height:100px;
background:linear-gradient(red,blue,yellow,red) 0 0/100% 200%;
animation:y 2s linear infinite;
}
.box::after {
content:"";
display:block;
height:100%;
background:linear-gradient(green,lightblue,pink,green) 0 0/100% 200%;
animation:inherit;
animation-direction: reverse;
-webkit-mask:linear-gradient(90deg,#fff 50%,transparent 0) 0 0/20% 100%;
}
#keyframes y {
to {
background-position:0 -200%;
}
}
<div class="box"></div>
UPDATE: This is an interesting problem. I'm surprised to find that I don't have an obvious or particularly elegant solution to having a gradient running vertically while repeating with horizontal gaps.
Far more elusive than I initially expected.
Best I could come up with is to put one of the gradients in a pseudo element and apply a mask-image. This won't work in IE, but it appears to be supported everywhere else.
See updated demo below.
If I understand what you're trying to do, I think you could accomplish it by animating the background positions:
.demo {
height: 200px;
background-image:
linear-gradient(#f4e04d, #3bceac 20%, rgba(22, 22, 22, 0) 100%);
animation: move 0.7s infinite alternate;
background-size: 3rem;
position: relative;
}
.demo::before {
content: '';
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background: linear-gradient(#042a2b, transparent);
/* This is the magic part: using a horizontal repeating-linear-gradient
to mask out "columns", allowing the container's background gradient to
show through */
-webkit-mask-image: repeating-linear-gradient(to right, black 0 3rem, transparent 3rem 6rem);
background-size: 3rem;
/* run the same animation in reverse to animate up instead of down */
animation: move 0.7s infinite alternate-reverse;
}
#keyframes move {
from {
background-position: 0 0;
}
to {
background-position:
0 200px;
}
}
<div class="demo"></div>
It's difficult to infer exactly what you're trying to do, but here's another sample (very similar to #ray hatfield's answer) that will move the first background down while the second background moves up:
.sample {
width: 250px;
height: 50px;
position: relative;
background-image: linear-gradient(to bottom, #f4e04d, #3bceac 20%, rgba(22, 22, 22, 0) 100%), linear-gradient(to right, #042a2b 3rem, transparent 3rem, transparent 6rem);
animation: move 1s infinite linear;
}
#keyframes move {
0%, 100% {
background-position: 0 -75px, 0 0;
}
50% {
background-position: 0 0, 0 -75px;
}
}
<div class="sample"></div>

Animation changing a HSL variable isn't working

I'm trying to create a rainbow animation with CSS variables and HSL. I've got the following code, however in Chrome it just snaps between both states.
#keyframes rainbow {
from {
--accent-bright: hsl(0,87%,48%);
--accent-dark: hsl(0,94%,48%);
--accent-verydark: hsl(0,88%,33%);
}
to {
--accent-bright: hsl(359,87%,48%);
--accent-dark: hsl(359,94%,48%);
--accent-verydark: hsl(359,88%,33%);
}
}
.rainbow, .rainbow *, .rainbow > * {
animation-name: rainbow;
animation-duration: 3.6s;
animation-iteration-count: infinite;
}
[...]
#topBar {
height: 56px;
width:100vw;
position:fixed;
top:0;
background-image: linear-gradient(to right, var(--accent-bright),var(--accent-dark));
color: var(--text-onaccent);
}
If I change the hue in one of the keyframes to someething more noticible, you can see the gradient flipping.
The property background-image is not animatable
However... opacity is animatable.
This means that you can create an ::after pseudo-element, exactly overlapping your original element and animate the pseudo-element's opacity so that it fades into view.
Remember to apply pointer-events: none to the pseudo-element, so that, as far as interactivity goes, the pseudo-element remains entirely insubstantial.
Working Example:
N.B. I have introduced yellow to make the animation more visible.
.rainbow {
--accent-bright: hsl(0, 87%, 48%);
--accent-dark: hsl(0, 94%, 48%);
--accent-verydark: hsl(0, 88%, 33%);
position: relative;
width: 100px;
height: 100px;
background-image: linear-gradient(to right, var(--accent-bright), var(--accent-dark));
color: var(--text-onaccent);
}
.rainbow::after {
--accent-bright: hsl(359, 87%, 48%);
--accent-dark: yellow;
--accent-verydark: hsl(359, 88%, 33%);
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: linear-gradient(to right, var(--accent-bright), var(--accent-dark));
pointer-events: none;
animation: rainbow 3.6s infinite;
}
#keyframes rainbow {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
<div class="rainbow"></div>

How to animate a ripple effect of a gradient flowing across a background image in CSS

Not quite a pulse animation -- but somewhat similar (not radial, but linear) -- I am trying to create the effect of sort of a lens flare if you turn a piece of glass and see a band of light swipe across it, in CSS. So say you have a regular background image, or a seamless repeating background image, in CSS. Now you want to animate across that image a rectangular band of light that is sort of a "fade-in ... full light ... fade-out" gradient of white light. So you have a linear-gradient sort of like transparent, semi-transparent-white, white, semi-transparent-white, transparent that flows across the background image (seamless/repeating background image, or regular background image), repeatedly flowing across like it was a pool of water in constant motion.
Wondering if this sort of thing is possible in CSS, and how to do it.
Maybe it is simply an animated linear-gradient mask (which I am not familiar with but have heard of). Not sure.
Basically animating a semitransparent linear gradient like this (just the line part, and imagine it was a simple rectangle).
Are you looking for something like below:
body {
margin:0;
height:100vh;
background:
linear-gradient(to right,transparent 33%,white,transparent 66%),
url(https://picsum.photos/id/10/800/800) center;
background-size:300% 100%,cover;
animation:change 2s linear infinite;
}
#keyframes change {
from { /*Use "to" to change the direction */
background-position:right,center;
}
}
html {
background:#fff;
}
Related to get more details about the calculation:Using percentage values with background-position on a linear gradient
NOt sure if this is what you are looking for. Here it is a shot!
.ripple{
width: 50px;
height: 50px;
display: block;
position: relative;
background-color: #00ccff;
border-radius: 100%;
opacity: 0.5;
}
.ripple:before, .ripple:after{
content: '\0020';
width: 0;
height: 0;
position: absolute;
top: 50%;
left: 50%;
border-radius: 100%;
border: 2px solid #0088ee;
transform: translate(-50%, -50%);
}
.ripple:before{
animation: ripple-one 2.5s infinite;
}
.ripple:after{
animation: ripple-one 3.5s infinite;
}
#keyframes ripple-one{
0%{
width: 0;
height: 0;
opacity: 1;
}
100% {
width: 100%;
height: 100%;
opacity: 0;
}
}
#keyframes ripple-two{
0%{
width: 0;
height: 0;
opacity: 1;
}
100% {
width: 100%;
height: 100%;
opacity: 0;
}
}
<label class="ripple"></label>

CSS Transition from no background color to gradient

Is it possible to make a transition from a div without background to a div with gradient background?
div { background-color:none;}
div:hover {
background:#D74413; background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#D74413), to(#8A2D0D));
background: -webkit-linear-gradient(top, #D74413, #8A2D0D); background: -moz-linear-gradient(top, #D74413, #8A2D0D);
background: -ms-linear-gradient(top, #D74413, #8A2D0D); background: -o-linear-gradient(top, #D74413, #8A2D0D);
}
Animating gradients is not simple and involves playing with background-size and -position of the gradients. Shown here for example:
http://www.impressivewebs.com/animating-css3-gradients/
An easy workaround that works for me is to put the gradient on a child of the div and animate it's opacity like here:
http://jsfiddle.net/willemvb/rWpZN/
HTML:
<div id="container">
<div id="back"></div>
</div>​
CSS (for webkit, but would work for other modern browsers too if you add the variants)
#container {
position: relative;
width: 500px; height: 500px;
background: transparent;
}
#back {
position: absolute;
width: 100%; height: 100%;
top: 0; left: 0;
opacity: 0;
background: -webkit-linear-gradient(top, #ccc, #999);
z-index: -1;
-webkit-transition: opacity 3s ease-out;
}
#container:hover #back {
opacity: 1;
}​
Use this site:
Ultimate CSS Gradient Generator

Resources