-
Notifications
You must be signed in to change notification settings - Fork 20.6k
different result of width() and height() since jQuery 3.0 #3193
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
Comments
Agreed! It's a good breaking change though, wouldn't you say? As far as documenting, perhaps we could add a sentence to the existing item here? Either that or create an entirely new "Breaking change" item for it. Rewording the heading will break existing links. |
.width() is now more correct, yes. |
The current implementation has one problem. Setting and Getting via css() is not symmetric anymore:
|
Good point, and that doesn't seem good. Not sure how to deal with it though. It would help if |
Applications like mine have the defect right now. |
jQuery's |
The change is still not in the upgrade guide. IMO this should be done as fast as possible to prevent upgraders to have the same problems as we had. |
The reason no change has been made is because we haven't yet decided whether we should change code or docs. Once we do this ticket will be closed. |
Thanks for the explanation. |
If I may add my opinion.... What you are doing with this change is mixing this two concepts, so now there is no way of consistently getting the dimensions of an element. Rather, we get the dimensions or the bounding box depending on whether there are CSS transformations applied or not. It's an acceptable breaking change if .width() and .height() now return the bounding box rather than the dimensions as long as we have a way of getting the true dimensions. Do we have such a way? Also, .css() is supposed to give the computed css properties (hence its name), but if now .css('width') and .css('height') give the bounding box instead, that's not just a breaking change, that's messing with the user base. It's just a huge gotcha. |
Just to add another point regarding relationship of
This is documented behavior, have not checked if this is still valid for jQuery 3.0. |
I think those are all valid points. As far as resolving the problem, there are conflicting concerns here, I'll just mention width but it applies to height as well.
@HolgerJeromin @Getfree What would you like these APIs to return? Let's start with that and think about how existing code might break. |
The way I see it, it's essential that we have a reliable way of getting the dimensions and position of an element no matter if the element itself or an ancestor is css-transformed. Consider this example: The blue box wants to be exactly under the red box. But since the BODY element is transformed, bounding-box coordinates are no good. In general, from the moment you apply css-transformations, any calculation based on elements dimensions is going to give the wrong result. I'm Ok with jQuery 3 introducing breaking changes as long as there is a way of getting true element's dimensions (and not bounding-box dimensions) when they are needed. |
Exactly. My application needs a way to get dimension based information for correct positioning of complex transformed elements. Non fractional value is no disadvantage if result is not complete bogus after transforming. |
Hmm, maybe we need to use Are there any cases where you'd want the dimensions with transforms applied? |
Let's start with a summary of documented surface area (using the horizontal dimension without loss of generality):
All of these should be capable of returning fractional values, but—since they are so closely tied to the CSS box model and especially since they're all also setters—ignore transforms. In fact, the non- For this ticket, though, I have to agree with @HolgerJeromin. We should not use |
Also remember that Example: https://jsfiddle.net/au6uem3p/ |
@Getfree I wouldn't say they give "wrong" results as they do return the element displayed position. Going back to basics, I was wondering what are the main questions being asked that jQuery (or a browser API for that matter) should answer to. I see 3 of them related to
The browser APIs have been evolving in a way that should satisfy the above conditions. There is no API to get the displayed size of the element but without taking transitions into account; asking for something like that is kind of weird, most of the time people asking this question are really asking for the value of the computed width, not the displayed width minus transforms. AFAIK there is no browser API that would answer this question as well. There is Now, as for the last point - our problem is that the If we want to leave |
I've tried removing the I'm not sure if there's anything we can do before 4.0. |
Going back to |
Seems like @mgol has explained the challenges here pretty well. Any API that retrieves the actual transformed dimension or position as a single number is taking several CSS properties into account and can't be used as both a getter and setter to round-trip that single number. What can we do before 4.0? I'd consider some of this to be regressions so even if it changes existing behavior for better compatibility with 2.x it still may be in play for a 3.x.0 release. |
Browsers have There is no browser API for returning the "computed width" in CSS terms. Put another way, if you have:
|
I actually meant the bounding box of the element i.e. "what's the size of the box that appears on the screen", so including transforms.
I meant "resolved width"; I keep using the wrong name because of how
I meant "offsetWidth" here, I keep mixing stuff, d'oh. Post corrected. Basically, my point was that you may either ask for a resolved value for a specific CSS property, here: |
Yes, that's a correct summary of the state of browser API. |
|
Considering the impact of some of these changes, moving to 3.2.0. We'll get smaller issues out in a 3.1.1 first. |
@vanderlee As a work around, I added the following utility functions to our application. function _jQuerySize(elem, name) {
if (typeof elem === 'string') {
elem = jQuery(elem);
}
if (elem instanceof jQuery) {
elem = elem[0];
}
let val = jQuery.style(elem, name);
return parseFloat(val);
}
export function outerWidth(elem) {
return _jQuerySize(elem, 'width');
}
export function outerHeight(elem) {
return _jQuerySize(elem, 'height');
} Then to use it: import { outerWidth } from 'utils/jquery.js';
outerWidth('.user-item');
// or
let $userItem = $('.user-item');
outerWidth($userItem); You could probably even monkey patch jQuery if you have 3rd party libraries that depend on this behavior ... but that felt a bit dangerous. |
you may find alternative implementations of width of height functions in this site: |
The fix for this issue brought a regression: #3571. It seems we don't have a good Web API to satisfy our needs:
Is there any way to retrieve a fractional "real" value for width on inline elements that doesn't take transforms into account? @bzbarsky? |
Updated example to show that transforms can be just as well expected as unexpected. Then positioning something near another element, for example (using jQuery 3.1.1): Here, the behaviour toward So in the end, there is no way to make it work for everything because crucial knowledge about the context is not given to the method. This is a lot like the difference between |
Another idea for a partial fix for 3.2.1 - keep the current logic but
fallback to offsetWidth if gCS returns auto (unless offsetWidth is
undefined, then fallback back to auto). The negative effect would be that
we'd lose subpixel values for width on inline elements. Also, inline SVG
elements would keep the broken .width() === 0 but we've never supported
that use case.
Timo: the problem with including transforms is that the same code handles
.css('width') where taking transforms into account is definitely unexpected.
--
Michał Gołębiowski
|
Not that's shipping in browsers. In fact maybe even that's not shipping; I thought that that https://drafts.csswg.org/cssom-view/#dom-geometryutils-getboxquads using the node itself as the relativeTo value might do the trick, but you'd probably still get post-transform sizes. (I should note that asking for the "width" of a non-replaced inline is a fairly odd question, especially as soon as there's a linebreak in the middle of it.) |
Just to provide feedback:
#2439 has not only the impact returning non-integer values.
I have a CSS transform:scale(2) in a root element with a div which has css width 200px.
jQuery 2.x returns 200 for .width() as it uses offsetWidth
jQuery 3.0 returns 400 for .width() as it uses getBoundingClientRect()
This is a breaking change which should be at least mentioned in the upgrade guide.
The text was updated successfully, but these errors were encountered: