18

I'm trying to let jQuery take care of a menu, while CSS does something to the window background when resizing the browser.

So jQuery does something like this:

if ( $(window).innerWidth() < mediaQueries['small']) {
    // (where 'small' would be 966)
    // Perform jQuery stuff on a menu ul
}

And CSS has something like this:

@media all and (max-width: 966px) {
    body {
        background: url(smallback.jpg) no-repeat 0 0;
    }
}

When using Firefox, there's a gap of 17 pixels (which seems to be the vertical scrollbar width) in which the jQuery stuff is already handled, but the CSS is not.

As other browsers may use different widths for their scrollbars, just adding 17px to the CSS won't really fix the problem. So how do I get jQuery to take the scrollbars into account? $(window).innerWidth() doesn't seem to do that for me.

Any help would greatly be appreciated.

Open this page in Firefox, Opera or IE for an isolated version of the problem. (Chrome and Safari don't suffer from this problem. Thusfar: Webkit: +1, Gecko: -1, Trident: -1, Presto: -1.)

3
  • what happens if you use width() ? Commented Dec 12, 2011 at 10:16
  • @Ben the same thing, it doesn't matter. Looks like the Javascript forgets about the scrollbars? Commented Dec 12, 2011 at 10:18
  • can you setup a basic example somewhere for people to test ? Commented Dec 12, 2011 at 10:19

5 Answers 5

35

In addition to the solution of JackieChiles:

Using

var width = Math.max( $(window).width(), window.innerWidth);
will always get you the width without scrollbars in any browser.

This solution is (IMHO) better because the JS does not depend on any CSS.

Thanks to JackieChiles and Arjen for this solution!

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you, this solution worked for me. jQuery documentation says that .innerWidth() is not applicable to window and document objects; for these, use .width() instead. I have edited your answer accordingly.
My issue had not cute display in webkit browsers. I had to use this way to fix: isWebKit ? $(window).width() : Math.max($(window).width(), window.innerWidth);
10

My solution to triggering JavaScript at the exact same time as media queries (even in the face of device or browser quirks as seen here) is to trigger my window.resize logic in response to a change that the media query made. Here's an example:

CSS

    #my-div
    {
        width: 100px;
    }

    @media all and (max-width: 966px)
    {
        #my-div
        {
            width: 255px;
        }
    }

JavaScript

    var myDivWidth;

    $(document).ready(function() {
        myDivWidth = $('#myDiv').width();

        $(window).resize(function () {
            if ($('#myDiv').width() != myDivWidth) {
                //If the media query has been triggered
                myDivWidth = $('#myDiv').width();
                //Your resize logic here (the jQuery menu stuff in your case)
            }
        });
    });

In this example, whenever #myDiv changes size (which will occur when the media query is triggered), your jQuery resize logic will also be run.

For simplicity I used an element width, but you could easily use whatever property you are changing, such as the body background.

Another advantage of this approach is that it keeps the window.resize function as lightweight as possible, which is always good because it is called every single time the window size changes by a single pixel (in most modern browsers anyway).

The bug that you encountered seems to me to be a browser-specific problem, as you said. Although it seems incorrect intuitively, Firefox (and other browsers with the issue) actually seems to match the W3C recommendation for media queries more closely than the Webkit browsers. The recommendation states that the viewport width includes scrollbars, and JavaScript window width does not seem to include scrollbars, hence the disrepancy.

7 Comments

Thanks a lot! Although it's a workaround it sure is helpful advice, because now users will experience no difference.
@Simon: Glad I could help. It certainly is frustrating though that the media query and JavaScript definitions of width don't always agree.
@Simon You should mark Jackie's answer as correct (tick next to it)
@Simon: Just using window.innerWidth will give you the full width including scrollbars as opposed to the jQuery $(window).innerWidth(). Although window.innerWidth may fix your problem in Firefox, it will then occur in the WebKit browsers.
@JackieChiles Ah, nice! Forgot that JS != JQ. :-) And though I always hate "if (IE) then ... if (FF) then ... if (Chrome) then ..." code, I guess it'll take a while before we could get rid of that (if ever).
|
4

If you happen to be using Modernizr, you can include the media query polyfill, which simplifies media query checks to:

if (Modernizr.mq('all and (max-width: 966px)')) {
    ...
}

Which is conveniently identical to your CSS:

@media all and (max-width: 966px) {
    ...
}

If you can't use Modernizr's polyfill, then stick with checking against Math.max(document.width, window.innerWidth).

Comments

2

window.matchMedia is a way you can fire events when media selectors kick on or off. It's new so not widely supported, but seems pretty useful.

"Using media queries from code" from MDN

Comments

-1
var viewport = jQuery(window).innerWidth();

if( viewport > 979 )
{
  // your code here
}

1 Comment

I'm sorry, but that's not even remotely an answer to the question. I think it's good that you put an effort in helping other people to solve their problems, but you're not helping if you don't read what their problem is about.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.