Reputation: 3770
I am trying to create a simple hover effect on a list elements. But, there is small gap between the element that shows up when mouse is over the list item. This forces the event mouseleave
to be triggered, which is unwanted.
Here is fiddle demo. Try to go to the small box after hovering over the list item.
HTML:
<ul>
<li>test <div class="block">Block</div></li>
<li>test2 <div class="block">Block descriptions</div></li>
</ul>
CSS:
ul { width: 50px; }
ul li { width: 50px; height: 50px; background: #c00; margin: 0 0 10px 0; }
li .block {
position: absolute;
margin: 0 0 0 70px;
background: #ddd;
display: none;
}
JavaScript:
$("ul li").hover(function() {
$(this).children(".block").stop().fadeIn();
}, function() {
$(this).children(".block").stop().fadeOut();
});
How to prevent such effect?
Upvotes: 1
Views: 824
Reputation: 206353
Try this demo:
$('ul li').on("mouseenter mouseleave",function( e ){
var $this = $(this);
if (e.type == 'mouseenter') {
clearTimeout( $this.data('timeout') );
$this.find('.block').stop().fadeTo(400,1);
}else{
$this.data( 'timeout', setTimeout(function(){
$this.find('.block').stop().fadeTo(200,0, function(){
$(this).hide();
});
},200) );
}
});
What it does is: set a timeout value to the data
attribute of the currently hovered li
element that will act like a hover intent that will wait 200ms for the mouseenter on your .block
elements maintaining the element visible. Once the mouse reaches your block element it will reset the timeout.
Upvotes: 1
Reputation: 816790
The mouseleave
event is triggered because you literally leave the element when you ty to move the mouse over to the child. The only solution is to extend the width of the li
element.
The maintain the same look, I suggest to move the red box into its own element, for example:
<ul>
<li>
<span class="icon">test</span>
<span class="block">Block</span>
</li>
<li>
<span class="icon">test2</span>
<span class="block">Block descriptions</span>
</li>
</ul>
And change the CSS to:
li span {
display: inline-block;
vertical-align: middle;
}
li .icon {
width: 50px;
height: 50px;
background: #c00;
}
li .block {
margin: 0 0 0 70px;
background: #ddd;
display: none;
}
The li
element extends over both children: DEMO. Note though that (should be fine according to http://caniuse.com/inline-block).display: inline-block
might not work in older IE versions.
Upvotes: 0
Reputation: 318302
You have two elements with mouse event handlers attached, and they are placed with a little distance from each other, so when the mouse is leaving one element on the way to the other element it goes outside both element and the event handler is triggered again etc.
You can either place both elements inside a wrapper element and attach the event handler to that element
<ul>
<li><div>test <div class="block">Block</div></div></li>
<li><div>test2 <div class="block">Block descriptions</div></div></li>
</ul>
js:
$("ul li").on({
mouseenter: function() {
$(".block", this).fadeIn();
},
mouseleave: function() {
$(".block", this).fadeOut();
}
});
or you can try to guesstimate the time it takes to move the mouse and use a little timeout to fake it:
var timer;
$("ul li").on({
mouseenter: function() {
clearTimeout(timer);
$(this).children(".block").fadeIn();
},
mouseleave: function() {
var self = this;
timer = setTimeout(function() {
$(self).children(".block").fadeOut();
}, 400);
}
});
Upvotes: 0
Reputation: 10243
something like this should work. might need a couple of tweaks.
var fn = function(elem) {
$(elem).children(".block").fadeOut();
};
var timeout;
$("ul li").on("mouseenter", function() {
var that = this;
clearTimeout(timeout);
$(this).children(".block").fadeIn();
}).on("mouseleave", function() {
var that = this;
timeout = setTimeout(function() {
fn(that)
}, 1000);
});
Upvotes: 0