7

I have the following piece of HTML:

<div><p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor 
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud 
exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in 
reprehenderit in voluptate velit <strong id="s">esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</strong></p></div>

The width of the DIV is fixed at 600px using CSS. Now, I want to find the offset().left of the <strong> element. So I did:

alert( $("#s").offset().left );

However this does not seem to produce the right value, as I can clearly see the strong element is seen half way through the 600px width, but the offset value I get is only 8px.

How do I find the offset().left value of the inline strong element?

philly77
  • 519
  • 3
  • 8
  • 14

3 Answers3

26

Here's what's happening:

Diagram

Since the inline element spans multiple lines jQuery will give you the left-most position of that element, not the offset of the beginning of the element.

To get around this, try this plugin:

jQuery.fn.inlineOffset = function() {
    var el = $('<i/>').css('display','inline').insertBefore(this[0]);
    var pos = el.offset();
    el.remove();
    return pos;
};

The plugin will create a temporary element and insert it just before the target element - it will then return the offset of that temporary element.

Example usage:

alert( jQuery('strong').inlineOffset().left );
Spooky
  • 2,966
  • 8
  • 27
  • 41
James
  • 109,676
  • 31
  • 162
  • 175
  • A (minor) optimization would be: 1. var pos = el.offset(); 2. el.remove(); 3: return pos; Instead of calling offset() twice and create a new object to return. – PatrikAkerstrand Jun 15 '09 at 12:44
  • Thanks Machine, just changed it :) – James Jun 15 '09 at 12:47
  • Is there a reason why you’re using `.insertBefore(this[0])` and not just `.insertBefore(this)`? – Mathias Bynens May 05 '10 at 14:48
  • 1
    `this` could contain any number of elements, and since `offset()` only returns the offset of the first in the collection it would be pointless to insert before all of `this`. – James May 05 '10 at 14:52
  • @J-P Thanks for this! It also can be used to get the offset of hidden elements.. You rock. – Mahdi.Montgomery Feb 12 '11 at 23:59
  • 1
    There is a huge discrepancy in one certain case: When the inline element is not in the first line but starts a new one: In this case the empty `` remains on the previous line giving a completely wrong result. – Boldewyn Nov 04 '11 at 13:40
  • 1
    Use a non-empty i tag. In current Chrome 33.0.1750.46 it makes problems, will return the wrong position. Might get optimized away. – Christian Feb 24 '14 at 14:09
0

The reason you are getting the result of 8px is because even though the element starts in half way through your container, since there's a line break its left edge is 8px in from the page.

I have one of those feelings that there's probably a much better way to do it than this, but the first thing I could think of to work around this problem is to insert another element right before the <strong> and check its position:

$("<span><span>").insertBefore($('#s')).offset();
nickf
  • 537,072
  • 198
  • 649
  • 721
-1

I believe offset is relative to the document, while position is relative to the parent.

http://docs.jquery.com/CSS/position

ScottE
  • 21,530
  • 18
  • 94
  • 131