Bug Tracker

Opened 6 years ago

Closed 5 years ago

#14989 closed bug (migrated)

$(window).width() AND $(window).outerWidth() excluding the scrollbar width

Reported by: antti@… Owned by: dmethvin
Priority: low Milestone: 1.12/2.2
Component: dimensions Version: 2.1.0
Keywords: Cc:
Blocked by: Blocking:

Description

It is sometimes annoying that $(window).width() or $(window).outerWidth() do not include the scrollbar width in their value. Especially when trying to match the window width to the CSS media queries.

Currently e.g. if you have a media query in the CSS such as

@media screen and (max-width: 1600px) {
  body {background: red;}
}

When the red background is actually applied to the document by the browser, jQuery tells the window width is less than 1600px (1600 - scrollbar width).

This is annoying e.g. in cases where there are some mobile-specific stuff that needs to be done in both, CSS and JS. And they would need to be done at the exactly same width of the document/window.

However, plain JavaScript returns 1600 as the window width when asked at the point of the breakpoint as follows:

console.log(window.innerWidth);

Is it possible to get either $(window).width() or $(windor).outerWidth() working consistently with the browser's actual width? $(document).width() and $('body').width() will not return the same as "window.innerWidth" either, they return the same as $(window).width() and $(window).outerWidth().

Fixing this would greatly help making consistent code with the CSS media queries.

Possible workarounds currently are:

  • Using plain javascript, i.e. window.innerWidth
  • Checking $('...').is(':visible') for some element that is visible only in the target width

Here's an example of what I mean: http://jsfiddle.net/aq5vb/

Change History (18)

comment:1 Changed 6 years ago by antti@…

And this applies to earlier versions of jQuery as well, I just reported it for the latest stable.

comment:2 Changed 6 years ago by dmethvin

I'm very concerned about changing this, considering the compatibility implications; it's been this way forever. For $(window).width() we return document.documentElement.clientWidth which does not include the scrollbars as you've observed. We say that is "the width of the viewport".

http://api.jquery.com/width/

Any other opinions on this? If people expect it to exclude scrollbars we would break a lot of code by changing it.

comment:3 Changed 6 years ago by anonymous

I'm not sure if I articulated myself very clearly but what I actually meant was that the jQuery width in fact EXCLUDES the scroll bar from the width while the CSS media queries count it as part of the viewport.

Here's an image that might (or not) emphasize my point (see also the CSS that defines the breakpoint): http://i.imgur.com/2mtrjGw.jpg

If you say it's the "width of the viewport", shouldn't it be consistent with what the browser considers as the viewport width then?

I understand that it would might things but it just bothers me that it does not match the width that the CSS media queries are using, i.e. the width of the viewport. In fact, none of these do (you can test this by changing it in the jsFiddle above):

$(window).width();
$(window).innerWidth();
$(window).outerWidth();

Any possibility to get even ONE of these working consistently with the browser's viewport width?

comment:4 Changed 6 years ago by dmethvin

Yes, you made yourself clear. My point was that as far as I can tell we have been doing it this way for a long time. If we change it there is a very good chance that we will break someone's code who expects the width to include only the client area. Still looking for feedback from others.

comment:5 Changed 6 years ago by scottgonzalez

Please don't change this. Honestly, it's strange that the media queries include the scrollbars since developers are obviously using things like (max-width: 600px) based on actual usable space, and that excludes scrollbars.

I'd expect tons of broken sites if jQuery changed, but almost no broken sites if media queries changed. Just a thought...

comment:6 Changed 6 years ago by antti@…

I understand that changing $(window).width() would break things.

I don't think changing $(window).outerWidth() would break anything.

comment:7 Changed 6 years ago by antti@…

And could someone also post me an example of a code that would break or behave strangely if this was changed? I'm not quite sure if I currently even see the risk as high as you guys.

comment:8 Changed 6 years ago by antti@…

And just adding to this, looking closer to the API documentation of .width().

It states the following:

// Returns width of browser viewport
$( window ).width();
 
// Returns width of HTML document
$( document ).width();

So, if $(window).width() currently returns document.documentElement.clientWidth, isn't this wrong regarding to the API documentation?

comment:9 Changed 6 years ago by scottgonzalez

And could someone also post me an example of a code that would break or behave strangely if this was changed?

Anything that positions elements relative to the window, e.g., notifications. Positioning against the top right corner would overflow and cause a horizontal scrollbar.

Anything that sizes elements relative to the window, e.g., overlays. The overlay would be too large and would cause a horizontal scrollbar.

Anything that does bounds testing against the window, e.g., draggable elements contained to the window. The bounds would be slightly too wide and would cause a horizontal scrollbar at the right edge, increasing the size of the document and the bounds.

There are likely several other scenarios as well. Those are the generic cases that popped into my head right away.

comment:10 Changed 6 years ago by antti@…

Does not sound something I would do with jQuery, I think all of these cases are handled by CSS in most occasions. But the bounds part, you're correct on that one.

But yeah, it might break such things because of which I was looking for actual references to existing code that I could test against (e.g. links to github projects).

comment:11 Changed 5 years ago by dmethvin

Component: unfileddimensions
Milestone: None1.12/2.2
Priority: undecidedlow
Status: newopen

It seems highly unlikely that anyone would be using $(window).outerWidth() today so I'll mark this open for now and a potential change for 1.12/2.2.

comment:12 Changed 5 years ago by dmethvin

Owner: set to dmethvin
Status: openassigned

comment:13 in reply to:  11 Changed 5 years ago by scottgonzalez

Replying to dmethvin:

It seems highly unlikely that anyone would be using $(window).outerWidth() today so I'll mark this open for now and a potential change for 1.12/2.2.

#9434

comment:14 Changed 5 years ago by dmethvin

Why do we have all 3 return the same value? I'm wondering about the use case that spawned #9434.

comment:15 Changed 5 years ago by scottgonzalez

The use case is generic plugins that operate on elements, documents, and windows. For example, a plugin that centers x inside y would do something like:

x.css( "left", (y.outerWidth() - x.outerWidth()) / 2 );

The correct behavior would be achieved today even if y is a window. However, if the scrollbar width is included, x would be off-center by half the size of the scrollbar. To compensate for this, you would need to check for windows:

var yWidth = $.isWindow( y[ 0 ] ) ? y.width() : y.outerWidth();
x.css( "left", (yWidth - x.outerWidth()) / 2 );

Note that this extended logic is already required if you want to support jQuery <1.7 since that didn't support .outerWidth() on windows.

comment:16 Changed 5 years ago by scottgonzalez

comment:17 Changed 5 years ago by emartel

Hi,

Sorry I don't have a strong web development background but I'm very interested in the topic and I thought one of the best way to learn more is to collaborate with existing projects.

I've given some thoughts about this problem, and I'm wondering if there wouldn't be a simple solution to it...

I'm not sure how "elegant" this solution is, but it might be a start to handle legacy code and new code that wants an outerWidth that takes scrollbars into account.

Would it be an option to add a "state" to the window jQuery object? By default, the state is legacy / no-scrollbar / a decent name that explains the behavior of calls made on this object. Using a function call such as $(window).sizeExcludesScrollbars(true/false), the state is altered and the state is persisted, making subsequent calls to width / height take scollbars into account or not?

I believe that such a change would give Antti what he wants while leaving existing code described by Scott functional.

What do you guys think?

comment:18 Changed 5 years ago by m_gol

Resolution: migrated
Status: assignedclosed
Note: See TracTickets for help on using tickets.