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>
Related
I'm using both vertical and horizontal skeleton loader in a react component, please refer to this codepen - https://codepen.io/phutschi/pen/jejzbK for reference, I want to like this for vertical loader from bottom to top.
Loader.js
import './loader.scss'
function Loader() {
return (
<div className="animated-background">
<div className="background-masker content-first-line"></div>
<div className="background-masker content-second-line"></div>
<div className="background-masker content-third-line"></div>
<div className="background-masker vertical-line"></div>
</div>
)
}
export default Loader
loader.scss
#keyframes placeHolderLoader {
0% {
background-position: -468px 0;
}
100% {
background-position: 468px 0;
}
}
#keyframes verticalPlaceHolderLoader {
0% {
background-position: bottom ;
}
100% {
background-position: top;
}
}
.animated-background {
// height: 120px;
// position: relative;
.background-masker{
height: 14px;
border-radius: 7px;
width: 80%;
margin-bottom: 2px;
animation-duration: 1.3s;
animation-fill-mode: forwards;
animation-iteration-count: infinite;
animation-name: placeHolderLoader;
animation-timing-function: linear;
background: #f6f7f8;
background: linear-gradient(to right, #eeeeee 8%, #dddddd 18%, #eeeeee 33%);
background-size: 100%;
&.vertical-line{
width: 50px;
height: 140px;
animation-duration: 1.3s;
background: linear-gradient(to bottom, #eeeeee 8%, #dddddd 18%, #eeeeee 33%);
animation-name: verticalPlaceHolderLoader;
}
}
}
u can see, that I'm using separate gradient and animation for vertical lines, but the animation is not working for vertical lines, the animation should work from bottom to top.
Change the vertical animation keyframe to the following and it should work:
#keyframes verticalPlaceHolderLoader {
0% {
background-position: 0 70px;
}
100% {
background-position: 0 -70px;
}
}
See demo
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>
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?
I have created a simple animated wavy line to use as a divider on one of my websites. Looks perfect in safari but it displays strange in Chrome.
Here's the safari screenshot:
Here's the chrome screenshot:
The safari one is perfect for me, but it seems chrome isn't liking it.
I have tried adding ALL vendor prefixes to the start of the selectors and various places but I cant seem to fix the issue.
Can anyone please tell me where I'm going wrong?
Here's a CODEPEN and here's a code snippet:
.wavy-line {
width: 150px;
height: 50px;
overflow: hidden;
margin: 0 auto 0 auto;
}
.wavy-line:before {
content: attr(data-text);
position: relative;
top: -35px;
color: rgba(0,0,0,0);
width: calc(100% + 27px);
font-size: 4em;
text-decoration-style: wavy;
text-decoration-color: #25173A;
text-decoration-line: underline;
animation: animate .9s linear infinite;
-webkit-animation: animate .9s linear infinite;
}
#keyframes animate {
0% { left: -0px; }
100% { left: -30px;}
}
#-webkit-keyframes animate {
0% { left: -0px; }
100% { left: -30px;}
}
.wavy-line-green:before { text-decoration-color: #56AE5F; }
.wavy-line-blue:before { text-decoration-color: #1FB5D1; }
.wavy-line-yellow:before { text-decoration-color: #F9B930; }
<div class="wavy-line wavy-line-green" data-text="xxxxxxxxxxxxxx"></div>
<div class="wavy-line wavy-line-blue" data-text="xxxxxxxxxxxxxx"></div>
<div class="wavy-line wavy-line-yellow" data-text="xxxxxxxxxxxxxx"></div>
I will consider a previous answer to draw the waves using CSS and then you can easily animate them. You simply need to adjust the CSS variable to control the shape:
.wave {
--c:red; /* Color */
--t:5px; /* Thickness */
--h:50px; /* Height */
--w:120px; /* Width */
--p:13px; /* adjust this to correct the position when changing the other values*/
margin:5px auto;
width:calc(var(--w)*4);
height:calc(var(--h) + 10px);
overflow:hidden;
position:relative;
}
.wave:before {
content:"";
position:absolute;
padding:5px 0;
top:0;
left:0;
width:200%;
bottom:0;
background:
radial-gradient(farthest-side at 50% calc(100% + var(--p)), transparent 47%, var(--c) 50% calc(50% + var(--t)),transparent calc(52% + var(--t))),
radial-gradient(farthest-side at 50% calc(0% - var(--p)), transparent 47%, var(--c) 50% calc(50% + var(--t)),transparent calc(52% + var(--t)));
background-size:var(--w) var(--h);
background-position:calc(var(--w)/2) calc(-1*(var(--h)/2)),0px calc(var(--h)/2);
background-repeat:repeat-x;
background-origin:content-box;
animation:move 3s infinite linear;
}
#keyframes move {
to {
transform:translateX(-50%);
}
}
<div class="wave"></div>
<div class="wave" style="--w:140px;--h:40px;--p:13px; --t:8px;--c:purple"></div>
<div class="wave" style="--w:100px;--h:30px;--p:14px;--t:10px;--c:green;"></div>
<div class="wave" style="--w: 64px;--h: 22px;--p: 11px;--t: 7px;--c: orange;"></div>
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