CSS transform and transition on hover do not work after animation-fill-mode: forwards
Why does transform not work when animation fill mode is forwards?
As per W3C pec: (emphasis is mine)
By default, an animation will not affect property values between the time it is applied (the ‘animation-name’ property is set on an element) and the time it begins execution (which is determined by the ‘animation-delay’ property). Also, by default an animation does not affect property values after the animation ends (determined by the ‘animation-duration’ property). The ‘animation-fill-mode’ property can override this behavior.
If the value for ‘animation-fill-mode’ is ‘forwards’, then after the animation ends (as determined by its ‘animation-iteration-count’), the animation will apply the property values for the time the animation ended.
The above means that the UA has to apply and maintain the transform
on the element even after the animation has ended. This would sort of imply that the transform
mentioned within the animation gets precedence and hence the transform
that is mentioned within the :hover
state has no effect.
When animation-fill-mode: none
or animation-fill-mode: backwards
is applied then the UA does not have to maintain the transformed state after the animation has ended (meaning it kind of becomes like transform: none
) and so the transform
within the :hover
selector works.
This behavior is consistent in latest versions of Chrome and Firefox. In IE11 and Edge the transform
that is specified within the :hover
selector has no effect irrespective of what value is provided for the animation-fill-mode
property.
Why does transition not work when even when fill mode is changed to none?
I am not sure if the code in CodePen is the original one or if you made any changes for testing but the transition
property is wrongly specified in that demo and that is the reason why transition does not happen.
The code that is present is:
transition: scale 1s ease;
but scale
is not the property that needs to be transitioned. It is only the type of transform that needs to be done. The property is transform
and hence the code should be as below:
transition: transform 1s ease;
If you do this change then the transition
will work if the animation-fill-mode
is changed.
Transition doesn't work after animation forwards
Still don't know what's wrong with keyframes in chrome/safari, but have found simple workaround.
Now first 'before'-element is on right with no width right: 0; width: 0;
.
On hover it moves to left with 100% width, that begins to transitionally grow: left: 0; right: auto; width: 100%;
.
Finally, when hover was lost, 'before' starts to decreasing, resting on the right end again.
New code:
button {
padding: 5px 0;
position: relative;
border: none;
border-radius: 0;
background: transparent;
outline: none;
cursor: pointer;
font-weight: 700;
text-transform: uppercase;
&:before {
content: '';
position: absolute;
bottom: 0;
right: 0;
width: 0;
height: 4px;
border-radius: 2px;
background: blue;
transition: all .25s;
}
&:hover {
&:before {
left: 0;
right: auto;
width: 100%;
}
}
}
Codepen
How to animate element again, after animation-fill-mode: forward?
Use two animations like below:
.main-image {
transition: transform .5s ease-in-out;
height: 50px;
margin: 10px;
background: red;
}
#portfolio:hover #portfolio-image {
transform: scale(1.1);
}
@keyframes fade {
100% {
opacity: 1;
}
}
@keyframes move {
0% {
transform: translateY(-30%);
}
}
#portfolio .main-image {
opacity: 0;
animation:
0.5s ease-out 0.2s fade forwards, /* forwards only for opacity */
0.5s ease-out 0.2s move;
}
<div id='portfolio' class='main-block'>
<div id='portfolio-image' class='main-image'></div>
</div>
CSS animation with fill-mode including transition not working in firefox properly
Well, I added a keyframe for the start point 0%
to get it to work:
@keyframes test{
0% {
transform: translate(-200px);
}
100% {
transform: translate(0px);
}
}
Using the above, you could remove the transform
property form the .box
element.
Also, for the old versions of web browsers, consider using vendor prefixes such as -webkit-
and -moz-
, ... for the @keyframes
and the other CSS3 properties.
PS: I tested the demo with FF 9.0.1. This issue may appear only in earlier versions of web browsers. In fact, web browsers try to fix your bad-coding but only the smarters will win!
WORKING DEMO
Update
In order to fix the rendering issue (when the animation starts) you need to change the transition-property
from all
to the specific properties you really want. (border-radius
in this case):
.box{
animation-name: test;
animation-duration: 3s;
animation-fill-mode: forwards;
transition: border-radius 0.25s ease;
}
The problem was because of the conflict between animation
and transition
for the transform
property.
UPDATED DEMO
Execute :hover and :hover:after animation with keyframes on component load
I've fixed the animation with an additional element providing the :after feature:
.module .heading {
font-size: 2.75rem;
font-weight: 700;
margin-bottom: 2rem;
font-family: 'Oswald', sans-serif;
font-weight: 200;
color: var(--text-color-dark);
}
.module .active {
display: inline-block;
position: relative;
color: var(--text-color-dark);
animation-iteration-count: 1;
animation-fill-mode: forwards;
.reveal-line {
transform: scaleX(1);
transform-origin: bottom left;
content: '';
position: absolute;
width: 100%;
height: 2px;
bottom: 0;
left: 0;
background-color: var(--primary-color);
transform-origin: bottom right;
transition: transform 0.6s ease-out;
animation: loadInAnimation ease 1.5s;
}
}
@keyframes loadInAnimation {
0% {
width: 0%;
}
100% {
width: 100%;
}
}
<h3 className='heading reveal'>Unsere Angebote<div className='reveal-line' /></h3>
Hover animation makes initial animation rerun after mouse out
If you do not want the initial state animation to run again after you mouse out of the hover state and you want the element to return to its previous orientation. You will need to add a class to the foo element using JavaScript and add in CSS for that class that no longer allows that animation to run.
const fooEl = document.querySelector(".foo");
fooEl.addEventListener("mouseleave", () => {
fooEl.classList.add("stopped");
})
.foo {
margin: auto;
margin-top: 100px;
padding: 1em;
width: fit-content;
border: solid 1px black;
background: red;
color: white;
font-size: 2em;
/* The initial animation */
animation: kf-initial 2s;
}
.stopped {
animation: none;
}
.foo:hover {
/* The infinite animation */
animation: kf-hover 10s infinite;
}
@keyframes kf-initial {
from {transform: scale(0.2)}
to {transform: scale(1)}
}
@keyframes kf-hover {
100% {transform: rotate(1turn)}
}
<div class="foo">
Hello world
</div>
Related Topics
CSS - Border Radius and Solid Border Curved Inside
Working with CSS Floats in HTML2Pdf
CSSmin Not Correctly Handling @Import
Media Query About Screen Size Instead of Resolution
Rotating a Svg with CSS (Animation)
Change CSS Variables Dynamically in Angular
Overriding CSS on Github Pages Using Slate Theme
How to Prevent CSS Declaration Dropped Errors Cross Browser
How to Show Md-Toast with Background Color
Child Take Width % from Parents Parent
Div Elements to Follow a Curved Path with CSS3
How to Highlight a Selected Row in *Ngfor
Why Are My Google Web Fonts Pixelated