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.
Related
I want to have the beginning animation on load and then on :hover to add another animation. The problem is, after I leave the element(not hovering) it goes back to its first animation and repeats it.
Is there any way to avoid this from happening?
Problem video :
https://youtu.be/uCZdo4FsCj8
Code :
.char {
animation: slide-down 2s forwards cubic-bezier(0, 1.18, .82, 1.02);
animation-delay: calc(0s + (0.1s * var(--char-index)));
animation-iteration-count: 1;
opacity: 1;
#keyframes slide-down {
from {
transform: translate(-125%, 125%);
opacity: 1;
}
to {
transform: translate(0%);
opacity: 1;
}
}
&:hover {
animation: newAnim 0.4s forwards linear;
color: red;
#keyframes newAnim {
from {
transform: scale(1);
}
to {
transform: scale(1.2);
}
}
}
}
You cannot do it without using JavaScript. When :hover happens, the animation-iteration-count gets reset. This in turn causes the first animation to repeat after letting go of hovering. So you will have to use some JavaScript to get it working.
Have you considered using the animation just for the initial movement, and transitions for the :hover effect? This way, the animation-iteration-count is not reset after unhovering. Essentially add the following css code:
.char {
...your animations for initial loading
transition: color 0.4s linear, transform 0.4s linear;
}
.char:hover {
transform: scale(1.2);
color: red;
}
An example of such solution can be found in this codepen.
I have added a keyframe animation to slowly zoom the background image in and it works perfectly, however when I move mouse out the animation jumps back to the original state instead of zooming out.
#startup.hover:before {
opacity:1;
-webkit-animation: animatedBackground 5s ease-in-out 1;
-moz-animation: animatedBackground 5s ease-in-out 1;
animation: animatedBackground 5s ease-in-out 1;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
}
#-webkit-keyframes animatedBackground {
0% {
-webkit-transform: scale(1, 1);
-moz-transform: scale(1, 1);
-ms-transform: scale(1, 1);
-o-transform: scale(1, 1);
transform: scale(1, 1);
}
100% {
-webkit-transform: scale(1.1, 1.1);
-moz-transform: scale(1.1, 1.1);
-ms-transform: scale(1.1, 1.1);
-o-transform: scale(1.1, 1.1);
transform: scale(1.1, 1.1);
}
}
Am I missing something here?
first of all, is .hover a class you are adding or were you meant to use :hover? Just pointing this out. Assuming this is a class, you should add the transitions animation on the id.
#startup:before {
-webkit-transition: all 5s ease-in-out;
-moz-transition: all 5s ease-in-out;
-o-transition: all 5s ease-in-out;
transition: all 5s ease-in-out;
}
..this is why it's breaking when you are hovering out. There's no transition animation without the class!
You dont need such an advanced tool as a keyframes to make this effect.
It is easily achivable with transitions, here is an example.
https://jsfiddle.net/vqL3stjz/
.animable{
width: 100px;
height: 100px;
background-color: #000;
transition: all 500ms;
}
.animable:hover{
transform: scale(1.3, 1.3);
transition: all 500ms;
}
And if you need to make it with keyframes, then i suggest just applying reverse animation to unhovered element.
However, you will need to use some javascript then, to prevent side effect like animation running on the element right after it is loaded etc.
TL;DR Better use tranistions, unless you really need to use keyframes.
Reproduction online
Reproduction with vanilla Javascript
I'm creating a CSS animation by using this:
.slides.future.active {
-webkit-animation-name: sectionIn;
animation-name: sectionIn;
}
#keyframes sectionIn {
....
}{
.animated {
transition: all 800ms ease;
-moz-transition: all 800ms ease;
-webkit-animation-duration: 800ms;
animation-duration: 800ms;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
-webkit-animation-timing-function: ease;
timing-function: ease;
}
.slides.future{
-webkit-transform: translate3d(0, 100%, 0);
-ms-transform: translate3d(0, 100%, 0);
transform: translate3d(0, 100%, 0 );
}
Having the following HTML:
<div id="demo2" class="slides animated future active">
Demo
</div>
<div class="slides animated future">Demo 2</div>
Now, when I remove the class future from the element, the animation gets fired again.
This only happends in IE. (10, 11, 12, 13) Working well in Firefox, Chrome, Safari...
Reproduction online
Reproduction with vanilla Javascript
Strangely (not very strange for IE) you need to also tell the browser what to do when .slides and .active are there but not .future. If you don't then for that split second it goes back to where it was until it gets the instruction to revert back again. So you need to add:
.slides.active:not(.future){
-webkit-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0 );
}
Note: Tested in IE 11 only.
Fiddle
A possible solution is to change the CSS selector.
Instead of .animated use .future.animated and apply the animation on that selector.
.future.animated {
transition: all 800ms ease;
-moz-transition: all 800ms ease;
-webkit-animation-duration: 800ms;
animation-duration: 800ms;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
-webkit-animation-timing-function: ease;
timing-function: ease;
}
That way only the element with both classes gets animated. So removing the class future from the element prevents it from animating again.
https://jsfiddle.net/jsms8p1k/17/
I've been trying to use a transition-delay when moving from "state A" to "state B" but not having that delay when moving back to state A. This is a general question though about whether the CSS spec says that the settings for a transition should be those when the transition starts or those from the state which is being transitioned to. Here is an example:
.menu {
transform: translateX(0%);
transition: transform 1s ease-out;
}
.menu.is-open{
transform: translateX(100%);
transition: transform 5s ease-out;
}
Should the opening animation animation take 1 second or 5 seconds?
My code is slightly more complicated as it uses a delay, but basically it boils down to this.
.menu {
transform: translateX(0%);
transition: transform 0.5s ease-out 0;
}
.menu.is-open {
transform: translateX(100%);
transition: transform 0.5s ease-out 0.5s;
}
When I try this in Chrome or Firefox I get a delay when opening the menu and no delay when closing the menu, but in IE11/Edge it behaves as it would without the delay set. So I'm not sure whether this is a browser bug, or whether I've misunderstood how transitions work, hence my more general question about which transitions are used.
It should be transition: transform and not transition: translate
The transition rule accepts CSS properties not values
Try reversing the order so that the .menu gets the half second delay
.menu{
transform: translateX(0%);
transition: transform 0.5s 0.5s ease-out;
}
.menu.is-open{
transform: translateX(100%);
transition: transform 0.5s 0s ease-out;
}
As for not working in IE, see vendor prefixes for transition and transform
Seems like you understood correctly how transition works. See my code snippet:
JSFiddle
.hoverable {
height: 50px;
background-color: yellow;
}
.moving {
width: 100px;
height: 100px;
background-color: red;
-webkit-transform: translateX(0);
-ms-transform: translateX(0);
transform: translateX(0);
-webkit-transition: transform 1s linear 0s;
transition: -ms-transform 1s linear 0s;
transition: transform 1s linear 0s;
}
.hoverable:hover + .moving {
-webkit-transform: translateX(200%);
-ms-transform: translateX(200%);
transform: translateX(200%);
-webkit-transition: transform 0.5s linear 0.5s;
transition: -ms-transform 0.5s linear 0.5s;
transition: transform 0.5s linear 0.5s;
}
<div class="hoverable">Hover me</div>
<div class="moving">I can move</div>
Maybe transition-timing-function: ease-out seems like delay for you in some cases, so I used transition-timing-function: linear in my example to show the transition with a constant speed.
The red block moves from 0% to 200% for 0.5s with 0.5s delay. And moves from 200% to 0% for 1s without delay. There is no any magic with how transition works.
I want to fade out an element after 3 seconds. I'm currently using an animation to do this but I've just learned of transition-delay, so I believe I may be able to remove the animation and do it through a transition. Is this possible?
My original code is:
.foo {
animation: fadeOut 3s cubic-bezier(0.645, 0.045, 0.355, 1.000)
}
#keyframes fadeOut {
80%{
opacity: 1
}
100% {
opacity: 0
}
}
Here is my attempt at a transition:
.announcement {
display: block;
font-size:22px;
transition: opacity 0.4s cubic-bezier(0.645, 0.045, 0.355, 1.000);
transition-delay :3s;
opacity:0;
}
<div class="announcement">asdasd</div>
http://jsbin.com/vejewukusi/edit?html,css,output
Is this possible without adding another CSS class?
Just to make things more clear, I want to append a div with a class, wait 3 seconds, and then fade it out, and do this without using keyframes.
Does this solve your problem: JSFiddle? I have added an animation and a little function to animate the opacity:
.test {
animation: opacity 1s;
}
#keyframes opacity {
from { opacity: 0.5; }
to { opacity: 1; }
}