Issue when animating on hover effects with callbacks - javascript

So I am having this issue when I am using the hover event in jQuery. I have two containers side by side. I have hover events on both of them. When hover, a div with additional info slides up into frame. When you hover off, it slides back down.
Simple right? When you hover on an element it should remove the "hide-me" class and start sliding the info up (animating). When you hover off of an element the "hide-me" class should be removed once the animation is complete.This works fine when you hover on and hover off onto an element that is not a grid-item. When you hover off of an item onto another grid-item it seems to just add the class "hide-me" to the currently hovered element. Even though the hover off event hasn't fired yet.
Anyways enough talk here is the code on JS Fiddle:
https://jsfiddle.net/joemoe_1984/2k22yLmd/2/
For testing here is what works:
Hover from below/above image then hover out from below/above image
For testing how it doesn't work:
Hover from below/above image then hover out onto other image
UPDATE
Just to clarify a bit as I had an answer that got me the effect I wanted but didn't exactly solve the issue I was having exactly. I would like to know why the animation callbacks on complete don't properly work when hovering from one image to the other. This is the part that has been bugging me the most. When you hover on an image and then out it removes the class on hover then adds the class after the animation called from the hover out event finishes. This is the expected behaviour. When I hover over an image then onto the other image you will see that instead of adding the class to the first image on hover out, it adds it to the image you are current hovering. Its as if the animation callback is calling the wrong callback function once it animates up on hover.
The on hover state should never have the class added. It should be removed at this point. The class should also not be added during any of the animation states.
Just in case links aren't ok, here is the full html, css and javascript:
HTML
<div class="grid-container">
<div class="grid-item">
<a href="#" class="grid-inner">
<div class="grid-image">
<img src="http://vignette3.wikia.nocookie.net/metroid/images/8/86/Samus_artwork_11.jpg/revision/latest?cb=20100516174330" alt="">
</div>
<div class="grid-info hide-me">
<div class="middle-align">
<h4 class="grid-title">Some title</h4>
<div class="grid-details">
This is some info about this item
</div>
</div>
</div>
</a>
</div>
<div class="grid-item">
<a href="#" class="grid-inner">
<div class="grid-image">
<img src="http://vignette3.wikia.nocookie.net/metroid/images/8/86/Samus_artwork_11.jpg/revision/latest?cb=20100516174330" alt="">
</div>
<div class="grid-info hide-me">
<div class="middle-align">
<h4 class="grid-title">Some title</h4>
<div class="grid-details">
This is some info about this item
</div>
</div>
</div>
</a>
</div>
</div>
CSS
.grid-item {
width: 25%;
float: left;
overflow: hidden;
}
.grid-item img {
max-width: 100%;
height: auto;
}
.grid-inner {
position: relative;
display: block;
}
.grid-info {
position: absolute;
background: blue;
color: white;
width: 100%;
height: 100%;
}
.hide-me {
display: none;
}
.middle-align {
position: relative;
top: 50%;
-webkit-transform: translateY(-50%);
-ms-transform: translateY(-50%);
transform: translateY(-50%);
}
Javascript
$(document).ready(function() {
$('.grid-item').hover(hover_in, hover_out);
function hover_in(e) {
$info = $(e.currentTarget).find('.grid-info');
target_height = $(e.currentTarget).height();
$info.css('top', target_height).removeClass('hide-me');
$info.stop().animate({
'top': 0,
}, 500, function() {
console.log('animated up');
});
}
function hover_out(e) {
$info = $(e.currentTarget).find('.grid-info');
target_height = $(e.currentTarget).height();
$info.stop().animate({
'top': target_height,
}, 500, function() {
console.log('animated down');
$info.addClass('hide-me');
});
}
});

Try substituting using .show() after call to .stop() for .removeClass('hide-me') at hover_in
$(document).ready(function() {
$('.grid-item').hover(hover_in, hover_out);
function hover_in(e) {
$info = $(e.currentTarget).find('.grid-info');
target_height = $(e.currentTarget).height();
$info.css('top', target_height) //.removeClass('hide-me')
.stop()
.show()
.animate({
'top': 0,
}, 500, function() {
console.log('animated up');
});
}
function hover_out(e) {
$info = $(e.currentTarget).find('.grid-info');
target_height = $(e.currentTarget).height();
$info.stop().animate({
'top': target_height,
}, 500, function() {
console.log('animated down');
$info.addClass('hide-me');
});
}
});
.grid-item {
width: 25%;
float: left;
overflow: hidden;
}
.grid-item img {
max-width: 100%;
height: auto;
}
.grid-inner {
position: relative;
display: block;
}
.grid-info {
position: absolute;
background: blue;
color: white;
width: 100%;
height: 100%;
}
.hide-me {
display: none;
}
.middle-align {
position: relative;
top: 50%;
-webkit-transform: translateY(-50%);
-ms-transform: translateY(-50%);
transform: translateY(-50%);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<body>
<h1>Animation grid</h1>
<div class="grid-container">
<div class="grid-item">
<a href="#" class="grid-inner">
<div class="grid-image">
<img src="http://vignette3.wikia.nocookie.net/metroid/images/8/86/Samus_artwork_11.jpg/revision/latest?cb=20100516174330" alt="">
</div>
<div class="grid-info hide-me">
<div class="middle-align">
<h4 class="grid-title">Some title</h4>
<div class="grid-details">
This is some info about this item
</div>
</div>
</div>
</a>
</div>
<div class="grid-item">
<a href="#" class="grid-inner">
<div class="grid-image">
<img src="http://vignette3.wikia.nocookie.net/metroid/images/8/86/Samus_artwork_11.jpg/revision/latest?cb=20100516174330" alt="">
</div>
<div class="grid-info hide-me">
<div class="middle-align">
<h4 class="grid-title">Some title</h4>
<div class="grid-details">
This is some info about this item
</div>
</div>
</div>
</a>
</div>
</div>
</body>
jsfiddle https://jsfiddle.net/2k22yLmd/3/

Ok. So I figured it out. It turned out to be a scope issue. The problem stemmed from using e.currentTarget (or this) within the hover event scope. I stored that instance into a variable and then later used it in the callback of the animation sequence.
It appears that the current target changes from when the animation callback uses it giving me the unexpected results. For the animation callbacks I should have used the instance (this) within the scope of the animation callback function like so:
$info.stop().animate({
'top': target_height,
}, 500, function() {
console.log('animated down');
$(this).addClass('hide-me'); // this refers to the current animated object. This is the correct one.
$info.addClass('wrong-one'); // $info refers to the current hover event target which is the on hover item when it should be the hover off item. This is incorrect
});
You can test it out and see that going from one image to the next will now add the class hide-me to the correct one and add the class wrong-one to the currently hovered item which is not the expected behaviour I was looking for.
Thanks to everyone for pitching in on the answers and providing alternative solutions but this was real issue for me.

Related

Slide a div into appearance without jQuery

I am using onclick method on a link in order to display a div. However, it doesn't slide, it simply appears. How do I make it appear with a slide effect without using jQuery. The reason I don't want to use jQuery is because I want the page to load as fast as possible.
function view() {
document.getElementById('topmenu').setAttribute('style', 'display:block');
}
#topbar {
background-color: yellow;
overflow: auto;
}
#topmenu {
display: none;
}
<header>
<div id="topbar">
<img src="/images/santorini-wedding-photographer-logo.png" style="float: left;">
<span style="float: right;">MENU</span>
</div>
<div id="topmenu">
some text here
</div>
</header>
It can be done using Javascript
setInterval() and clearInterval() functions.
See code samples here
JavaScript slidedown without jQuery
You can't apply transition to display property - you can transition scale instead - see demo below:
function view() {
// add a class to show the element
document.getElementById('topmenu').classList.add('show');
}
#topbar {
background-color: yellow;
overflow: auto;
}
#topmenu {
transform: scaleY(0); /* scale to zero vertically */
transform-origin: top; /* set origin to top */
overflow: hidden;
transition: transform 1s; /* apply transition to only scale */
}
#topmenu.show {
transform: scaleY(1); /* scale to full height */
}
<header>
<div id="topbar">
<img src="https://via.placeholder.com/50" style="float: left;">
<span style="float: right;">MENU</span>
</div>
<div id="topmenu">
some text here
</div>
</header>

CSS transition duration not applying on first instance of transition effect

I'm trying to create a series of sliding divs triggered on press of a button. The idea is that each div will have a thumbnail and some text tied to it. Upon clicking left/right button, the divs will move their position accordingly.
My code can be seen in the jsfiddle below. I'm encountering 3 problems:
1) The "transition: left 2s" rule isn't applying on the first transition effect, it does on the subsequent ones.
2) I'd like the repeat pressing of the corresponding buttons to apply the left property value again so that I can slide the divs repeatedly.
3) Instead of the "right" button re-positioning the "left" property back to 0, I'd like to shift it back in the opposite direction with the previous left property value.
Essentially I'm trying to recreate the slider found on this side.
http://www.euphoriumbakery.com/
Any help or input will be greatly appreciated.
Thank you very much for your help.
https://jsfiddle.net/kshatriiya/g709swLg/1/
window.onload = function() {
$("#left").on("click", function() {
$("#view").css("left", "-262px");
});
$("#right").on("click", function() {
$("#view").css("left", "0px");
});
}
#galwrapper {
width: 650px;
height: 400px;
display: block;
overflow: hidden;
}
#view {
position: relative;
width: 1423px;
transition: left 2s;
}
.col-md {
display: inline-block;
margin-top: 100px;
width: 18%;
}
.thumb img {
opacity: 0.9;
height: auto;
width: auto;
max-height: 150px;
max-width: 150px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="galwrapper">
<div id="view">
<div class="col-md">
<div class="thumb">
<img class="img-rounded" src="http://netdna.walyou.netdna-cdn.com/wp-content/uploads/2010/09/retrocake1.jpg">
<div class="caption">
<h4>Retro Cake</h4>
</div>
</div>
</div>
<div class="col-md">
<a href="#" class="thumb active">
<img class="img-rounded" src="https://i.ytimg.com/vi/dh8ii5sbvyc/maxresdefault.jpg">
<div class="caption">
<h4>Strawberry Cake</h4>
</div>
</a>
</div>
<div class="col-md" id="mid">
<a href="#" class="thumb">
<img src="https://i.ytimg.com/vi/dh8ii5sbvyc/maxresdefault.jpg">
<div class="caption">
<h4>Retro Cake</h4>
</div>
</a>
</div>
#view {
position: relative;
width: 1423px;
left:0;
transition: left 2s;
}
Initially make left:0; for the div with id view https://jsfiddle.net/81tqeof4/6/
and for sliding effect get the current left position and update the position.check fiddle for an example
$("#left").on("click", function(){
var leftPosition = parseInt($("#view").position().left) - 256;
$("#view").css("left", -Math.abs(leftPosition));
});
transition works only on an existing property
So initially(in your CSS) you do not have a left property available in your #view. It is only later on a click that your JavaScript adds the left and your transition starts working.
So basically you need to set the left property to a value in your CSS, before your JavaScript takes effect and adds the left
#view {
position: relative;
width: 1423px;
left: 0; //initiate
transition: left 2s;
}

Add css display block after a delay function

In a sequence of animations I have a small bug I can't figure out. I am running delays for different parts of the animation to sequence them in. For those divs, I style them to display:none and then I fade them in after their delay.
Well for this particular animation, I am toggle sliding a "mask" off of it, so not fading anything in like normal. This is causing an overlapping over my other divs to where I thought originally it was a z-index issue well, not that's not the case. The problem is, I am not displaying none because I am not initiallizing it with a fadeIn, so the background-color always shows and disrupts other elements.
This is blue background overtop of the teal is the background-color of the home-learn div....
I need help figuring out how I keep my div home-learn displaying none until the delay has processed and then to display it somwhow.
Here is the code:
#home-learn {
color: #FFF;
position: absolute;
text-align: center;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
font-size: 2.3em;
z-index: 99;
display: none;
}
#curtain-div {
width: 100%;
height: 100%;
position: absolute;
background-color: #0085A1;
top: 0;
left: 0;
z-index: 1;
}
$(function(){
$('#home-learn').css('display', 'block');
$("#curtain-div").delay(15800).toggle("slide", {
direction: "right"
}, 1000);
});
<div id="home-learn">
<div id="curtain-div"></div>
Discover more...
</div>
I need to figure out how I can make $('#home-learn').css('display', 'block'); work after the delay.
If you need to see this live, comment below and I will add the site.
UPDATE - ADDED HTML
<div class="blue">
<div id="hand-wrap"><img src="/images/hand.png" class="hand" alt="HELLO"></div>
<span class="hand-text">HELLO</span>
<div class="circle">
<div class="spinner top topright"></div>
<div class="spinner top topleft"></div>
<div class="spinner bottom bottomleft"></div>
<div class="spinner bottom bottomright"></div>
<div class="mask q2"></div>
<div class="mask q4"></div>
</div>
<div id="circle-text">We're Optimum<br>Designs</div>
<div class="aqua">
<div id="aqua-text1">We transform ideas...</div>
<div id="aqua-text2">...into reality.</div>
</div>
<div id="blue-home-text">We build beautiful, engaging sites for companies both large and small.</div>
<div id="home-learn">
<div id="curtain-div"></div>
Discover more...
</div>
For this question:
I need to figure out how I can make $('#home-learn').css('display', 'block'); work after the delay.
Add the line just after the delay method with queue() method:
$("#curtain-div").delay(15800).queue(function() {
$('#home-learn').css('display', 'block');
}).toggle("slide", {
direction: "right"
}, 1000);
EDIT
To proof this works, I add a fiddle here:
https://jsfiddle.net/4vLLnxt1/
You must to see the blue box appears after the 4 seconds of delay. That works perfectly.
Second EDIT
Due the comments below, try changing with this:
$("#curtain-div").delay(15800).queue(function() {
$('#home-learn').css('display', 'block');
$(this).toggle("slide", {
direction: "right"
}, 1000);
});
Third EDIT
As we talk in comments, all is solved with next parameter. The whole code:
$("#curtain-div").delay(15800).queue(function(next) {
$('#home-learn').css('display', 'block');
next();
}).toggle("slide", {
direction: "right"
}, 1000);

jquery-ui slide left doesn't work first time

When I'm using show() and hide() methods from jquery-ui:
var current = 1;
function slide(buttonNum) {
if (current != buttonNum){
$("#page" + current).hide("slide", { direction: "left" }, 800, function() {
$("#page" + buttonNum).show("slide", { direction: "right" }, 800);
});
current = buttonNum;
}
}
My intention is that every time button is clicked for this function the page would scroll left to change to required page.
The problem is that it doesn't work first time I'm clicking page number with function above(the current div would slide to the left, but div which I change to just pops up without animation) but works normally other times.
my css is as follows:
.slider {
width: 400px;
height: 300px;
overflow: hidden;
}
.slider .content {
position: relative;
}
.slider .content .page {
float: left;
width: 400px;
height: 300px;
background-size: cover;
}
and HTML:
<div class="slider">
<div class="content">
<div id='page1' class="page">
<!-- stuff -->
</div>
<div id='page2' class="page">
<!-- stuff -->
</div>
<div id='page3' class="page">
<!-- stuff -->
</div>
</div>
</div>
<a onclick='slide(1)' href="#">1</a>
<a onclick='slide(2)' href='#'>2</a>
Try hiding the elements that you expect not to be visible at the beginning, so that the show animation will actually execute. E.g. add this at the top:
$("#page2").hide();
$("#page3").hide();
That way running .show() on them will have an effect.

Dynamic Image Overlay with Jquery

I have an image with an overlay DIV which shows 2 images when I hover on the image, this works fine, but I want it to be dynamic and work for countless images on the page, currently it works for the first picture only, I'm not that good with javascript and jquery and would appreciate your help on this one.
Jquery Code:
$("#imageOverlay").hover(
function() {
$(this).children("img").fadeTo(200, 0.7).end().children("#hover").show();
},
function() {
$(this).children("img").fadeTo(200, 1).end().children("#hover").hide();
});
HTML Code:
<div id="imageOverlay">
<div id="hover">
<img src="http://placehold.it/100x30&text=Full View" />
<img src="http://placehold.it/100x30&text=Similar" />
</div>
<img src="http://placehold.it/1000x1000&text=Thumbnail">
</div>
CSS Code:
#imageOverlay {
display: inline;
position: relative;
}
#imageOverlay #hover {
display: none;
position: absolute;
margin-top: 10px;
margin-right: 10px;
z-index: 2;
}
#imageOverlay #hover a {
width: 100px;
height: 30px;
display: block;
margin-bottom: 5px;
}
Use a class for #imageOverlay and #hover, you can only have one instance of an ID, so when you have more than one of those IDs, the function is only finding the first one. Also, just fade the container box, not each individual image. Also, use stop() before an animation to make sure you don't get weird behavior when people are mousing on and off your element. Then, putting the main image first ensures that the hovered images are "on top" without having to worry about z-index.
HTML
<div class="imageOverlay">
<img src="http://placehold.it/1000x1000&text=Thumbnail">
<div class="hover">
<img src="http://placehold.it/100x30&text=Full View" />
<img src="http://placehold.it/100x30&text=Similar" />
</div>
</div>
JS
//fade out the images initially
$(".imageOverlay .hover").fadeTo(0, 0)
$(".imageOverlay").hover(
function() {
$(this).find(".hover").stop().fadeTo(200, 1);
},
function() {
$(this).find(".hover").stop().fadeTo(200, 0);
} //when writing clean code, be sure your closer ends at the same indent as your opener
);
CSS
.imageOverlay {
display: inline-block;
position: relative;
}
.imageOverlay .hover {
position: absolute;
top: 10px;
right: 10px;
}
.imageOverlay .hover a {
width: 100px;
height: 30px;
display: block;
margin-bottom: 5px;
}
And your images should show up on top when you hover!
Make #imageOverlay a class and apply it to multiple attributes in your html.
css:
.imageOverlay
//css rules
jquery:
$(".imageOverlay").hover(
function() {
$(this).children("img").fadeTo(200, 0.7).end().children("#hover").show();
},
function() {
$(this).children("img").fadeTo(200, 1).end().children("#hover").hide();
});
html:
<div class="imageOverlay">
// do stuff
</div>
<div class="imageOverlay">
// do stuff
</div>

Categories