207

I am using Twitter Bootstrap on a project. As well as the default bootstrap styles I have also added some of my own

//My styles
@media (max-width: 767px)
{
    //CSS here
}

I am also using jQuery to change the order of certain elements on the page when the width of the viewport is less that 767px.

$(document).load($(window).bind("resize", checkPosition));

function checkPosition()
{
    if($(window).width() < 767)
    {
        $("#body-container .main-content").remove().insertBefore($("#body-container .left-sidebar"));
    } else {
        $("#body-container .main-content").remove().insertAfter($("#body-container .left-sidebar"));
    }
}

The problem I am having is that the width calculated by $(window).width() and the width calculated by the CSS doesn't seem to be the same. When $(window).width() returns 767 the css calculates it the viewport width as 751 so there seems to be a 16px different.

Does anyone know what is causing this and how I could solve the problem? People have suggested that the width of the scrollbar isn't being taken into considering and using $(window).innerWidth() < 751 is the way to go. However ideally I want to find a solution that calculates the width of the scrollbar and that is consistent with my media query (e.g where both conditions are checking against the value 767). Because surely not all browsers will have a scrollbar width of 16px?

Pattle
  • 5,983
  • 8
  • 33
  • 56
  • 1
    Try something if ($('html').width() <= 767) { // Do something } – Vaibs_Cool Oct 10 '13 at 09:29
  • @Vaibs_Cool Thanks for the suggestion but I still get the same result – Pattle Oct 10 '13 at 09:30
  • 1
    Possible duplicate of [CSS media queries and JavaScript window width do not match](http://stackoverflow.com/questions/11309859/css-media-queries-and-javascript-window-width-do-not-match) – Ignitor Jan 16 '14 at 23:20
  • Answer i here [enter link description here][1] [1]: http://stackoverflow.com/questions/11309859/css-media-queries-and-javascript-window-width-do-not-match – Rantiev Feb 19 '14 at 14:24
  • Does "document.documentElement.clientWidth" (instead of "$(window).width()") work how you are wanting it to work? Edit: My mistake, just saw Vaibs_Cool's answer. – joshhunt Mar 28 '14 at 00:43
  • What browser/os are you testing this on? – joshhunt Mar 28 '14 at 00:46
  • You may be looking for **outerWidth**. See my comment below. – fzzylogic Mar 31 '14 at 06:53
  • I just answered this question over here: http://stackoverflow.com/questions/8161304/how-to-reliably-get-screen-width-with-the-scrollbar/23159528#23159528 – Joshua Plicque Apr 18 '14 at 18:06
  • Hey I answered this same question over here: http://stackoverflow.com/questions/8161304/how-to-reliably-get-screen-width-with-the-scrollbar/23159528#23159528 – Joshua Plicque Apr 18 '14 at 18:08
  • scrollbar is 16px btw... – zanderwar Oct 28 '16 at 12:36
  • The best solution on this site is from NateS. Moderniyer and other solutions looks like morons against it. – Čamo Nov 23 '16 at 21:57

18 Answers18

325

If you don't have to support IE9 you can just use window.matchMedia() (MDN documentation).

function checkPosition() {
    if (window.matchMedia('(max-width: 767px)').matches) {
        //...
    } else {
        //...
    }
}

window.matchMedia is fully consistent with the CSS media queries and the browser support is quite good: http://caniuse.com/#feat=matchmedia

UPDATE:

If you have to support more browsers you can use Modernizr's mq method, it supports all browsers that understand media queries in CSS.

if (Modernizr.mq('(max-width: 767px)')) {
    //...
} else {
    //...
}
ausi
  • 7,253
  • 2
  • 31
  • 48
  • 9
    If you can afford to use the Modernizr library, this is the best answer out there. – richsinn Sep 02 '14 at 05:22
  • 1
    This solution is better: http://stackoverflow.com/a/19292035/1136132 (2nd code). Only JS. – joseantgv Apr 28 '15 at 11:21
  • @joseantgv My solution is also js-only. Can you explain why the solution you linked to is better? – ausi Apr 28 '15 at 15:04
  • @ausi no need to extra library (Modernizr) and cross browser, not only IE9+ – joseantgv Apr 28 '15 at 15:32
  • @joseantgv The solution you linked to isn’t consistent with the CSS media queries in all browsers, that’s what my answer is all about. See: http://stackoverflow.com/questions/19291873/window-width-not-the-same-as-media-query/19292035#comment47998659_19292035 – ausi Apr 29 '15 at 08:58
  • Can confirm using jquery's innerWidth is still not capturing my css breakpoints in chrome – Frozenfire Aug 19 '15 at 19:22
  • Does Modernizr.mq() fire off automatically on window resizing/orientation changing? Or do you have to put window.resize() / orientation change yourself? I checked the docs, but didn't see anything – EdwardM Oct 26 '15 at 17:05
  • 2
    @edwardm `Modernizr.mq` only returns a boolean value, so you have to call it yourself in an `onresize` event handler. – ausi Oct 27 '15 at 17:08
  • The solution mentionned by NateS is way better. Doesn't need Modernizer and is compatible with every browser supporting media queries. – Bernig Apr 05 '16 at 09:38
  • @Bernig The solution from NateS is the same technique that is used by `Modernizr.mq`, but Modernizr uses `window.matchMedia` on modern browsers which is the recommended way. – ausi Sep 06 '16 at 12:09
  • @ausi right, but media queries having better browser support than matchMedia (not only for IE9), I don't see the point in using two techniques (for old and modern browsers) instead of one that works for both. Cf. http://caniuse.com/#search=CSS3%20Media%20Queries and http://caniuse.com/#search=matchMedia So still, I'd choose the simple yet effective version over the Modernizr one if we can avoid using it. But could you please ellaborate on why it is the recommended way (and by who) ? Thanks – Bernig Sep 06 '16 at 20:28
  • 3
    @Bernig `window.matchMedia` is the recommended way, because it doesn’t trigger a [reflow](http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/), depending on how often you call the function this can cause a performance problem. If you don’t want to use Modernizr directly, you can copy the source code from [src/mq.js](https://github.com/Modernizr/Modernizr/blob/5eea7e2a213edc9e83a47b6414d0250468d83471/src/mq.js) and [src/injectElementWithStyles.js](https://github.com/Modernizr/Modernizr/blob/5eea7e2a213edc9e83a47b6414d0250468d83471/src/injectElementWithStyles.js). – ausi Sep 08 '16 at 08:24
  • What if I need a width between sizes? Is `window.matchMedia('(min-width: 568px)').matches && window.matchMedia('(max-width: 767px)').matches` working? – Kurt Lagerbier Sep 17 '20 at 15:54
  • 1
    @KurtLagerbier Yes, that would work, but you could also use a simpler method and combine both media query like so: `window.matchMedia('(min-width: 568px) and (max-width: 767px)').matches` – ausi Sep 18 '20 at 08:41
  • Then the next question would be "Won't it be a headache to keep the CSS in JS and the bare CSS consistent"? E.g., what if you change something in CSS and forget to change the same property in the corresponding JS? – aderchox Jul 29 '21 at 14:37
  • If you want to respond to a media query based style change in the JavaScript I would use `getComputedStyle()` inside a `resize` event to check what the actual style is you are interested in. – ausi Jul 29 '21 at 15:38
190

Check a CSS rule that the media query changes. This is guaranteed to always work.

http://www.fourfront.us/blog/jquery-window-width-and-media-queries

HTML:

<body>
    ...
    <div id="mobile-indicator"></div>
</body>

Javascript:

function isMobileWidth() {
    return $('#mobile-indicator').is(':visible');
}

CSS:

#mobile-indicator {
    display: none;
}

@media (max-width: 767px) {
    #mobile-indicator {
        display: block;
    }
}
sohaiby
  • 1,168
  • 3
  • 24
  • 39
NateS
  • 5,751
  • 4
  • 49
  • 59
33

It may be due to scrollbar, use innerWidth instead of width like

if($(window).innerWidth() <= 751) {
   $("#body-container .main-content").remove()
                                .insertBefore($("#body-container .left-sidebar"));
} else {
   $("#body-container .main-content").remove()
                                .insertAfter($("#body-container .left-sidebar"));
}

Also you can get the viewport like

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' ] };
}

Above code Source

Rohan Kumar
  • 40,431
  • 11
  • 76
  • 106
  • Thanks. This will work but is there anyway I can use jquery to include the width of the scrollbar. I'm just thinking that the width of the scrollbar could change on different browsers? – Pattle Oct 10 '13 at 09:34
  • 1
    Yes use `innerWidth()` or you can use it like `$('body').innerWidth();` See this http://stackoverflow.com/questions/8339377/jquery-how-to-get-screen-width-without-scrollbar – Rohan Kumar Oct 10 '13 at 09:36
  • 3
    You mean window.innerWidth, not on the jQuery $(window) object, $(window).width() returns it incorrectly – EJanuszewski Nov 20 '14 at 12:54
  • 1
    `window.innerWidth` isn’t consistent with CSS media queries in Safari 8 if scrollbars are enabled in the OSX system preferences. – ausi Apr 29 '15 at 08:52
9

yes, that's due to scrollbar. Right answer source: enter link description here

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' ] };
}
Rantiev
  • 2,121
  • 2
  • 32
  • 56
5

It's maybe a better practice not to JS-scope the document's width but some sort of change made by css @media query. With this method you can be sure the JQuery function and css change happens at the same time.

css:

#isthin {
    display: inline-block;
    content: '';
    width: 1px;
    height: 1px;
    overflow: hidden;
}

@media only screen and (max-width: 990px) {
    #isthin {
        display: none;
    }
}

jquery:

$(window).ready(function(){
    isntMobile = $('#isthin').is(":visible");
    ...
});

$(window).resize(function(){
    isntMobile = $('#isthin').is(":visible");
    ...
});
gramgram
  • 565
  • 3
  • 18
5

Use

window.innerWidth

This solved my problem

user4451021
  • 67
  • 1
  • 1
3

I was facing the same problem recently - also with Bootstrap 3.

Neither $.width() nor $.innerWidth() will work for you.

The best solution I came up with - and is specifically tailored to BS3 -
is to check the width of a .container element.

As you probably know how the .container element works,
it's the only element that will give you the current width set by BS css rules.

So it goes something like

bsContainerWidth = $("body").find('.container').width()
if (bsContainerWidth <= 768)
    console.log("mobile");
else if (bsContainerWidth <= 950)
    console.log("small");
else if (bsContainerWidth <= 1170)
    console.log("medium");
else
    console.log("large");
user3041539
  • 607
  • 7
  • 17
3

Here is an alternative to the methods mentioned earlier that rely on changing something via CSS and reading it via Javascript. This method does not need window.matchMedia or Modernizr. It also needs no extra HTML element. It works by using a HTML pseudo-element to 'store' breakpoint information:

body:after {
  visibility: hidden;
  height: 0;
  font-size: 0;
}

@media (min-width: 20em) {
  body:after {
    content: "mobile";
  }
}

@media (min-width: 48em) {
  body:after {
    content: "tablet";
  }
}

@media (min-width: 64em) {
  body:after {
    content: "desktop";
  }
}

I used body as an example, you can use any HTML element for this. You can add any string or number you want into the content of the pseudo-element. Doesn't have to be 'mobile' and so on.

Now we can read this information from Javascript in the following way:

var breakpoint = window.getComputedStyle(document.querySelector('body'), ':after').getPropertyValue('content').replace(/"/g,'');

if (breakpoint === 'mobile') {
    doSomething();
}

This way we are always sure that the breakpoint information is correct, since it is coming directly from CSS and we don't have to hassle with getting the right screen-width via Javascript.

dschenk
  • 315
  • 2
  • 13
  • You don't need to use `querySelector()` or `getPropertyValue()`. You can look for single quote to in regex too (since it's not consistent). This: `window.getComputedStyle(document.body, ':after').content.replace(/"|'/g, '')`. And, to make that a bit less expensive, you can wrap it in underscore/lodash `._debounce()` with ~100ms wait. Finally, appending attribs to makes output available to other things such as tooltip disable clauses looking for raw flags/data outside vars. Example: https://gist.github.com/dhaupin/f01cd87873092f4fe2fb8d802f9514b1 – dhaupin Jun 23 '16 at 18:29
2

Javascript provides more than one method to check the viewport width. As you noticed, innerWidth doesn't include the toolbar width, and toolbar widths will differ across systems. There is also the outerWidth option, which will include the toolbar width. The Mozilla Javascript API states:

Window.outerWidth gets the width of the outside of the browser window. It represents the width of the whole browser window including sidebar (if expanded), window chrome and window resizing borders/handles.

The state of javascript is such that one cannot rely on a specific meaning for outerWidth in every browser on every platform.

outerWidth is not well supported on older mobile browsers, though it enjoys support across major desktop browsers and most newer smart phone browsers.

As ausi pointed out, matchMedia would be a great choice as CSS is better standardised (matchMedia uses JS to read the viewport values detected by CSS). But even with accepted standards, retarded browsers still exist that ignore them (IE < 10 in this case, which makes matchMedia not very useful at least until XP dies).

In summary, if you are only developing for desktop browsers and newer mobile browsers, outerWidth should give you what you are looking for, with some caveats.

fzzylogic
  • 2,183
  • 1
  • 19
  • 25
1

Here's a less involved trick to deal with media queries. Cross browser support is a bit limiting as it doesn't support mobile IE.

     if (window.matchMedia('(max-width: 694px)').matches)
    {
        //do desired changes
    }

See Mozilla documentation for more details.

user2128205
  • 37
  • 1
  • 1
  • 4
0

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.

0

The best cross-browser solution is to use Modernizr.mq

link: https://modernizr.com/docs/#mq

Modernizr.mq allows for you to programmatically check if the current browser window state matches a media query.

var query = Modernizr.mq('(min-width: 900px)');
if (query) {
   // the browser window is larger than 900px
}

Note The browser does not support media queries (e.g. old IE) mq will always return false.

Sanjib Debnath
  • 3,556
  • 2
  • 22
  • 16
0
if(window.matchMedia('(max-width: 768px)').matches)
    {
        $(".article-item").text(function(i, text) {

            if (text.length >= 150) {
                text = text.substring(0, 250);
                var lastIndex = text.lastIndexOf(" ");     
                text = text.substring(0, lastIndex) + '...'; 
            }

            $(this).text(text);

        });

    }
Adam Colton
  • 189
  • 2
  • 5
0

try this

getData(){
    if(window.innerWidth <= 768) {
      alert('mobile view')
      return;
    }

   //else function will work

    let body= {
      "key" : 'keyValue'
    }
    this.dataService.getData(body).subscribe(
      (data: any) => {
        this.myData = data
      }
    )
}
DINESH Adhikari
  • 1,242
  • 1
  • 12
  • 11
0

What i do ;

<body>
<script>
function getWidth(){
return Math.max(document.body.scrollWidth,
document.documentElement.scrollWidth,
document.body.offsetWidth,
document.documentElement.offsetWidth,
document.documentElement.clientWidth);
}
var aWidth=getWidth();
</script>
...

and call aWidth variable anywhere afterwards.

You need to put the getWidth() up in your document body to make sure that the scrollbar width is counted, else scrollbar width of the browser subtracted from getWidth().

burkul
  • 113
  • 1
  • 5
-1

if you want to check the width screen in the device every 1 second you can do

 setInterval(function() {
        if (window.matchMedia('(max-width: 767px)').matches) {
            alert('here')
        } else {
            alert('i am ')
        }
    }, 1000);
Ahmed Elgammudi
  • 642
  • 7
  • 15
  • Please don’t do this. This is a really bad suggestion, seeing that `MediaQueryList` (the type returned by `matchMedia` has a way of registering listeners that can be used to be notified when the result of the evaluation changes. – Raphael Schweikert Jul 08 '21 at 11:15
-2

Try this

if (document.documentElement.clientWidth < 767) {
   // scripts
}

For More Reference click here

Vaibs_Cool
  • 6,126
  • 5
  • 28
  • 61
-2

Implementation slick slider and display different numbers of slides in the block depending on the resolution (jQuery)

   if(window.matchMedia('(max-width: 768px)').matches) {
      $('.view-id-hot_products .view-content').slick({
        infinite: true,
        slidesToShow: 3,
        slidesToScroll: 3,
        dots: true,
      });
    }

    if(window.matchMedia('(max-width: 1024px)').matches) {
      $('.view-id-hot_products .view-content').slick({
        infinite: true,
        slidesToShow: 4,
        slidesToScroll: 4,
        dots: true,
      });
    }