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%;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div id="test"></div>
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;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div id="test"></div>
How to animate gradient colors with keyframes:
// Beggin
#demo {
width: 200px;
height: 200px;
position: absolute;
background: linear-gradient(to right, #f06 0%, #60f 100%);
z-index: 2;
}
/* Use a 'Before' element to change the background */
#demo::before {
content: '';
position: absolute;
width: 100%;
height: 100%;
background: linear-gradient(to left, #f06 0%, #60f 100%);
/* Give it an Opacity of 0 and create your animation property: */
opacity: 0;
animation: bg 2800ms ease-in-out 0s infinite alternate-reverse;
z-index: -1;
}
/* Now call the keyframe-function */
@keyframes bg {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
/* Unnecessary styling: */
h3 {
color: #fff;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -130%);
font-family: Helvetica, Arial, sans-serif;
}
<div id="demo"><h3>CWM</h3></div>
To animate the background, you need to modify the background position.
To make the transition smooth, you need to play with opacity - and since you don't want all the element to fade, you need to use a pseudo element for this
#test{
width: 200px;
height: 200px;
position: relative;
background-color: rgba(215,54,92,0.7);
transition: background-color 1s;
}
#test:hover{
background-color: transparent;
}
#test:after {
content: "";
position: absolute;
left: 0px;
top: 0px;
right: 0px;
bottom: 0px;
z-index: -1;
background-image: linear-gradient(45deg,
rgba(215,54,92,0.5),
rgba(215,54,92,0.9),
rgba(215,54,92,0.5),
rgba(215,54,92,0.9),
rgba(215,54,92,0.5)
);
background-size: 800px 800px;
background-position: 0px 0px;
animation: move 2s infinite linear;
opacity: 0;
transition: opacity 1s;
}
#test:hover:after {
opacity: 1;
}
@keyframes move {
from {background-position: 0px 600px;}
to {background-position: -800px 600px;}
}
<div id="test"></div>