Skip to main content

Bug Tracker

Side navigation

#7730 closed bug (fixed)

Opened December 08, 2010 02:37PM UTC

Closed April 12, 2011 04:25AM UTC

offset.js: setOffset uses parseInt to parse css values which may contain floating point numbers

Reported by: inukshuk Owned by: inukshuk
Priority: high Milestone: 1.6
Component: css Version: 1.4.4
Keywords: Cc: scottgonzalez
Blocked by: Blocking:
Description

I encountered 'wobbly' behaviour using jQuery UI autocomplete, caused by sub-pixel rendering issues.

Use parseFloat instead; see commit:

https://github.com/inukshuk/jquery/commit/4b0b05ffc8a087b8053f08099511f4bf2490939f

Attachments (0)
Change History (11)

Changed December 08, 2010 03:57PM UTC by scottgonzalez comment:1

cc: → scott.gonzalez

Changed December 08, 2010 05:40PM UTC by rwaldron comment:2

owner: → inukshuk
status: newpending

Thanks for taking the time to contribute to the jQuery project! Please provide a reduced jsFiddle test case to help us assess your ticket!

Additionally, test against the latest jQuery release AND the jQuery 0 GIT version.

In this case, please provide a test that demonstrates the "wobbly" behaviour you're describing. Thanks!

Changed December 08, 2010 06:44PM UTC by ajpiano comment:3

parseFloat does not accept a radix argument.

Changed December 09, 2010 10:59AM UTC by inukshuk comment:4

status: pendingnew

Thanks for taking a look at this. The 'wobbling' effect can be encountered if a function repeatedly positions an element using setOffset, for example the autocomplete widget in jQuery UI.

The problem is that it is possible, given the right circumstances, for fractional values to be written to CSS -- this value is then parsed by the second call to setOffset and ommitted if parseInt is used for that purpose. The effect is that the element in question will be alternating between a position based on float and one on int. Whether or not this results in a visible bug depends on the exact numbers invovled and on the browser's sub-pixel rendering I would think. It is therefore difficult to produce a minimal example, but you can observe the behaviour I describe here:

http://jsfiddle.net/gy9KU/

You need to monitor the CSS top value of the (initially hidden) ui-autocomplete div.

1. Select the input field and type 'a'; ui-autocomplete is displayed using a top value of '-2.39999px'.

2. Now, clear the input field and type 'a' again; ui-autocomplete is displayed, this time using a top value of '-2px'.

You can repeat these steps indefinitely with the same behaviour.

I encountered this on a site, where the fraction in question was > 0.5 and the result was plainly visible in many browsers. I suspect it is the problem that caused these issues in jQuery UI:

http://bugs.jqueryui.com/ticket/5280

http://bugs.jqueryui.com/ticket/6000

If I use parseFloat in setOffset I can remove the superflous Math.round or parseInt calls in ui-position. In the case of ui-position I believe this is the best solution, because ui-position has no way of knowing what a browser will do with fractions, therefore it should not touch them either way.

Of course you're right about the radix argument; here is a commit without it:

https://github.com/inukshuk/jquery/commit/25b509ec755bfd875c1ccb3e0a9ca182e49a156c

Changed December 14, 2010 06:26AM UTC by snover comment:5

status: newpending

Could you please provide a pull request for your patch on GitHub along with a unit test? Thanks!

Changed December 20, 2010 07:25AM UTC by inukshuk comment:6

_comment0: Do you have any suggestions for a suitable unit test? The best test case I can think of is to set a sub-pixel value in CSS and test tat offset() corectly parses the fractions. But what if the browser does not report the sub-pixels? Is there any policy to deal with browser differences in the unit tests? I guess they are best avoided, but then, how best to test this issue?1292829934408088
status: pendingnew

Do you have any suggestions for a suitable unit test? The best test case I can think of is to set a sub-pixel value in CSS and test that offset() corectly parses the fractions. But what if the browser does not report the sub-pixels? Is there any policy to deal with browser differences in the unit tests? I guess they are best avoided, but then, how best to test this issue?

Changed December 27, 2010 12:28AM UTC by snover comment:7

_comment0: So, if I’m understanding this issue correctly, the problem with parseInt for most browsers (which don’t do sub-pixel rendering) is that it doesn’t round—it just drops the fractional amount. \ \ Are there browsers that don’t report fractional amounts? If so, what might work as a reasonable test case would be to use a value that doesn’t round properly currently (like 1.7), set & get it, then Math.round and compare. Incorrect behaviour would end up with 1; correct behaviour would end up with 2. Right?1293409771612473

So, if I’m understanding this issue correctly, the problem with parseInt for most browsers is that it doesn’t round—it just drops the fractional amount—which means browsers that use round instead of floor when deciding how to place fractional pixels end up jumping.

What might work as a reasonable test case would be to use a value that doesn’t round properly currently (like 1.7), set & get it, then Math.round and compare. Incorrect behaviour would end up with 1; correct behaviour would end up with 2. Right? Are there browsers that actually use floor behaviour?

Changed December 27, 2010 08:01PM UTC by snover comment:8

component: unfiledcss
milestone: 1.next1.5
priority: undecidedhigh
status: newopen

Changed December 27, 2010 09:07PM UTC by inukshuk comment:9

As I understand it browsers may legitimately use sub-pixel values. There are some problems with this, however. Consider a case where you have three columns in a container and each column is designed to take up a third of the container. Now, what happens if the container's witdh divided by 3 results in a fractional value and the browser or display does not support sub-pixel rendering? The browser has to pick the lesser of three evils:

1. make one column larger/smaller than the other to

2. size the columns identically, but not fill the container

3. size the columns identically, exceeding the container

This issue is also discussed here:

http://ejohn.org/blog/sub-pixel-problems-in-css/

I think a Javascript library should handle all pixel values reported by the browser with utmost care; if the browser reports fractions we should not touch them, as I suppose it is conceivable for the scenarios to arise where the Browser decides to round up a value < 0.5 or vice versa. If the browser reports a fractional value, I think it is best to conserve it and feed it back to let the browser decide what to do with it.

Perhaps somebody with experience in sub-pixel rendering could verify this?

Changed January 15, 2011 01:12PM UTC by inukshuk comment:10

I think the jsFiddle example in #7885 is actually a great test case. Using that, here is my commit again:

https://github.com/jquery/jquery/pull/182

Changed April 12, 2011 04:25AM UTC by john comment:11

milestone: → 1.6
resolution: → fixed
status: openclosed

Landed.