jQuery: fade in/out + animate elements

10,703

The core cause of your issue is that you need a call to .siblings().stop(), in addition to the $(this).stop() (which you already have).

After you fix that, you'll see a new issue, where your captions initially work correctly, but then begin to fade in only partially once they've been moused-over repeatedly (and eventually, they'll disappear completely until you reload the page). This is due to the way .fadeIn() works when combined with .fadeOut() -- fadeIn() doesn't always fade-in to opacity:1 -- instead, it fades-in to whatever opacity was applied at the time fadeOut() was called previously.

To get around this, you can use animate({opacity:1},'slow') instead of fadeIn('slow') -- or you can use the more concise (and clearer) .fadeTo('slow',1) (docs). (note, the parameter order is different on fadeTo, as compared to the other animation functions - the duration comes first, then the value you want to fade to).

Of course, you could also use fadeTo() in place of your other opacity animation --though there is certainly nothing wrong with using animate() as you've shown -- the two are equivalent. (of course, you would need to se animate() if you want to manipulate multiple css properties at the same time.)

When it all comes together, it might look something like this:

$(function() {
    $('.image').each(function() {
        $(this).hover( function() {
            $(this).stop().fadeTo('slow',0.3)
                .siblings().stop().fadeTo('slow',1);
        }, function() {
            $(this).stop().fadeTo('slow',1)
                .siblings().stop().fadeTo('slow',0);
        });
    });
});

You can see this code in action at jsFiddle: http://jsfiddle.net/coltrane/XstpE/
(note: that example depends on the hosted resources that go with the original post above, so it won't work if those get moved or become otherwise unavailable).


Also note: In the example above, I have included the use of .each() as you did in your original example, but I want to point out that it's really not necessary.

The following is equivalent (and would usually be considered "better" jQuery technique):

$(function() {
    $('.image').hover(function() {
        $(this).stop().fadeTo('slow', 0.3)
            .siblings().stop().fadeTo('slow', 1);
    }, function() {
        $(this).stop().fadeTo('slow', 1)
            .siblings().stop().fadeTo('slow', 0);
    });
});

When you apply an event handler to a multi-element set, jQuery automatically binds the same handler on every element in the set. (I've updated my example at jsFiddle (linked above) to show the code without the each()).


Edit

The OP points out that hovering over the caption (which sits on top of the image) causes the mouseleave handler to trigger, thus resulting in the roll-out action being performed. The desired behavior is to have the caption not trigger the rollout.

This issue happens because the caption "shadows" the image, and the hover() is applied to the image. When the mouse rolls over the caption it's no longer on the image (it's on the caption) so the browser fires a mouseleave on the image. This same situation can give rise to all sorts of other subtle problems too -- especially as you add more complex content.

To solve this, I recommend that you simply apply hover() one level up (to the container that holds the image and the caption), instead of applying it to the image directly. In this case that container is $('.entry'). The code would change like this:

$(function() {
    $('.entry').hover(function() {
        $('.image',this).stop().fadeTo('slow', 0.3)
            .siblings().stop().fadeTo('slow', 1);
    }, function() {
        $('.image',this).stop().fadeTo('slow', 1)
            .siblings().stop().fadeTo('slow', 0);
    });
});

here is a new version of the jsFiddle

Share:
10,703
klavina
Author by

klavina

Updated on June 04, 2022

Comments

  • klavina
    klavina almost 2 years

    I'm using jQuery to fade in/out some elements and change the opacity of the others.

      $(function(){
    
            $('.image').each(function() {
                $(this).hover(
                    function() {
                        $(this).stop().animate({ opacity: 0.3 }, 'slow');
                        $(this).siblings().fadeIn('slow');
                    },
    
                   function() {
                       $(this).stop().animate({ opacity: 1 }, 'slow');
                       $(this).siblings().fadeOut('slow');
                   })
                });
            });
    

    You can see the full code at http://projects.klavina.com/stackoverflow/01/ (I'm also using the jQuery Masonry plugin on the page).

    I'm fairly new to JS/jQuery and the above code doesn't work well, unless I mousover the .image element really slowly. When I move over the elements faster, the captions over the images show even when I've already moved over another element. How can I remove that? I.e. the captions should fade in only when I'm still hovering that particular element.

    The first image on the example site has a "z-index: 100;" for the caption, so I can get the text overlay at full opacity. Ideally, I would have "z-index: 100;" for all the captions, but this makes the hovering work even worse.

    Plus, the fading in/out looks distorted in IE. How can I fix that? I did use the opacity change on another page, and fixed the IE bug by adding a white background to the element, but I can't do that here (as I have a photo underneath).

    Thank you!