53

For a responsive template, I have a media query in my CSS:

@media screen and (max-width: 960px) {
    body{
       /*  something */
       background: red;
    }
}

And, I made a jQuery function on resize to log the width:

$(window).resize( function() {
    console.log( $(window).width() );
    console.log( $(document).width() ); /* same result */
    /* something for my js navigation */
}

And there a difference with CSS detection and JS result, I have this meta:

<meta content="user-scalable=no, initial-scale=1.0, maximum-scale=1.0, width=device-width" name="viewport"/> 

I suppose it's due to the scrollbar (15 px). How can I do this better?

Valerio Bozz
  • 1,176
  • 16
  • 32
benoît
  • 1,473
  • 3
  • 13
  • 31

8 Answers8

72

You're correct about the scroll bar, it's because the CSS is using the device width, but the JS is using the document width.

What you need to do is measure the viewport width in your JS code instead of using the jQuery width function.

This code is from http://andylangton.co.uk/articles/javascript/get-viewport-size-javascript/

function viewport() {
    var e = window, a = 'inner';
    if (!('innerWidth' in window )) {
        a = 'client';
        e = document.documentElement || document.body;
    }
    return { width : e[ a+'Width' ] , height : e[ a+'Height' ] };
}
Michael Bird
  • 824
  • 7
  • 4
  • Solid. Much better than $(document).width(); window.matchMedia() is probably better, but its IE10+ – Bosworth99 May 21 '14 at 19:19
  • 4
    This doesn't seem to work if the window has scroll bars and your media queries are checking max-width, at least in Chrome. Checking some css on an element that you know is set by a particular media query appears to work though. – mhenry1384 Oct 14 '14 at 18:08
  • @mhenry1384 what are you talking about? – Jürgen Paul Jul 23 '16 at 12:44
9

I found following code on http://www.w3schools.com/js/js_window.asp:

var w=window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;

Practically its working the same way as the answer in @Michael Bird's answer, but it's more easy to read.

Edit: I was looking for a method to give exactly the same width as it is used for css media queries. But the suggested one does not work perfect on Safari with scrollbars, sorry. I ended up using modernizr.js in one central function and in the rest of the code I just check if display type is mobile, tablet or desktop. As I am not interested in the width, this works fine for me:

getDisplayType = function () {
  if (Modernizr.mq('(min-width: 768px)')){
    return 'desktop';
  }
  else if (Modernizr.mq('(min-width: 480px)')){
    return 'tablet'
  }
  return 'mobile';
};
LarS
  • 1,324
  • 20
  • 27
  • 1
    If `document.documentElement` doesn't exist, this script will fail. Don't trust w3schools, see http://www.w3fools.com/ – ausi Mar 28 '14 at 10:09
  • 3
    @ausi: Would you please be so kind and elaborate a bit more than "don't trust w3schools"? I can't see the problem so far. See also [Any cross browser issues with document.documentElement](http://stackoverflow.com/questions/11391827/any-cross-browser-issues-with-document-documentelement) – LarS Mar 29 '14 at 21:48
  • 1
    OK, seems there is no browser which doesn't have `document.documentElement`. Didn't know that. – ausi Mar 30 '14 at 13:01
7

window.innerWidth is what you need.

if (window.innerWidth < 768) works for 768 break point in CSS

Ross
  • 511
  • 2
  • 9
  • 18
3

Workaround that always works and is synced with CSS media queries.

Add a div to body

<body>
    ...
    <div class='check-media'></div>
    ...
</body>

Add style and change them by entering into specific media query

.check-media{
    display:none;
    width:0;
}
@media screen and (max-width: 768px) {
    .check-media{
         width:768px;
    }
    ...
}

Then in JS check style that you are changing by entering into media query

if($('.check-media').width() == 768){
    console.log('You are in (max-width: 768px)');
}else{
    console.log('You are out of (max-width: 768px)');
}

So generally you can check any style that is being changed by entering into specific media query.

gsamaras
  • 71,951
  • 46
  • 188
  • 305
1

My experience was that the media query width tracks document.body.clientWidth. Because of a vertical scroll bar coming and going, checking document, window, or viewport().width could cause my Javascript to run late--after the media query rule change, depending on the height of the window.

Checking document.body.clientWidth allowed my script code to execute consistently at the same time the media query rule took effect.

@media (min-width:873px) {
     //some rules
}
...

if ( document.body.clientWidth >= 873) {
    // some code
}

The Andy Langton code put me onto this--thanks!

Jim
  • 125
  • 2
  • 5
  • 1
    If the body is wider than the screen this won't work. I saw solutions where an invisible div is positioned fixed and it's width is set to 100%. Using it's clientWidht should work. – LarS Mar 29 '14 at 22:01
1

Hi i use this little trick to get JS and CSS work together easily on responsive pages :

Test the visibility of an element displayed or not on CSS @media size condition. Using bootstrap CSS i test visibility of a hidden-xs class element

var msg = "a message for U";

/* At window load check initial size  */
if ( $('#test-xsmall').is(':hidden')  ) {
  /* This is a CSS Xsmall situation ! */
  msg = "@media CSS < 768px. JS width = " + $(window).width() + " red ! ";
  $('.redthing-on-xsmall').addClass('redthing').html(msg);

} else {
  /* > 768px according to CSS  */
  msg = "@media CSS > 767px. JS width = " + $(window).width() + " not red ! ";
  $('.redthing-on-xsmall').removeClass('redthing').html(msg);
}


/* And again when window resize  */

$(window).on('resize', function() {
  if ($('#test-xsmall').is(':hidden')) {
    msg = "@media CSS < 768px. JS width = " + $(window).width() + " red ! ";
    $('.redthing-on-xsmall').addClass('redthing').html(msg);
  } else {
    msg = "@media CSS > 767px. JS width = " + $(window).width() + " not red ! ";
    $('.redthing-on-xsmall').removeClass('redthing').html(msg);
  }
});
@media (min-width: 768px) {
  .hidden-xs {
    display: block !important;
  }
}
@media (max-width: 767px) {
  .hidden-xs {
    display: none !important;
  }
}
.redthing-on-xsmall {
  /* need a scrollbar to show window width diff between JS and css */
  min-height: 1500px;
}
.redthing {
  color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<!-- the CSS managed Element that is tested by JS --> 
<!-- class hidden-xs hides on xsmall screens (bootstrap) -->

<span id="test-xsmall" class="hidden-xs">THIS ELEMENT IS MANAGED BY CSS  HIDDEN on @media lower than 767px</span>


<!-- the responsive element managed by Jquery  -->
<div class="redthing-on-xsmall">THIS ELEMENT IS MANAGED BY JQUERY RED on @media max width 767px </div>
fr-info
  • 11
  • 4
1

The simple and reliable way of doing this is to use Media Queries.

To demonstrate, I want to check if the screen width is greater than or equal to 992px (Bootstrap's large device):

function isLargeDevice() {
    if (window.matchMedia("(min-width: 992px)").matches) {
        return true;
    } 
    return false;
}

If you are using Modernizer then it's a bit easier, here I want to check if the screen is smaller than Bootstrap's large screen (992px)

function isSmallerThanLargeScreen() {
    if (Modernizr.mq('(max-width: 991px)')) {
        return true;
    }
    return false;
}
Hooman Bahreini
  • 14,480
  • 11
  • 70
  • 137
0

Css media query is equal to window.innerWidth. Css Media Queries calculate the scrollbar as well.

Paul Ghiran
  • 1,233
  • 1
  • 16
  • 29
Sam Morgan
  • 191
  • 1
  • 1
  • 4