I want to achieve an effect than when the user hovers over a div, it\'s background color turns into a gradient that smoothly switches from one corner to the other, repeatedly, u
As already pointed out in comments, linear gradients are not transitionable or animatable unlike colors (background-color
) because they are considered as image (background-image
). Transitions effects are generally achieved by the UA calculating the value at each intermediate stage and then applying that value to the element. In case of an image, it is not possible to calculate the values at intermediate stages and hence they cannot be transitioned.
You need to transition the position (background-position
) instead to achieve the effect. This can be done by using a pseudo-element whose background contains the linear-gradient
and animating its position on hover
. The gradient should go both ways (that is, it should go from rgba(215,54,92,0.9)
to rgba(215,54,92,0.5)
and then to rgba(215,54,92,0.9)
) because it needs to accommodate both phases of the animation and its background-size
also needs to be double (that is 200% 200%
). Then by animating the positon from 0% 100%
to 100% 0%
the required effect can be achieved.
#test {
position: relative;
width: 200px;
height: 200px;
background-color: rgba(215, 54, 92, 0.7);
transition: background-color .1s;
}
#test:hover {
background-color: transparent;
cursor: pointer;
}
#test:hover:after {
position: absolute;
content: '';
height: 100%;
width: 100%;
background: linear-gradient(45deg, rgba(215, 54, 92, 0.9), rgba(215, 54, 92, 0.5), rgba(215, 54, 92, 0.9));
background-size: 200% 200%;
background-position: 0% 100%;
animation-name: test_hover;
animation-duration: 4s;
animation-iteration-count: infinite;
animation-timing-function: linear;
animation-direction: alternate;
}
@keyframes test_hover {
from {
background-position: 0% 100%;
}
to {
background-position: 100% 0%;
}
}
Another slightly different approach that can be used is to add two pseudo-elements with each having one stage of animation's gradient and then animate their opacity
such that at any point of time only one of them will be visible. This would also produce a similar effect.
#test {
position: absolute;
width: 200px;
height: 200px;
background-color: rgba(215, 54, 92, 0.7);
transition: background-color .1s;
}
#test:before,
#test:after {
position: absolute;
content: '';
height: 100%;
width: 100%;
z-index: 1;
}
#test:before {
background: linear-gradient(45deg, rgba(215, 54, 92, 0.9), rgba(215, 54, 92, 0.5));
opacity: 0;
}
#test:after {
background: linear-gradient(45deg, rgba(215, 54, 92, 0.5), rgba(215, 54, 92, 0.9));
opacity: 0;
}
@keyframes test_hover {
0%, 100% {
opacity: 0;
}
50% {
opacity: 1;
}
}
#test:hover:before,
#test:hover:after {
cursor: pointer;
animation-name: test_hover;
animation-duration: 4s;
animation-iteration-count: infinite;
animation-fill-mode: backwards;
}
#test:hover:before {
animation-delay: 1s;
}
#test:hover:after {
animation-delay: 3s;
}
#test:hover {
background-color: transparent;
transition: background-color 2s 1s;
}