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.

CSS "hook" for left and top styles makes no sense

See original GitHub issue

Description

Nothing more pointless in browser scripting than trying to compute styles. The document.defaultView.getComputedStyle (incorrectly referenced as window.getComputedStyle in jQuery) method is a hideously complex black box that virtually never needs to be opened. In twenty years of browser scripting, I’ve managed to avoid it almost entirely (exception that comes to mind was an HTML editor).

Regardless, jQuery aspires to fix the whole thing and frequently gets into trouble. Consider this “hook” for the top and left styles:

// Support: Safari <=7 - 9.1, Chrome <=37 - 49
// Add the top/left cssHooks using jQuery.fn.position
// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
// Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347
// getComputedStyle returns percent when specified for top/left/bottom/right;
// rather than make the css module depend on the offset module, just check for it here
jQuery.each( [ "top", "left" ], function( i, prop ) {
	jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
		function( elem, computed ) {
			if ( computed ) {
				computed = curCSS( elem, prop );

				// If curCSS returns percentage, fallback to offset
				return rnumnonpx.test( computed ) ?
					jQuery( elem ).position()[ prop ] + "px" :
					computed;
			}
		}
	);
} );

The cryptically named support.pixelPosition flag refers to a test result where a percentage-based top style fails to compute to pixel units. This is an issue that dates back to the bad old days of IE 8-, where currentStyle was frequently used by libraries as a slightly-off substitute for getComputedStyle; it didn’t convert any units to pixels. jQuery certainly does this in older versions, so the problem should be familiar.

This is the part that attempts to fix the issue:

// If curCSS returns percentage, fallback to offset
return rnumnonpx.test( computed ) ?
	jQuery( elem ).position()[ prop ] + "px" :
	computed;

It calls the position method instead, which attempts to figure the offset of the element from the document origin, which would only be equivalent to the computed left and top styles in only a small subset of cases.

For example, an element with a position style of absolute with all parent elements having position: static would work. On the other hand, an element with fixed position would fail unless the document’s scroll position is its origin. Furthermore, an element with relative position would fail in virtually every case. And so on, this “hook” will simply cause browsers demonstrating this quirk to return nonsensical position values in numerous cases (not even considering problems related RTL documents).

For those who never bothered to read my “P is for Position” primer on the old cinsoft.net site (now retired) or the numerous Usenet articles I authored on this subject (dating back to at least 2008), I’ll go over the general solution again.

In short:

  1. Save the left or top style (e.g. elem.style.left).
  2. Get the offset.
  3. Set the left or top style to '0'.
  4. Get the offset again.
  5. Find the difference between the two offsets.
  6. Put the old left or top style back.

And as the offset method is just a pointless wrapper for getBoundingClientRect (seems to exist only to handle calls passing disembodied elements or elements with a display style of none), would advise simply calling getBoundingClientRect and documenting that trying to compute position styles (or offsets) for such elements will result in undefined behavior (a recurring theme here). In addition, to let callers know they made a mistake at the earliest possible time, throw an exception in such cases (as opposed to returning zeros).

HTH

PS. What about right and bottom positions? The solution as it sits is only half-finished. Luckily I archived the related primer years ago:

https://github.com/david-mark/My-Library/blob/master/position.html

PPS. As this is an old issue that surely affects previous jQuery versions, am curious as to how the old versions are kept up to date when bugs like this are fixed.

Link to test case

No test case needed. Logic is clearly incorrect.

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Comments:19 (8 by maintainers)

github_iconTop GitHub Comments

3reactions
dmethvincommented, Dec 22, 2016

A “bug report” that finishes with “No test case needed. Logic is clearly incorrect” is already starting off on the wrong foot. Start with a test case that clearly fails, then we can talk about whether/why the code is wrong and how to fix it. The test case will end up in unit tests and we will all be happy.

2reactions
gibson042commented, Dec 22, 2016

@ctomczyk: If @david-mark (or anyone else) provides a test case demonstrating the bug, we will reopen this issue.

Read more comments on GitHub >

github_iconTop Results From Across the Web

A Complete Guide to CSS Cascade Layers
This is your complete guide to CSS cascade layers, a CSS feature that allows us to define explicit contained layers of specificity.
Read more >
CSS position property: relative, absolute, static, fixed, sticky
Using CSS position to layout elements on your website can be hard to figure out. What's the difference between absolute, relative, fixed, and...
Read more >
Need help on CSS - HTML & CSS - SitePoint Forums
Hi, I have a big disadvantage in understanding CSS and I want to learn how to ... .header { position: absolute; left: 0;...
Read more >
Flexible Layouts with CSS Positioning - A List Apart
Another thing—it makes sense to write your DIV structure in the order that you ... #top-col-1 { position:relative; padding-left:20%; padding-right:10px; } ...
Read more >
Styling Hooks - Lightning Design System
Styling hooks use CSS custom properties which make it easy to customize component styling and ... as no other part of the styling...
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