Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.position() and .offsetParent() return incorrect value #3107

Closed
anseki opened this issue May 5, 2016 · 2 comments · Fixed by #3487
Closed

.position() and .offsetParent() return incorrect value #3107

anseki opened this issue May 5, 2016 · 2 comments · Fixed by #3487
Assignees
Milestone

Comments

@anseki
Copy link

anseki commented May 5, 2016

.position() method should return a position of element relative to a closest ancestor element that is positioned.
Therefore, for example, if CSS properties top/left of the element that has position:absolute are set to that returned position, the element should not move.
But when the ancestor element that is positioned does not exist (i.e. all ancestor elements have position:static, this is default), a position relative to <html> element incorrectly is returned.
For example:
https://jsfiddle.net/fqbgy5pq/

Result:

ClientRect   top: 63   left: 63
CSS props    top: auto left: auto
.position()  top: 59   left: 59
Set return value of `.position()` to `top` and `left`, then the element should not move.
ClientRect   top: 59   left: 59
CSS props    top: 59px left: 59px
.position()  top: 55   left: 55

Note: 2px was lost by this issue, and more 2px was lost by another issue of .offset().
When fixed .offset() is used:

Result:

ClientRect   top: 63   left: 63
CSS props    top: auto left: auto
.position()  top: 61   left: 61
Set return value of `.position()` to `top` and `left`, then the element should not move.
ClientRect   top: 61   left: 61
CSS props    top: 61px left: 61px
.position()  top: 59   left: 59

.offsetParent() method that is called by .position() method returns <html> when ancestor element that is positioned is not found. Then, .position() mistakes.

return offsetParent || documentElement;

I think that .offsetParent() should return document or null in this case.
document means "base of coordinates".
null means "ancestor element is not found".

Also, .position() method should return coordinates relative to the document in this case.

And also, .position() method returns incorrect coordinates when <html> has position:non-static (i.e. the ancestor element is really <html>).
For example:
https://jsfiddle.net/wczL6ae5/

Result:

ClientRect   top: 63   left: 63
CSS props    top: auto left: auto
.position()  top: 59   left: 59
Set return value of `.position()` to `top` and `left`, then the element should not move.
ClientRect   top: 62   left: 62
CSS props    top: 59px left: 59px
.position()  top: 58   left: 58

Note: 1px was added by this issue, and 2px was lost by another issue of .offset().
When fixed .offset() is used:

Result:

ClientRect   top: 63   left: 63
CSS props    top: auto left: auto
.position()  top: 61   left: 61
Set return value of `.position()` to `top` and `left`, then the element should not move.
ClientRect   top: 64   left: 64
CSS props    top: 61px left: 61px
.position()  top: 62   left: 62

When .offsetParent() method returned <html>, .position() method ignores its offset.

if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {

Therefore, if the <html> has offset (i.e. margin), returned value is incorrect.
Strange to say, only border-width is included in that calculation.
top: parentOffset.top + jQuery.css( offsetParent[ 0 ], "borderTopWidth", true ),

I think that it might affect scripts that exist if the return value of .offsetParent() method is changed.
At least, .position() should be fixed even if .offsetParent() is not fixed. In this case, .position() should not use .offsetParent(), or it should check whether position is static when <html> was returned.
This issue affects .offset() method because setter of .offset() uses .position().

@markelog
Copy link
Member

markelog commented May 16, 2016

I think that .offsetParent() should return document or null in this case.
document means "base of coordinates".
null means "ancestor element is not found".

This behaviour is already defined in spec - https://drafts.csswg.org/cssom-view/#dom-htmlelement-offsetparent, we deviate from it though -

jquery/src/offset.js

Lines 162 to 166 in 95c7ab6

// This method will return documentElement in the following cases:
// 1) For the element inside the iframe without offsetParent, this method will return
// documentElement of the parent window
// 2) For the hidden or detached element
// 3) For body or html element, i.e. in case of the html node - it will return itself

There is a lot of issues with offsetParent - #1765 :/

@anseki
Copy link
Author

anseki commented May 17, 2016

If jQuery doesn't behave as with CSSOM specification, I think that .position() should be fixed.

@timmywil timmywil modified the milestone: 3.1.1 Jun 30, 2016
@timmywil timmywil modified the milestones: 3.1.1, 3.2.0 Jul 13, 2016
gibson042 added a commit to gibson042/jquery that referenced this issue Jan 5, 2017
gibson042 added a commit to gibson042/jquery that referenced this issue Jan 5, 2017
@timmywil timmywil modified the milestones: 3.2.0, 3.3.0 Mar 15, 2017
gibson042 added a commit to gibson042/jquery that referenced this issue Mar 20, 2017
@lock lock bot locked as resolved and limited conversation to collaborators Jun 18, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Development

Successfully merging a pull request may close this issue.

4 participants