13

I have a question about jQuery offset() function. I use it on my site to display "email a friend" window after clicking on email icon.

However, the window appears sticked to the right side of browser's window, not on the position of the icon. You can see it in action on http://pec.solarismedia.net/calendarday.html

$(".emailFriend").hide();
    $(".emailIcon").on("click", function(e) {
        $(".emailFriend").css({
            "position": "absolute", 
            "left": $(this).offset().left, 
            "top": $(this).offset().top
        }).fadeIn(500);
        return false; 
    }); 

There is a picture showing the difference between intention and reality.

Derek 朕會功夫
  • 92,235
  • 44
  • 185
  • 247
FilipBenes
  • 335
  • 2
  • 3
  • 10
  • Regardless of the JS solution you accept, it'd make sense to position the `.emailtofriend` modal via CSS. Contain the element inside `.userTools` and position with relative. – Matt Stone Nov 19 '12 at 07:42

2 Answers2

17

It's because #container has position: relative;. Thus absolute settings of the email box are relative to the #container. You have to either remove the property or calculate the value of left with something like this:

$(this).offset().left - $('#container').offset().left
Michał Miszczyszyn
  • 11,835
  • 2
  • 35
  • 53
3

just use position istead. The .position() method allows us to retrieve the current position of an element relative to the offset parent. Contrast this with .offset(), which retrieves the current position relative to the document.

$(".emailFriend").insertBefore('.emailIcon').hide();
$(".emailIcon").on("click", function(e) {
    $(".emailFriend").css({
        "position": "absolute", 
        "left": $(this).position().left, 
        "top": $(this).position().top
    }).fadeIn(500);
    return false; 
});

added appendTo('.userTools'). an element showing at the same position than another should be within the same element. Then position works and will work even if you change the layout.

If you don't want to change the dom structure for any reason you should use something like this:

$(".emailFriend").hide();
$(".emailIcon").on("click", function(e) {
    $(".emailFriend").css({
        "position": "absolute", 
        "left": $(this).offset().left-$(".emailFriend").offsetParent().offset().left, 
        "top": $(this).offset().top-$(".emailFriend").offsetParent().offset().top
    }).fadeIn(500);
    return false; 
});
iRaS
  • 1,958
  • 1
  • 16
  • 29
  • This code won't work either, have you tested? `$(this).position().top` is equal 0 because the `position()` method **does not** calculate the values the way CSS will. CSS will position elements relating to the closest ancestor with `position: relative;` while jQuery takes only the parent into consideration. – Michał Miszczyszyn Nov 19 '12 at 07:41
  • 1
    @Miszy wow - i'm sorry. the position method is exactly for such issues. the only problem was the dom structure where .emailFriend is not within the same element as .emailIcon. – iRaS Nov 19 '12 at 07:55
  • 2
    i just played a little bit with the second answer and added an if-statement: `if ($('.emailFriend').offset().left+$('.emailFriend').width() > $(window).width()) { $('.emailFriend').css('left', $(window).width()-$('.emailFriend').outerWidth()-$('.emailFriend').offsetParent().offset().left-20); }` just to make shure its not overlapping the view port – iRaS Nov 19 '12 at 09:44