question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Popup position not correct when offsetWidth/offsetHeight == 0

See original GitHub issue

CodeSandbox demo

https://codesandbox.io/s/gifted-sunset-ewyjj

Steps to reproduce the problem

  1. Using Chrome v92.0.4515.159
  2. Make sure that popperjs/core is in version 2.9.3
  3. Click on the red box, which is the trigger for displaying the pop-up

(The example is based on a largely more complex real use case, using Bootstrap, but I managed to recreate the behavior with that simple structure and pure Popper)

What is the expected behavior?

The popup should be displayed just below the red box, but is instead translated to the top left, partly outside of the container. The behaviour is correct in Firefox 91.0.2.

image

What went wrong?

The issue was introduced by fix #1247, which introduce additional checks on scaled elements.

There are 2 main characteristics in the constructed scenario that triggers the problem:

  • The parent container has non-integer margins (because of the use of fraction of rems: margin: 1.1rem;) that results in a getBoundingClientRect rectangle with decimal width and/or height. On the contrary, offsetWidth and offsetHeight return integers, so as the result the new isElementScaled function return true, as the numbers are not exactly the same. For instance, in my example, rect.width == 321.859375, and element.offsetWidth == 321, hence rect.width / element.offsetWidth || 1 == 1.0026771806853583, and scaleX !== 1 return true

  • Independently, it appears that Chrome does not compute any offsetWidth or offsetHeight for the #popper-button element in this scenario, and return 0 for both of them (this is the difference with Firefox, as the latter return values).

Putting those two characteristics together in

https://github.com/popperjs/popper-core/blob/f4a6550be3bc95ea5a0348218ae470848ff91544/src/dom-utils/getBoundingClientRect.js#L15-L19

scaleX and scaleY are computed because includeScale == true, and they are equal to Infinity because element.offsetWidth == 0 and element.offsetWidth == 0

Then all values in the object returned by getBoundingClientRect are equals to 0 because they are divided by Infinity

So, when used in getCompositeRect function, with const rect = getBoundingClientRect(...)

https://github.com/popperjs/popper-core/blob/f4a6550be3bc95ea5a0348218ae470848ff91544/src/dom-utils/getCompositeRect.js#L56-L61

The rect components in the x and y output are 0, and - putting the scroll contribution aside - only the parent container offset negatively contributes, so the position is likely to be negative, therefore the translation to the top left corner.

Possible fixes

I am not familiar enough with the library to suggest the best course of action to prevent this bug, but I can see 2 directions:

  • isElementScaled should maybe only compare integers, and round the getBoundingClientRect dimensions to integers. I guess that the initial fix was for significant scaling, not just when the bounding rectangle and the elements differs by a fraction of a pixel.
  • Ignore scaling when element.offsetWidth or element.offsetHeight return 0, and prevent the Infinity scaling ratio.

Any other comments?

Sorry if the bug description lacks more understanding of the library, I am not familiar with it, as I use it only through Bootstrap. I just observed the reported behaviour and concluded this was down to Popper through Javascript troubleshooting in Chrome Dev Tools.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:5
  • Comments:14 (8 by maintainers)

github_iconTop GitHub Comments

2reactions
mzgajnercommented, Sep 13, 2021

Can confirm same issue as @BrianHung (parent width resolving to .5 px), still present in latest version (2.10.1 at the time of this comment), fixed by reverting to 2.9.2.

2reactions
FezVrastacommented, Sep 1, 2021

May someone verify if this fixes your issue?

https://github.com/popperjs/popper-core/pull/1353

Read more comments on GitHub >

github_iconTop Results From Across the Web

Popup position not correct when offsetWidth/offsetHeight == 0
Independently, it appears that Chrome does not compute any offsetWidth or offsetHeight for the #popper-button element in this scenario, and ...
Read more >
Why would jquery return 0 for an offsetHeight when firebug ...
An element that is not actually taking part in the document render process has no dimensions, and will give an offsetWidth/Height of 0....
Read more >
Display Div in center of Screen as pop up - MSDN - Microsoft
My problem is I need to display this div (pop up) in center of the ... Thanks a lot for your replies but...
Read more >
HTML DOM Element offsetWidth Property - W3Schools
The offsetWidth property returns the viewable width of an element (in pixels) including padding, border and scrollbar, but not the margin.
Read more >
Autocomplete popup position [#625170] | Drupal.org
This works only if the autocomplete field is not positioned directly at the left bottom... if($.browser.msie == true ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found