How can I stop this jQuery from bugging out? - javascript

So I'm trying to create a box that has two layers: The front layer and the back layer. They're going to be stacked on top of each other so the back layer is hidden by default.
When you hover over the top of the box (front layer technically), then the front layer is supposed to slide up revealing the back layer. I tried to do this by using .slideUp() and .slideDown() but it kept bugging out revealing both layers at the same time. So then I switched to just .slideUp() and .fadeIn() but that didn't seem to help too much.
As you can see, it sometimes shows both divs when it's not supposed to and it also slides multiple times randomly. How could I make this more efficient?
Here is a JsFiddle
UPDATE:
Questions seeking debugging help ("why isn't this code working?") must
include the desired behavior, a specific problem or error and the
shortest code necessary to reproduce it in the question itself.
Questions without a clear problem statement are not useful to other
readers.
That is the reason people are voting to close this answer... What does this question not have, from that list?
Desired behavior? - Check
Specific problem? - Check
Shortest code necessary? - Check
Clear problem? - check

You don't really need to use slideUp and slideDown, you can achieve the slide effect by using the transform and transition CSS3 properties.
Updated JS fiddle: https://jsfiddle.net/9uw2q24h/3/
Javascript:
$('.outer').hover(function() {
$(this).children('.front').addClass('front-up');
}, function() {
$(this).children('.front').removeClass('front-up');
});
CSS:
.outer {
position: relative;
.front,
.back {
text-align: center;
width: 100%;
}
.back {
display: block;
}
.front {
position: absolute;
transition: 0.5s ease;
}
.front-up {
transform: translateY(-100%);
}
}
If you have to support older browsers, make sure to add the vendor prefixes to the transition and tranform rules (-webkit-, -moz-, etc.).

You can do this like:
var running = false;
$('.outer').hover(function() {
if (!running) {
running = true;
$(this).children('.front').slideUp(function() {
$(this).next('.back').slideDown(function() {
running = false;
});
});
}
}, function() {
if (!running) {
running = true;
$(this).children('.back').slideUp(function() {
$(this).prev('.front').slideDown(function() {
running = false;
});
});
}
});
Explanation: as soon as the animation starts you save the status in a variable in order to avoid conflicts (otherwise it will be called again). Additionally with the slideDown and slideUp combined you have a much smoother animation. You had a not very nice flickering with your combination of fadeOut and slideDown
Fiddle: https://jsfiddle.net/dL7ckq6b/

With a slight tweak to your CSS, specifically making your elements' position property absolute, will cause your back element to be behind your front element from the start, now you only have to show/hide your front element.
Javascript:
$('.outer').hover(function() {
$('.front').slideUp();
console.log("IN");
}, function() {
$('.front').slideDown();
console.log("OUT");
});
I did also update the CSS to more clearly show the effect happening.
CSS:
.outer {
.front,
.back {
text-align: center;
position: absolute;
padding: 20px 10px;
border: 2px solid yellow;
}
.front {
z-index: 10;
background-color: red;
}
.back {
z-index: 0;
background-color: blue;
}
}
Here is the JSFiddle: https://jsfiddle.net/z8e7eb4b/

Related

Hiding element after css transition

I have this element that starts hidden and then gets animated with a css transition on a click event.
I know the display property cannot be animated, so what I do is remove the class that applies the display:none, and then make the change that triggers the css transition, like so:
popin.classList.remove('hidden') // removes the display:none property
setTimeout(() => {
popin.classList.remove('closed') // triggers transition
}, 10)
See this fiddle: http://jsfiddle.net/wre2674p/6/ for a full example.
I've found out that in order to work, the 2nd step must be done asynchronously. Put it in a setTimeout and it works...sort of. In Chrome, any timeout duration works (even 0).
For Firefox and Edge, the behavior varies. For 100ms, it works every time. But for a timeout of e.g. 10ms, the transition works only maybe 50% of times. Since it delays the animation, I wish to keep it as low as possible, while ensuring it works consistently.
I suspect it is related to reflow/repaint occurring when changing display property from none to block, but I lack details on these subjects to full understand what's happening and how to prevent it. Any idea?
Remove the hidden class from CSS and HTML, remove timeout from js. There is no need to display none the #popin since you already have overflow hidden. The transition can be triggered directly, you are over complicating things
document.getElementById('toggle').addEventListener('click', function(e){
let source = e.currentTarget
source.disabled = true
let popin = document.getElementById('popin')
if (popin.classList.contains('closed')){
popin.classList.remove('closed')
}
else{
popin.classList.add('closed')
}
setTimeout(() => {
source.disabled = false
}, 850)
})
body{
overflow: hidden;
}
#popin{
display: block;
position: absolute;
top: 0;
right: 0;
width: 400px;
height: 100vh;
/*transform: translate(0, 0);*/
transition: opacity 800ms;
opacity: 1;
background: lightgreen;
}
#popin.closed{
opacity: 0;
z-index: -1;
pointer-events: none;
}
<button id="toggle">toggle</button>
<div id="popin" class="closed">
<h1>Popin</h1>
</div>

How can I make this Jquery animate() with css3 animations?

This is my jfiddle
And this is my actual code
$card.animate({
left: "1000px"
}, 500, function(){
$card.hide(500);
});
(I dont know why 'left' didnt work on jfiddle) Basically ive got a container with 5 $cards there. When user swipes the card (already implemented) the animate() is triggered and the card slides to the rightand then disappears. How can I implement such thing in CSS animations instead of using Jquery? Ive read that CSS animations run faster (and I proved it on my mobile device, the hide() runs really slow)... Any help or advice will be appreciated
First of all, create a class that you can trigger via jQuery that will have the animation.
Then, using you have two options: transition or animation. Transitions are simpler and more direct, but you can do more with animations.
Here is how I would suggest to do it: a transition for the movement, and an animation to recreate the hide() function.
#keyframes hide {
99% { display: auto; }
100%{ display: none; opacity: 0; }
}
.myelement {
transition: all .5s;
position: absolute;
left: 0;
}
.myelement.toLeft {
left: 2000px;
animation: hide .5s 1 forwards;
}
To trigger it, simply do this:
$(".myelement").addClass("toLeft");
Here is a working JSFiddle.
And like #MohitBhardwaj said, it is necessary for you to set position to absolute, relative, or static in order for positioning (i.e., the left property) to work.
It's also important to note that a transition needs an initial value. I added left: 0 to do this. Otherwise, (with a CSS transition) it would simply jump to 2000px because there is no starting point.
Also, because 2000px as a left value is very large, I suggest you change the parent element's scroll to overflow: hidden, so that the extraneous scroll bar doesn't appear.
Your left didn't work, because you need to set position to a value other than static (which is default) for it to work.
As for using CSS, you can add a class instead of animating in jQuery. This class can change the transition which you can set in css as per your requirements.
var my_div = $('.myelement');
my_div.on('click', function() {
var $this = $(this);
$this.addClass("gone");
setTimeout(function(){
$this.hide();
}, 600 );
})
#mywrapper
{
overflow: hidden;
}
.myelement {
height: 200px;
width: 200px;
background-color: red;
opacity: 1;
position: relative;
transition: all 0.5s ease;
opacity: 1;
left: 0px;
}
.myelement.gone
{
left: 500px;
opacity: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="mywrapper">
<div class="myelement">
Click me please
</div>
</div>

CSS-3 Transform bug, menu appearing stuck

I am using this plugin called transit.js to create a simple menu animation and basically I have the following menu, see below:
The code for the open and close of the menu is as follows:
$('.main-header .nav-toggle-button').on('click' , function() {
// $('.main-header .navigation').toggleClass('show');
if ($('.main-header .navigation').hasClass('show')) {
$('.main-header .navigation').stop().removeClass('show');
return false;
}
$('.main-header .navigation').stop().transition({
perspective: '1000px',
rotateY: '180deg',
duration : 0
}, function() {
$(this).addClass('show').stop().transition({ rotateY: '0' });
});
return false;
});
DEMO HERE, (I am sorry, the fiddle just doesn't recreate this issue.)
BUG: As you can see on close there is no animation, the menu goes away, now this bug occurs when the page is scrolled more than
200px+ and below 992px width, so basically when you click on the
hamburger, the menu opens with a rotate animation but when you
click the hamburger again the menu sometimes doesn't close even though
the 'show' class has been removed form the menu.
This is one of these bugs that is just beyond me, inspecting in the console and going through the JS code has just not really helped.
I would really appreciate if anyone can point out what I am doing wrong here, as the JS and CSS really seems to be perfect but the css transforms using transit is just not working as expected.
As already mentioned seems to be a Chrome bug, I tried editing the CSS on your demo and this solution seems to work ... try adding a "z-index" to -1 here:
#media (max-width: 992px)
.navigation {
display: none;
position: absolute;
top: 100%;
left: 0;
right: 0;
background: #fff;
background: rgba(255,255,255,.95);
z-index: -1; // ADD THIS
}
An alternate solution to your problem..
The problem I found is, on smaller screens, your mini-menu appears on-click of hamburger icon. But it doesn't disappear when clicked on hamburger icon again.
However, it disappears immediately if you scroll the window. So, I added two lines inside the if statement which actually scrolls the window 1px down and then 1px up (to keep the position of the document same). Add the following code inside your if statement (before return false; line).
window.scrollBy(0, 1);
window.scrollBy(0, -1);
I think that your mistake is that you re using the hover event to add and remove the animation, he just fire once that your mouse is over the element:
/* dropdown */
$('.navigation .dropdown-menu-item').hover(function() {
$('.navigation .dropdown-menu-item').find('.dropdown-menu-list').removeClass('opened');
$(this).find('.dropdown-menu-list').stop().transition({ 'y' : '20px' , duration: 0 } , function() {
$(this).addClass('opened').stop().transition({ 'y': 0 });
});
return false;
}, function() {
$(this).find('.dropdown-menu-list').removeClass('opened');
});
Use mouseenter and mouseleave events to add and remove the dropdown list animation, by this way you gonna have the events fired at over and leave:
$(document).on('.navigation .dropdown-menu-item', 'mouseenter', function(){
$('.navigation .dropdown-menu-item').find('.dropdown-menu-list').removeClass('opened');
$(this).find('.dropdown-menu-list').stop().transition({ 'y' : '20px' , duration: 0 } , function() {
$(this).addClass('opened').stop().transition({ 'y': 0 });
});
return false;
})
$(document).on('.navigation .dropdown-menu-item', 'mouseleave', function(){
$(this).find('.dropdown-menu-list').removeClass('opened');
})
Here is css solution...
with this your menu will open and close smoothly
add following css to your code and over-wright
#media(max-width:991px) {
.navigation {
transition: all 0.4s;
-webkit-transition: all 0.4s;
display: block;
transform: rotateY(90deg) !important;
-webkit-transform: rotateY(90deg) !important;
perspective: 1000px !important;
-webkit-perspective: 1000px !important;
opacity: 0;
visibility: hidden;
}
.navigation.show {
display: block;
opacity: 1;
transform: rotateY(0deg) !important;
-webkit-transform: rotateY(0deg) !important;
visibility: visible;
}
}
ENJOY...

Animation is sticking when I drag the cursor

I'm a super novice (I learned html, css, jQuery last week on codeAcademy) so this may be a dumb question.
However, when I drag my cursor quickly across the block in the following example the animation seems to stick, in other words, the blocks remain opaque. Could you all help me? My code it linked below. Thank you in advance.
http://jsfiddle.net/ivanjsfiddle00/eFShc/1/
$(document).ready(function() {
$(".button").hover(function() {
$(this).filter(':not(:animated)').animate({"opacity": 1 })
}, function() {
$(this).filter(':not(:animated)').animate({"opacity": 0.5 })
});
});
EDIT:
Thank you all. Substituting filter(':not(:animated)') with stop(true) worked.
You need to use stop() to clear the animation queue between events. This also makes your filter(':not(:animated)') redundant.
$(".button").hover(function () {
$(this).stop(true).animate({
"opacity": 1
})
}, function () {
$(this).stop(true).animate({
"opacity": 0.5
})
});
Example fiddle
#Rory seems to have answered the original question, but it's worth pointing out that another option would be to use CSS and make use of the :hover pseudo element.
.button {
float: left;
margin: 1px;
opacity: 0.5;
display: inline-block;
background-color: #757575;
width: 50px;
height: 50px;
}
.button:hover{
background-color:#323a44;
}
detecting if the element is in animating before animate
add if($(this).is(":animated")) return false; before your animate code

get previous siblings, accordion effect

I'm trying to get an accordion effect on a DIV when hovering.
The right side of the accordion is working already, but the left one isn't.
I put my code in jsFiddle
Can someone please help me with the left side? I've been trying it for hours but it won't work :(
Javascript:
$(document).ready(function () {
$('.middle').hover(function () {
$(this).siblings().stop().animate({
opacity: 1
}, 200);
},
function () {
$(this).siblings().stop().animate({
opacity: 0
}, 200);
});
});
The reason the right is fading, and the left isn't is because you are applying a CSS transition to the right side spans.
You can easily address this by applying the same transition to <span> tags:
.squares span {
transition-property:opacity;
transition-duration:1s;
transition-delay:0.1s;
}
In fact, you could condense your code and make it easier to adjust overall by combining repeated styles across the multiple spans into single definitions.
For example:
.squares span {
opacity: 0;
float: left;
width: 139px;
height: 138px;
transition-property:opacity;
transition-duration:1s;
transition-delay:0.7s;
}
span.middle {
background:#0f0;
opacity: 1;
}
span.left1,
span.right1 {
background:#00F;
transition-delay:0.1s;
}
span.left2,
span.right2 {
background:#0FF;
transition-delay:0.3s;
}
span.left3,
span.right3 {
background:#0F0;
transition-delay:0.5s;
}
span.left4,
span.right4 {
background:#FF0;
transition-delay:0.7s;
}
See the working example here: http://jsfiddle.net/uBBZ2/14/
In your css you set the transition-property and transition-duration settings on the right side blocks, but not the left side ones. If you comment them out, both transitions happen quickly and at the same time. If you add those settings mirrored to the left side, they both happen more slowly.

Categories