Removing class from element isn't triggering css animation - javascript

I'm building a carousel (slideshow) effect for my website and I have little issue. At every image change I want to make fade effect. So I've added a class with animation for it. And here the problem comes.
This function is firing every 3 sec (setInterval)
let sliderInterval = setInterval(nextImg, 3000);
function nextImg() {
imgChange(sliderNum + 1);
}
const heroImg = document.querySelector('.hero__image');
function imgChange(x) {
heroImg.classList.remove("fade");
sliderNum = (x + imgLocations.length) % imgLocations.length;
heroImg.src = imgLocations[sliderNum];
heroImg.classList.add("fade");
}
Fade effect:
.fade {
animation: fade 1.5s ease-in-out;
}
#keyframes fade {
from {opacity: .4}
to {opacity: 1}
}
<div class="hero">
<img class="hero__image" src="photo1">
</div>
It works only for first image switch. Altough at the start of function it shall remove the class fade I see in function that it stays there in element and won't gone. It doesn't matter if I try to put this effect on hero section or img within it.

The problem is that css animations with keyframes will by default only run once. It is possible to alter the amount of times they run, but that will run them constantly in a loop which is undesirable.
Instead, what needs to happen is the animation needs to be reset. In order to do this, the element needs to have its animation name removed (fade in this case). This can be done with animation-name: none;, however, the rule needs to be placed on the element when fade is removed. Note the change to the selector to make the fade animation name take precedence when applied.
On top of this, it is important to note that if you remove and add the same class in a function, due to the way that browsers work, nothing will happen. In order for the browser to recognize any changes made, a page repaint must occur (here is a list of what makes that happen). In order to force the page to repaint, I chose to use offsetHeight, which is why you see heroImg.offsetHeight used in the code (note that it only needs to be read, it doesn't have to be used or assigned).
I mocked your image with a div for convenience.
let sliderInterval = setInterval(imgChange, 3000);
const heroImg = document.querySelector('.imgMock');
function imgChange() {
heroImg.classList.remove("fade");
heroImg.offsetHeight; // force repaint to recognize `animation-name: none;`
heroImg.classList.add("fade");
}
.imgMock.fade {
animation: fade 1.5s ease-in;
}
#keyframes fade {
from {opacity: .4}
to {opacity: 1}
}
.imgMock {
height:50px;
width:50px;
background-color:black;
animation-name: none;
}
<div class="hero">
<div class="imgMock"></div>
</div>

Related

jQuery .fadeOut method on and element that is being appended after DOM load

(I am 9 weeks into a boot camp, so I apologize for the potentially rudimentary nature of this...)
I am appending an element to the DOM (a button) within a conditional:
$('.buttonsAndInputs').append(`<button id="clearHistoryButton">Clear All</button>`);
When this button is clicked, it runs through a series of functions to empty an array and clear some other content off the DOM. I would like to use the .fadeOut method of jQuery to remove THE BUTTON.
I have this in a subsequent function:
$('#clearHistoryButton').remove();
I would like to:
$('#clearHistoryButton').fadeOut(1000);
...so that it disappears in a fancy fashion.
It's not working - it simply waits one second and then - POOF - is gone.
This is my first question. This community has been ESSENTIAL in my growth in this realm and, as always, I appreciate all of you so very much.
Did you try transition: opacity 1s in your CSS ?
Advantage:
Hardware accelerated (GPU), i.e. it doesn't bother your main processor (CPU) with this task, whereas jQuery's fadeOut() function is software based and does take CPU resources for that effect.
Steps:
Add transition: opacity 1s to your CSS rules of the desired button element
here: ( #clearHistoryButton )
Add a CSS rule with button.fadeMeOut with opacity: 0
Add a simple jQuery function to add the class ".fadeMeOut" at click
Then remove button with setTimeout(function(){$('#clearHistoryButton').remove()},1000)
Run code snippet
$(function() { // Shorthand for $( document ).ready()
$("#clearHistoryButton").on( "click", function() {
// first: fade out the button with CSS
$(this).addClass("fadeMeOut");
// then: after fadeOut effect is complete, remove button from your DOM
setTimeout(function(){
$('#clearHistoryButton').remove();
},1000);
});
});
button {
opacity: 1;
-webkit-transition: opacity 1s;
-moz-transition: opacity 1s;
transition: opacity 1s;
}
button.fadeMeOut {
opacity: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="clearHistoryButton">Press to hide me</button>

Does an element animation run after setting display to a visible state?

Does an animation run after setting the display to block?
I'm setting the animation style of an element and then setting the display from none to block. It is playing the animation for me but I've read that display doesn't trigger animations. Who is correct?
Part of the Code:
// method 1 - enable a media query
var animation = "fadein 1s ease-out";
element.style.setProperty("animation", null, "important");
element.style.setProperty("animation", animation, "important");
enableQuery(rule); // manually enable a media query
// method 2 - set display none to block
element.style.display = "block";
var animation = "fadein 1s ease-out";
element.style.setProperty("animation", null, "important");
element.style.setProperty("animation", animation, "important");
CSS
#keyframes fadein {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
If you display is none outside of a media query and then you enable a media query that sets the display to block then that would cause the animation to play? Does requestAnimationFrame fit into any of this?
From the specification:
Setting the display property to none will terminate any running animation applied to the element and its descendants. If an element has a display of none, updating display to a value other than none will start all animations applied to the element by the animation-name property, as well as all animations applied to descendants with display other than none.
I have nothing more to add. I guess it's pretty clear.

My css animation and JQuery are not syncing up

I'm building a simple blinking div, it blinks every 3s:
.timer { opacity: 1; animation: blink 3s alternate infinite; }
#keyframes blink { to {opacity: .25;} }
and it's text content is updated every 3s as well, counting down from 50 to 0:
var number = 50;
window.setInterval(function countdown(){ $('.timer').text(number--); }, 3000);
However for some reason my animation and JQ slowly become out of sync, you'll notice it after a few animations have run through. I'm wondering how I could go about assuring that they keep in time with each other.
JS Fiddle:
https://jsfiddle.net/rourkemclaren/61ry4s1j/3/
Thanks in advance.
The issue is related to the CSS alternate flag. If you remove it the effect becomes more streamlined.
Note that you can also listen to the CSS animation events using JavaScript instead of using the setInterval:
$('.timer').on('animationiteration', function() {
$(this).text(--number);
});

Assigning classes to a slide within a basic css slider

Basically I have a really simple (makes a change) slider that is done with css only. There are labels for the nav buttons and they are unique for each slide. Question is , How can I add/remove classes to certain items within the slide ONLY WHEN the slide is navigated to.
As with sliders they tend to load everything when the slider loads and I want to add cool animations to the bits on the slides so makes it pointless if everything loads at slide one.
jsfiddle http://jsfiddle.net/greggy_coding/013481b9/3/
I have provided some jsfiddle mock up of the slider and the classes animated and fade which are the ones in this instance i want to add and remove on the specific slide loading .. I will then assign them to different bits on the slide...
.animated {
-webkit-animation-duration: 1s;
animation-duration: 1s;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
}
.fadeInUpBig {
-webkit-animation-name: fadeInUpBig;
animation-name: fadeInUpBig;
opacity: 0.3;
background-color: rgba(0,0,0,0.3);
}
CSS allows you to create animations with transitions and keyframes that once were only possible with JavaScript or Flash. Unfortunately, with CSS there’s no way to perform a callback when an animation is complete. With JavaScript, it’s possible to detect the end of a CSS transition or animation and then trigger a function.
Using JavaScript, we can detect the transitionend event; however for cross-browser, support we need to include the other browsers’ prefixes.
$(function() {
//Store a ref to slides
var $slides = $(".slides");
//Bind event to the contianed that gets animated
$(".slide-container")
.on("transitionend webkitTransitionEnd oTransitionEnd msTransitionEnd", function(e){
// Remove classes from all the elements within the active container that starts with the class 'add-anim'
$slides.find(".slide-container [class^='add-anim']").removeClass("animated bounceInLeft bounceInUp");
//Add appropriate classes to the matched elements within the active container
var $radio = $slides.find(":radio[name='radio-btn']:checked");
$radio.next(".slide-container").find(".add-anim-up").addClass("animated bounceInUp");
$radio.next(".slide-container").find(".add-anim-left").addClass("animated bounceInLeft");
});
});
Here is your entire code with HTML+JS+CSS.
Note: The above solution works, but the problem is, depending on the browser, it can fire twice (i.e. Chrome supports both webkitTransitionEnd and transitionend). There are ways to overcome this though, by detecting the supported event property. Take a look at this demo for more details.
Hope that helps.

Why does the transition not work?

I got a Section named "login" and a Section named "register".
When the opacity of them changes, I want to have a linear transition that take 0.3 seconds.
CSS:
#login{
opacity: 0;
transition:opacity 0.3s linear;}
#register{
opacity: 0;
display: none;
transition:opacity 0.3s linear;}
When you go on the Homepage HERE and click on "Query",
the opacity of #login changes to 1. That works fine with the transition!
When you click "oder registriere dich neu" below the Login-Form,
the Login-Section gets opacity: 0 again - then get display: none.
That also works perfect with a transition.
BUT than the REGISTER-Section is put to display: block and then opacity: 1 (after a setTimeout of 500 Milli-seconds.)
This don't have a transition! why?
When i click "Hast du schon einen Account?" again (to get back to the login),
the register Block will fade out with a transition perfecty again, and the login-form comes up without a transition again?
Here's the Javascript code for setting the opacities:
function changeSection(IDOut, IDIn)
{
var IDOut = "#" + IDOut;
var IDIn = "#" + IDIn;
hideSection(IDOut);
showSection(IDIn);
}
function hideSection(IDOut)
{
$(IDOut).css({opacity: "0"});
setTimeout(function(){
$(IDOut).css({display: "none"});
},500);
}
function showSection(IDIn)
{
setTimeout(function(){
$(IDIn).css({display: "block"});
$(IDIn).css({opacity: "1"});
},500);
}
IDOut is the Section, I want to Fade out (witch works perfect for login and register).
IDIn is the Section, I want to Fade in (witch DON'T WOKR for login and register)!
Why does the transition not work for IDIn?
Any Ideas?
You are using jQuery, you can do this alot simpler and let the jQuery handle it for you.
instead of your code for showSection and hideSection, use:
$('#yourselector').fadeIn(300);
to fade an element in with a time of 300 miliseconds, and:
$('#yourselector').fadeOut(300);
to hide it.
The transition does not work according to your code.
The IDIn originally has the display property as none and opacity as 0.
According to the function showSection, you first wait for 500ms, and then set the display and opacity property simultaneously to what you want. Concurrency is the problem, because display and opacity are changed in one animation frame at the same time, but the browser has to choose one property to transit. And it choose display.
More technically, transition only works on elements that are visible and have dimension. The width and height must not be zero. So display:none; cancels out your transition.
So the solution is easy, just put display outside of your setTimeout. Make display changed first.
The benefit over native jQuery method fadeIn is that it utilizes css transition, which is more efficient than jQuery's underlying animation.
function showSection(IDIn)
{
$(IDIn).css({display: "block"});
setTimeout(function(){
$(IDIn).css({opacity: "1"});
},500);
}

Categories