I have this CSS animation where when a page is chosen, the page scrolls from the bottom to the top.
The issue I am having is that the page briefly displays in it's top position first, then disappears to scroll from the bottom to top. How can I keep the page from showing before it's animation?
Note: I would like to keep the brief animation delay 500ms
mainPanelContent.classList.add('slide-up-now');
.slide-up-now {
-webkit-animation: slide-up .6s cubic-bezier(0.4, 0, 0.2, 1) 500ms;
-moz-animation: slide-up .6s cubic-bezier(0.4, 0, 0.2, 1) 500ms;
animation: slide-up .6s cubic-bezier(0.4, 0, 0.2, 1) 500ms;
}
@-webkit-keyframes slide-up {
0% { -webkit-transform: translateY(100%); }
100% { -webkit-transform: translateY(0); }
}
Solution:
The correct solution to this issue is to set animation-fill-mode
as backwards
(or use the shorthand like below):
animation: slide-up .6s cubic-bezier(0.4, 0, 0.2, 1) 500ms backwards;
Reasoning:
When delay is added to any animation, its execution is put on hold till that time has elapsed and during this time, the element holds whatever position was assigned to it initially. For it to start at the translated position, you either have to manually add the setting to the element (or) tell the UA to do it for you.
When we set the animation-fill-mode
as backwards
, the UA automatically sets the property value defined for the first frame of the animation's first iteration as the properties during the delay period and thus it will start at the translated position for your case.
Here's what the W3C Spec says about
animation-fill-mode: backwards
During the period defined by animation-delay, the animation will apply the property values defined in the keyframe that will start the first iteration of the animation. These are either the values of the from keyframe (when animation-direction is normal or alternate) or those of the to keyframe (when animation-direction is reverse or alternate-reverse).
Alternate Solution:
You can of-course solve this by adding a transform: translateY(100%
) to the element originally also but that makes less sense when there is a specific property to achieve it.
(I assume that the element did not have transform: translateY(100%)
initially in your code.)
Why using opacity may not always be acceptable solution?
Solution by using opacity
(as you have done in your own answer) is not wrong but you would notice that the opacity
also gets animated from 0
to 1
over the course of the animation which means that the content slowly fades into view as opposed to just a slide up action. While, this can also be fixed by adding extra keyframes in between, those are just work-arounds for something that could have been achieved by using a single property.
Sample for all solutions:
In the below snippet, I have added samples for the version with the problem and all possible fixes.
.slide-up-now {
animation: slide-up .6s cubic-bezier(0.4, 0, 0.2, 1) 500ms;
}
.slide-up-now-fixed { /* preferred method */
animation: slide-up .6s cubic-bezier(0.4, 0, 0.2, 1) 500ms backwards;
}
.slide-up-now-fixed-initial-prop {
transform: translateY(100%);
animation: slide-up .6s cubic-bezier(0.4, 0, 0.2, 1) 500ms forwards;
}
.slide-up-now-opacity {
opacity: 0;
animation: slide-up-opacity .6s cubic-bezier(0.4, 0, 0.2, 1) 500ms forwards;
}
@keyframes slide-up {
0% {
transform: translateY(100%);
}
100% {
transform: translateY(0);
}
}
@keyframes slide-up-opacity {
0% {
transform: translateY(100%);
opacity: 0;
}
100% {
transform: translateY(0);
opacity: 1;
}
}
/* Just for demo */
div{
display: inline-block;
height: 100px;
margin: 10px;
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class='slide-up-now'>Slide Up Now</div>
<div class='slide-up-now-fixed'>Fixed by Fill Mode</div>
<div class='slide-up-now-fixed-initial-prop'>Fixed by Initial Setting</div>
<div class='slide-up-now-opacity'>Fixed by Opacity</div>
I got it with this:
.slide-up-now {
opacity: 0;
-webkit-animation: slide-up 1s cubic-bezier(0.4, 0, 0.2, 1) 500ms forwards;
}
@-webkit-keyframes slide-up {
0% { -webkit-transform: translateY(100%); opacity: 1 }
100% { -webkit-transform: translateY(0); opacity: 1 }
}
Note: I did opacity: 1
twice on purpose. I don't want any opacity effect at all and the first opacity 1 was not enough.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With