animation triggers on load, animate to default state when class removed - html

I'm doing an animation that gets triggered with adding a class to a element. Now on removal of the class I want the animation to go the other way, I figured out to how to reverse the animation, the problem is onload that it triggers it. What can I do to prevent it, what can I change, what am I missing?
the full html/css/js are in the fiddle
here are the good parts,
#keyframes expand {
20% {
opacity: 0;
width: 5rem;
}
70%, 100% {
opacity: 1;
transform: translate(0, 0);
width: 100%;
}
}
#keyframes contract {
0% {
transform: translate(0, 0);
width: 100%;
}
100% {
transform: translate(0, -6rem);
width: 5rem;
}
}
[data-am-button~="buy"] {
margin-bottom: .5rem;
transform: translate(0, -6rem);
width: 5rem;
animation: contract 500ms forwards;
span {
display: none;
}
.is-expanded & {
animation: expand 500ms forwards;
}
}

So instead of putting the animation on the button by default. Add the animation to a .is-contracted class.
Then toggle between these 2 classes when clicking the button. This means that nothing is animated on the page load. Only the button clicking.
CSS changes:
[data-am-button~="buy"] {
margin-bottom: .5rem;
transform: translate(0, -6rem);
width: 5rem;
//animation: contract 500ms forwards; <-- Removed this
span {
display: none;
}
.is-expanded & {
animation: expand 500ms forwards;
}
.is-contracted & {
animation: contract 500ms forwards;// <-- added it to this new class
}
JS changes:
$('.js-expander').on('click', function() {
var $this = $(this);
var $parent = $this.parents('.product-info');
if ( $parent.hasClass('is-expanded') ){
$parent.removeClass('is-expanded')
$parent.addClass('is-contracted')
} else {
$parent.addClass('is-expanded')
$parent.removeClass('is-contracted')
}
});
Here's a fiddle : https://jsfiddle.net/BradChelly/Lugnmmpe/7/

Related

Smooth parent transition on child "translateX"

On GIF below, there's parent div, which contain "left-menu" and "app-content". Left menu is animating, using keyframes and translate property
#LeftMenuContainer {
&.menu_hidden {
animation: slide-out 0.6s forwards;
}
&.menu_shown {
animation: slide-in 0.6s forwards;
}
}
#keyframes slide-in {
0% { transform: translateX(-100%); width: 0; }
100% { transform: translateX(0); width: auto; }
}
#keyframes slide-out {
0% { transform: translateX(0); width: auto; }
100% { transform: translateX(-100%); width: 0; }
}
DOM tree looks like this
<div id="contentContainer" class="flex">
<app-left-menu></app-left-menu>
<div>Be smooth!</div>
</div>
Is there any way, to "smooth" transition parent width, when "left-menu" is hiding? I try to add styles for parent, with
transition-property: width;
transition-duration: 0.6s;
but it doesn't work.
https://im2.ezgif.com/tmp/ezgif-2-a1f74da85c.gif
Assume It only flickers when comes to animate, so you can try to use will-change, css-will-change-property
The will-change CSS property hints to browsers how an element is expected to change. Browsers may set up optimizations before an element is actually changed
If you are using framework like React can try to use framer-motion

Css transition not transitioning back to original state when using animation with it

I am trying to make a loading animation. I am using css transition to transition into the loading by scaling and then using animation to scale out the x axis. But when I try to transition back to the original state it doesn't use the transition anymore it just snaps back. I could use animation for the whole thing but I want to account for the page continuing to load so I don't want to have to write extra javascript logic to handle it. It would be nice if It would just transition on its own.
When you click the following snippet the first time it works fine. But when you click it again it just snaps back to its original state and doesn't use the transition. If you use a different property like opacity in the animation part then it works fine so I'm assuming there is something with the browser not recognizing the current scaled value. Is this a bug or am I doing something wrong?
document.querySelector('.wrapper').addEventListener('click', () => {
document.querySelector('.wrapper').classList.toggle('loading')
})
.wrapper{
position:fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.wrapper > div{
color: white;
display:flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
background: blue;
transition: transform 500ms ease-out;
transform: scale(1);
}
.wrapper.loading > div{
transform: scale(0.2, 0.002);
animation: loading 1000ms ease-out infinite;
animation-delay: 500ms;
}
#keyframes loading {
0%{
transform: scale(0.2, 0.002)
}
50%{
transform: scale(0.5, 0.002)
}
100%{
transform: scale(0.2, 0.002)
}
}
<div class="wrapper">
<div>click me</div>
</div>
TL;DR
I believe that this happens because CSS transition eventually gives a class two states and transitions between them, when you remove your class you don't change its state, you remove it. my solution would be to add another class to set it back.
CSS transitions work by defining two states for the object using CSS. In your case, you define how the object looks when it has the class "loading" and you define how it looks when it doesn't have the class "saved" (it's normal look). When you remove the class "loading", it will transition to the other state according to the transition settings in place for the object without the "loading" class.
If the CSS transition settings apply to the object (without the "loading" class), then they will apply to both transitions.
your transition CSS settings only apply to .saved and thus when you remove it, there are no controls to specify a CSS setting. You may want to add another class ".fade" that you leave on the object all the time and you can specify your CSS transition settings on that class so they are always in effect.
I don't know a pure css fix for this.
But you can add a different class with a animation that restores to what it was before with JS
const wrapper = document.querySelector(".wrapper");
wrapper.onclick = () => {
if ([...wrapper.classList].includes("loading")) {
wrapper.classList.add("restore");
} else {
wrapper.classList.remove("restore");
}
wrapper.classList.toggle("loading");
};
.wrapper {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.wrapper>div {
color: white;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
background: blue;
animation: none;
transform: scale(1);
transition: transform 500ms ease-out;
}
.wrapper.restore>div {
animation: restore 500ms ease-out;
}
.wrapper.loading>div {
transform: scale(0.2, 0.002);
animation: loading 1000ms 500ms ease-out infinite;
}
#keyframes restore {
0% {
transform: scale(0.2, 0.002);
}
100% {
transform: scale(1);
}
}
#keyframes loading {
0% {
transform: scale(0.2, 0.002)
}
50% {
transform: scale(0.5, 0.002)
}
100% {
transform: scale(0.2, 0.002)
}
}
<div class="wrapper">
<div>click me</div>
</div>
You can use animation iteration count property:
div {
animation-iteration-count: 2;
}
or use fill mode to freeze the animation at the end:
-webkit-animation-fill-mode: forwards;

keyframe animation not working properly - CSS

I have an angular component that has a button and the button triggers a sidePanel and the side panels slidesOut over the component that has the button triggering the side panel to come out. I have 2 issues I can solve. The side panel has a width of 350px;
1) When the component with the button is loaded you can see the sidePanel doing the animation to hide
2) The slideIn works fine but the slideOut moves really fast
HTML
<div class="credit-card-container {{toggleSideBarFlag ? 'showSideBar': 'hideSideBar'}} {{ submittingPayment ? 'payment-success-container' : ''}}">
<app-bulk-pay-credit-card [ccTotalDue]="totalDue" [pickupAvailabilityList]='selectedEquipment' (submittingPayment)="isSubmittingPayment(true)"
(toggleSideBar)="onToggleSideBar(false)" (close)="onCloseBulkPay(false)"></app-bulk-pay-credit-card>
</div>
CSS
.bulk-pay-storage-container {
.showSideBar {
width: 100%;
display: block;
position: absolute;
z-index: 9999;
animation: slideIn 1s;
}
.hideSideBar {
width: 100%;
display: block;
position: absolute;
right: -350px;
z-index: 9999;
animation: slideOut 1s forwards;
}
}
#keyframes slideIn {
0% {
transform: translateX(350px);
}
100% {
transform: translate(0);
}
}
#keyframes slideOut {
100% {
transform: translateX(350px);
}
}
I would use transitions rather than animations in your example.
You can basically toggle between having showSideBar class and not having it.
Sidebar's start position is hidden outside of the viewport (left: -350px) and its visible state is left: 0.
Set left and transition properties on your sidebar and remove the animation property.
.bulk-pay-storage-container {
/ ... /
left: -350px;
transition: left 2s;
}
.bulk-pay-storage-container.showSideBar {
left: 0
}

run css animation when visible on scroll

I'm creating my test webpage and I ran into a problem, there are quite a few "answers" on my issue but none was I able to implement in my code. I know I have to use javascript but I was not able to get it working.
So, I need to run css animation of movement on chosen picture, when that picture is visible on screen when I scroll down to it. Basically like on this page: https://www.photoblog.com/
So I have this code in the html as for the picture:
<img class="movepic" src="pictures/test.jpg">
And then there is this simple code for the CSS movement:
.movepic {
position: relative;
animation-name: move;
animation-duration: 3s;
visibility: visible;
animation-fill-mode: forwards;
z-index:10;
}
#keyframes move {
0% { right:0px; top:150px;}
100% {right:700px; top:150px;}
}
Is there a way to make it work so I do not need to completely redo this? Or if so, could some please give me a advice how to do it maybe with code ilustration.
Thanks a lot
I use this code for this effect:
HTML:
<img class="movepic" src="pictures/test.jpg">
CSS:
.movepic {
opacity: 0;
margin: 25px 0 0;
color: white;
padding: 10px;
}
.FadeIn {
-webkit-animation: slideIn 0.8s ease 0.3s forwards;
animation: slideIn 0.8s ease 0.3s forwards;
}
#keyframes slideIn {
0% {
-webkit-transform: translateY(40px);
opacity: 0;
}
100% {
-webkit-transform: translateY(0px);
opacity: 1;
}
}
JQuery:
var $fade = $(".movepic"); //Calling the class in HTML
$(window).scroll(function () { //Using the scroll global variable
$fade.each(function () {
fadeMiddle = $(this).offset().top + (0.4 *$(this).height());
windowBottom = $(window).scrollTop() + $(window).height();
if (fadeMiddle < windowBottom) {
$(this).addClass("FadeIn");
}
});
});
/* On Load: Trigger Scroll Once*/
$(window).scroll();
Remove the animation-name from your style rule:
.movepic {
position: relative;
animation-duration: 3s;
animation-fill-mode: forwards
visibility: visible;
z-index:10;
}
and add this class to stylesheet:
.animation-class {
animation-name: move
}
Now add the jQuery:
var has_fired;
$("html").on("scroll", function () {
if (!has_fired && $(this).scrollTop() >= $("#imgContainer").offset().top) {
$("#imgContainer").addClass("animation-class");
has_fired = true; // use this if only want fired once
}
});
The animation will now run. BTW I would add an ID (imgContainer) to your container of interest and use this as selector for matching because unless .movepic is a unique class, this function will fire for any container with the .movepic class (if .movepic is the selector).

Remove/Hide div from DOM after animation completes using CSS?

I have an animation where a div slides out the view, however when the animation is completed, the div just returns to its origin position in the view. How do I totally remove the div or hide it after the animation ends using just CSS?
Here is the markup:
<div class="container">
<div class="slide-box" id="slide-box""></div>
</div>
and the css:
.slide-box {
position: relative;
width: 100px;
height: 100px;
background-image: url(../pics/red.png);
background-position: center;
background-size: cover;
background-repeat: no-repeat;
animation: slide 5s linear 1;
}
#keyframes slide {
0% {
left: 0;
}
20% {
left: 20%;
}
40% {
left: 40%;
}
60% {
left: 60%;
}
80% {
left: 80%;
}
100% {
left: 100%;
overflow: hidden;
visibility: hidden;
}
}
I don't want it to fade out over the duration of the animation, i just want it to disappear once it hits 100% in the keyframe. Thanks ahead of time!
Use the animation-fill-mode option. Set it to forwards and the animation ends at it's final state and stay like that.
Altered based upon comments Set opacity fade to just last 1% of animation... simplified keyframes. Added a jquery option to literally remove the div from the DOM. CSS alone won't alter the markup, where jQuery will.
Although you can't animate the display property. If you want the div totally gone, after the opacity fades to zero, you can then add the display property to remove the div. If you don't wait for opacity to end, the div will just vanish without any transition.
/*
This jquery is added to really remove
the div. But it'll essentially be
VISUALLY gone at the end of the
animation. You can not use, or
delete the jquery, and you really
won't see any difference unless
you inspect the DOM after the animation.
This function is bound to animation
and will fire when animation ends.
No need to "guess" at timeout settings.
This REMOVES the div opposed to merely
setting it's style to display: none;
*/
$('.slide-box').bind('animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd', function(e) { $(this).remove(); });
.slide-box {
display: block;
position: relative;
left: 0%;
opacity: 1;
width: 100px;
height: 100px;
background: #a00;
animation: slide 1s 1 linear forwards;
/*
animation-name: slide;
animation-duration: 1s;
animation-iteration-count: 1;
animation-timing-function: linear;
animation-fill-mode: forwards;
*/
}
#keyframes slide {
0% {
left: 0%;
opacity: 1;
}
99% {
left: 99%;
opacity: 1;
}
100% {
left: 100%;
opacity: 0;
display: none;
}
}
#-webkit-keyframes slide {
0% {
left: 0%;
opacity: 1;
}
99% {
left: 99%;
opacity: 1;
}
100% {
left: 100%;
opacity: 0;
display: none;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="slide-box" id="slide-box"></div>
</div>
animation: slide 5s linear forwards;
at 100%
opacity: 0;
display: none;
Try this.
Working fiddle: https://jsfiddle.net/jbtfdjyy/1/
UPDATE: JS mani
var slideBox = document.getElementById('slide-box');
setTimeout(function(){
slideBox.style.display = 'none';
}, 5000);
Try this. https://jsfiddle.net/jbtfdjyy/2/
Add something at 99% or so to your keyframes, and set opacity to 1 in that. If you have opacity: 1 at the start, then it will stay that way until 99%. Only at 100% will it change.
It's not technically fired at 100%. If you want that, I'd recommend using some JavaScript here, but this will at least give the illusion you want.
#keyframes slide {
0% {
left: 0;
}
20% {
left: 20%;
}
40% {
left: 40%;
}
60% {
left: 60%;
}
80% {
left: 80%;
}
99% {
opacity: 1;
}
100% {
left: 100%;
overflow: hidden;
opacity: 0;
display: none;
visibility: hidden;
}
}
UPDATE:
As per your request, here is a JavaScript version. Keep in mind, there are endless ways to accomplish such a task. I am using vanilla JS (no jQuery, etc.), and using ES6 syntax.
What we do here is set a timeout, and at the end of that timeout I broadcast an event animation_end. That event listener will handle the end of the animation (in this case, it adds a class which will handle the fading out). This is much more granular than you need it to be, you could simply do the adding of the class within the setTimeout, but I think it is slightly better this way as you can abstract you can do other things with events such as animation start, etc.
Here is the fiddle: https://jsfiddle.net/vmyzyd6p/
HTML:
<div class="container">
<div class="slide-box" id="slide-box""></div>
</div>
CSS:
.slide-box {
position: relative;
width: 100px;
height: 100px;
background-color: blue;
animation: slide 3s linear 1;
-webkit-transition: opacity 2s ease-in-out;
-moz-transition: opacity 2s ease-in-out;
transition: opacity 2s ease-in-out;
}
.animationEnd {
opacity: 0;
}
#keyframes slide {
0% {
left: 0;
}
20% {
left: 20%;
}
40% {
left: 40%;
}
60% {
left: 60%;
}
80% {
left: 80%;
}
100% {
left: 100%;
}
}
JavaScript:
// Create a function that handles the `animation_end` event
const animationEnd = () => {
// Grab the slidebox element
let slideBox = document.getElementById('slide-box');
// Get the class of the slidebox element
let slideClass = slideBox.getAttribute('class');
// Add the animation end class appended to the previous class
slideBox.setAttribute('class', slideClass + ' animationEnd');
};
// Create the animation end event
let animationEndEvent = new Event('animation_end');
// Cross browser implementation of adding the event listener
if (document.addEventListener) {
document.addEventListener('animation_end', animationEnd, false);
} else {
document.attachEvent('animation_end', animationEnd);
}
// Set the timeout with the same duration as the animation.
setTimeout(() => {
// Broadcast the animation end event
document.dispatchEvent(animationEndEvent);
}, 3000);