Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery .offset() not retrieving correct position

I'm working on a site which dynamically creates facebook-like buttons via PHP. However, the <div> that the buttons are contained in needs to have the CSS property overflow: hidden; This is the only way I've found that works to make a two-column format which forces both columns to expand to be the length of the longest one. The only problem with this method is that any facebook-like buttons placed near the bottom of the container get clipped when someone clicks on them and they expand.

Here's the way I've tried to solve this issue:

  1. Using jQuery, I loop through all facebook like buttons on the page and calculate their document offset using the offset() method.

  2. I then clone() each button as well as give it absolute positioning and the calculated offset using jQuery's css() method. I hope that each cloned button will be placed in the same position of the button it was cloned from when I append it to the document.

  3. Finally, I change each old facebook-like button's css to visibility: hidden; in order to make it invisible but still take up the space it would have previously on the page. I add the clones of the facebook-like buttons to a div without the overflow: hidden; property using the appendTo() function.

Here's my entire code for this process:

// Replaces functional facebook recommend buttons with identical ones
// in a div where they won't get clipped when they expand.
// Hides the old buttons so space is still left for new ones
$(window).load(function(){
    $(".fb-recommend").each(function(){ // cycle through each recommend button
        var offset = $(this).offset(); // calculate offset of each button
        var newButton = $(this).clone(); // clone the button
        newButton.css({'position':'absolute', 'left':offset.left, 'top':offset.top});
        $(this).css("visibility","hidden"); // hide the old button
        newButton.appendTo("#wrapper"); // put the new button in the wrapper where it won't get clipped
    });
});

At the end of all this, I expect to have clones of each button placed where the old button was but in a different <div>. The whole process works, except that the cloned facebook-like buttons are appearing at a slightly different position than the ones they were cloned from (as PitaJ points out they seem to be off by vertical offset multiples of around 39px). You can view the issue here:

LINK TO TEST WEBSITE

As you can see, the first button is placed in the correct location (the empty space filled by its hidden clone) but the other offsets were not calculated correctly.

I'd appreciate any ideas or help offered. Let me know if you'd like me to explain better or post more code!

Edit: I figured I'd post the CSS for the facebook-like buttons here (even though all I'm changing is the margin):

#content .fb-recommend {
    margin: 15px 0 5px 0;
}

Edit 2: As per UnLoco's suggestion, I added a min-height property to the fb-reccommend CSS and commented out the line of code that was hiding the old buttons so it's easier to see the problem (which is still there, though slightly lessened. The CSS now looks like this:

#content .fb-recommend {
    margin: 15px 0 5px 0;
    min-height: 39px;
}

Edit 3: The problem appears to have been solved in all browsers but IE by changing the CSS to this:

.fb-recommend {
    min-height: 24px;  // I used 24 because the fb-buttons are 24px in height
}

Final Edit? This seems to work on all browsers on my end, including IE:

.fb-recommend {
    min-height: 39px;
}

I'm thinking now that the 39 might have come from the 15px margin of the old fb-button + its 24px height. I think I can get around it by simply setting the height to be 39px and not having a margin.

like image 758
Alex Kalicki Avatar asked Aug 18 '12 21:08

Alex Kalicki


People also ask

What is offset () in jQuery?

jQuery offset() Method The offset() method set or returns the offset coordinates for the selected elements, relative to the document. When used to return the offset: This method returns the offset coordinates of the FIRST matched element. It returns an object with 2 properties; the top and left positions in pixels.

What is the difference between position and offset in jQuery?

Although both methods have some similarities, but the jQuery offset() method is different from the jQuery position() method. The offset() method retrieves the current position relative to the document, whereas the position() method retrieves the current position of an element relative to the parent element.

What is offset () Top?

The offsetTop property returns the top position (in pixels) relative to the parent. The returned value includes: the top position, and margin of the element.

How do I get Offsetbottom?

The jQuery offset() function is a built-in function in jQuery, by which we can return the offset of the bottom coordinate. The jQuery offset() function only specifies the top and left properties position, but with the help of top property and outerHeight() function, we can get the bottom position for elements.


2 Answers

this is because you are retrieving the offset before the fb iframes actually load. just add a css rule like this
div.fb-recommend{min-height:39px}

like image 181
unloco Avatar answered Oct 20 '22 20:10

unloco


I believe you're problem is some odd jQuery weirdness.

To fix this, simple change your code to this:

$(window).load(function(){
    $(".fb-recommend").each(function(index){ // cycle through each recommend button
        var offset = $(this).offset(); // calculate offset of each button
        var newButton = $(this).clone(); // clone the button
        newButton.css({'position':'absolute', 'left':offset.left, 'top':offset.top + (39*index)});
        $(this).css("visibility","hidden"); // hide the old button
        newButton.appendTo("#wrapper"); // put the new button in the wrapper where it won't get clipped
    });
});

This will account for the weird offset problem.

like image 30
PitaJ Avatar answered Oct 20 '22 21:10

PitaJ