22

which is the fastest and easy way to fire when bootstrap-responsive.css media queries go in action?

go in action = when you resize window to mobile width and site is changed to responsive mobile

hope question is clear

itsme
  • 48,972
  • 96
  • 224
  • 345
  • 1
    possible duplicate of [Bootstrap: Responsitive design - execute JS when window is resized from 980px to 979px](http://stackoverflow.com/questions/12168420/bootstrap-responsitive-design-execute-js-when-window-is-resized-from-980px-to) – ceejayoz Nov 24 '13 at 21:32
  • You'll need to do it with JavaScript. – ceejayoz Nov 24 '13 at 21:33

16 Answers16

32

I came up with an approach that uses window resize event, but relying on Twitter Bootstrap's media queries without hard coding their breakpoints:

<span id="mq-detector">
    <span class="visible-xs"></span>
    <span class="visible-sm"></span>
    <span class="visible-md"></span>
    <span class="visible-lg"></span>
</span>

#mq-detector {
    visibility: hidden;
}

var currMqIdx = undefined;
var mqDetector = $("#mq-detector");
var mqSelectors = [
    mqDetector.find(".visible-xs"),
    mqDetector.find(".visible-sm"),
    mqDetector.find(".visible-md"),
    mqDetector.find(".visible-lg")
];

var checkForResize = function() {
    for (var i = 0; i <= mqSelectors.length; i++) {
        if (mqSelectors[i].is(":visible")) {
            if (currMqIdx != i) {
                currMqIdx = i;
                console.log(mqSelectors[i].attr("class"));
            }
            break;
        }
    }
};

$(window).on('resize', checkForResize);

checkForResize();
falsarella
  • 12,217
  • 9
  • 69
  • 115
  • 3
    Neat :) I used your trick to set Bootstrap thumbnails to the same height, see [here](http://stackoverflow.com/questions/30205766/bootstrap-thumbnailscaption-with-same-height-per-row#30219581). – Jens May 13 '15 at 15:45
  • 1
    I like how this avoids duplicating the bootstrap configuration -- no magic numbers getting out of sync! – Levi Apr 11 '16 at 03:46
  • 1
    @farsarella Your answer is fabulous. Good job! – pedrozopayares Mar 09 '17 at 23:31
14

One issue with the other answers is the change event is triggered EVERY resize. This can be very costly if your javascript is doing something significant.

The code below calls your update function only one time, when a threshold is crossed.

To test, grab your window size handle, and drag resize it quickly to see if the browser chokes.

<script>
// Global state variable
var winSize = '';

window.onresize = function () {
    var newWinSize = 'xs'; // default value, check for actual size
    if ($(this).width() >= 1200) {
        newWinSize = 'lg';
    } else if ($(this).width() >= 992) {
        newWinSize = 'md';
    } else if ($(this).width() >= 768) {
        newWinSize = 'sm';
    }

    if( newWinSize != winSize ) {
        doSomethingOnSizeChange();
        winSize = newWinSize;
    }
};
</script>
Stickley
  • 4,561
  • 3
  • 30
  • 29
  • So, just to clarify the differences: the key point you described is the execution being triggered ONLY when `(newWinSize != winSize)`. – falsarella Feb 05 '15 at 16:50
  • This is correct. Your function is called only once when a threshold is crossed. – Stickley Feb 08 '15 at 01:50
  • 1
    @Stickley: Where are you defining newWinSize? Shouldn't you have `var newWinSize = '';` below `var winSize` – Chris Oct 06 '15 at 12:27
13

Using jquery you can find the size of current window and then accordingly do your stuff.

$(window).resize(function() {
  if ($(this).width() >= 1280) {
    //do something
  }
  else if ($(this).width() < 1280 && $(this).width()>= 980) {
    //do something
  }
  ...
});

CSS:: Twitter-Bootsrap-layouts

/* Large desktop */
@media (min-width: 1200px) { ... }

/* Portrait tablet to landscape and desktop */
@media (min-width: 768px) and (max-width: 979px) { ... }

/* Landscape phone to portrait tablet */
@media (max-width: 767px) { ... }

/* Landscape phones and down */
@media (max-width: 480px) { ... }
softvar
  • 17,917
  • 12
  • 55
  • 76
  • 2
    This doesn't work. On Chrome and possible other browsers, Jquery gives you the width of the HTML content, while the min-width in CSS depends on the width of the browser window itself. – Bjørn Stenfeldt Nov 26 '13 at 09:50
  • @BjørnStenfeldt OP wants to know the width of resized window. Your answer doesn't seem to work at all. Check your code here in my JS fiddle http://jsfiddle.net/softvar/bQsEV/ – softvar Nov 26 '13 at 12:03
10

This works for me in combination with Bootstrap 3:

<div id="media-width-detection-element"></div>
<style type="text/css">
    #media-width-detection-element {
        display: none;
        width: 0px;
    }
    @media (min-width: 768px) {
        #media-width-detection-element {
            width: 768px;
        }
    }
    @media (min-width: 992px) {
        #media-width-detection-element {
            width: 992px;
        }
    }
    @media (min-width: 1200px) {
        #media-width-detection-element {
            width: 1200px;
        }
    }
</style>
<script type="text/javascript">
    //<![CDATA[
    function xs() {
        return $("#media-width-detection-element").css("width") === "0px";
    }
    function sm() {
        return $("#media-width-detection-element").css("width") === "768px";
    }
    function md() {
        return $("#media-width-detection-element").css("width") === "992px";
    }
    function lg() {
        return $("#media-width-detection-element").css("width") === "1200px";
    }
    //]]>
</script>

The hidden DIV change width depending on the actual CSS min-width settings in use. Then my javascript simple check the current with of the DIV.

Bjørn Stenfeldt
  • 1,432
  • 1
  • 18
  • 25
  • OP wants to know the width of resized window. Your answer doesn't seem to work at all. Check your code here in my JS fiddle http://jsfiddle.net/softvar/bQsEV/ – softvar Nov 26 '13 at 12:02
  • 2
    The code works fine: http://jsfiddle.net/JWTt5/ ... I will let OP decide if this is the right answer or not. – Bjørn Stenfeldt Nov 26 '13 at 12:54
  • The page always alert for `xs`, no other alert works even if window is resized, also it's not responsive i.e. doesn't work on resizing window. – softvar Nov 26 '13 at 14:38
  • 2
    That's because it's in a frame. You need a high screen resolution to get it to say anything other than `xs`, or you need to take the code out of the frame. To make it pop up when you resize, simply put the alert inside `$(window).resize(function() { /*PUT ALERT HERE*/ });` – Bjørn Stenfeldt Nov 26 '13 at 20:01
5

Excellent Tip, @falsarella!

For those who like this sort of thing to not affect their actual markup the following works:

$(function(){
...
var mqClasses = ["visible-xs", "visible-sm", "visible-md", "visible-lg"];
var mq = $("<span id='mqDetector' style='visibility:hidden'></span>").appendTo($("body"));
$.each(mqClasses, function(idx, val) {
    mq.append("<span class='" + val + "'></span>");
});
function checkMQ() {
    var visible = mq.find(":visible").get(0).className;
    return visible.slice(-2);
};

function checkResize(){
    switch(checkMQ){
      case 'xs' : ...; break;
      case 'sm' : ...; break;
     ...
    }
}
$(window).on('resize', checkResize);
checkResize(); //do it once when page loads.
Community
  • 1
  • 1
bknights
  • 14,408
  • 2
  • 18
  • 31
  • Like this approach. I'm going to use this on my projects from now on. But I had some problems with `:visible`. Sometimes it was simply `false` on all the sizes (xs, sm, md, lg). I ended up using `function checkMQ() { var found; mq.children().each(function() { if ($(this).css("display") !== "none") { found = $(this); return false; } return true; }); return found.attr("class").slice(-2);}`. – Bjørn Stenfeldt Nov 06 '15 at 14:23
  • Shouldn't be possible but IIRC some early versions of the 3.x had hard-coded some of the responsive breakpoints so if you changed your grid you had to do some search and replace in order to get all the changes. Perhaps the @screen-zz-(max|min) values were affected by this. – bknights Nov 06 '15 at 19:20
  • Tested it on 3.0.0, so I guess that could be it. – Bjørn Stenfeldt Nov 06 '15 at 22:42
2

this code add body tag ld, md, sd or xd class

     $(function(){

        var device_width_detect = '';

        function device_detec(){
            if ($(this).width() >= 1280) {
                device_width_detect = 'ld';
            }else if ($(this).width() < 1280 && $(this).width()>= 992) {
                device_width_detect = 'md';
            }else if ($(this).width() < 992 && $(this).width()>= 768) {
                device_width_detect = 'sd';
            }else if ($(this).width() < 768) {
                device_width_detect = 'xd';
            }
            $('body').removeClass( "ld md sd xd" ).addClass( device_width_detect );
        }
        device_detec();
        $(window).on('resize', device_detec);

    });
user243709
  • 21
  • 1
1

Based on @falsarella's solution, the js part can be simplified to:

var currMqIdx = undefined;
var checkForResize = function() {    
    currMqIdx = $('#mq-detector span').index($('#mq-detector span:visible'));
};

$(window).on('resize', checkForResize);
checkForResize();

currMqIdx would be an int value, from 0 to 3. The bigger currMqIdx is, the wider the media is.

Community
  • 1
  • 1
aGuegu
  • 1,813
  • 1
  • 21
  • 22
1

Simpler

$(window).on('resize', function () {
  if ($('<div class="visible-lg">').css('display')=='block') {
    // Do something for lg
  }
  // ...
});
cmc
  • 4,294
  • 2
  • 35
  • 34
1

I have prepered a super lightweight library to deal with events fired when window width and Bootstrap breakpoint is changed - responsive-breakpoint-tester

var viewport = new ResponsiveTester();

$('body').on('in.screen.xs', function(event, devices) {
    // Code executed when viewport is was changed to xs
});

$('body').on('out.screen.xs', function(event, devices) {
    // Code executed when viewport is no longer xs
});

Other features like current breakpoint check are also included:

if (viewport.is('xs')) {
    // Executed only on xs breakpoint
}

if (viewport.is('!=xs')) {
    // Executed on all breakpoints that are not equal xs (sm, md, lg)
}

if (viewport.is('<md')) {
    // Executed on breakpoints that are smaller than md (xs, sm)
}

if (viewport.is('<=md')) {
    // Executed on breakpoints that are smaller or equal to md (xs, sm, md)
}

if (viewport.is('>md')) {
    // Executed on breakpoints that are larger than md (lg)
}

Bootstrap 4 and Foundation configuraions are supported, more info on GitHub Repository

patrykgruszka
  • 36
  • 1
  • 4
1

here is my solution for bootstrap 4, based on @falsarella idea

*note: use "full page" option below for test this snippet, otherwise it will return wrong screen type, based on snippet iframe size

/**
 * @returns STRING current screen type like: xs, sm, md, lg or xl
 */
function getScreenType() {

  !function initHelpers() {
    if ($('div.mq-detector').length !== 0) return;
    $('body').append(_mqDetector());
    // helpers
    function _mqDetector() {
      return `
      <div class="mq-detector invisible">
        <div
          class="d-block d-sm-none"
          data-type="xs"></div>
        <div
          class="d-none d-sm-block d-md-none"
          data-type="sm"></div>
        <div
          class="d-none d-md-block d-lg-none"
          data-type="md"></div>
        <div
          class="d-none d-lg-block d-xl-none"
          data-type="lg"></div>
        <div
          class="d-none d-xl-block"
          data-type="xl"></div>
      </div>
      `;
    }
  }();

  // @then

  return $('div.mq-detector').children().filter(':visible').data('type');

}

console.log(getScreenType())
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">
webolizzer
  • 337
  • 2
  • 5
1

Improving the excellent @falsarella answer, here is a shorter version that works with Bootstrap 4 :

CSS :

#mq-detector {
    visibility: hidden;
}

HTML :

<div id="mq-detector">
    <span data-mq="xs" class="d-block d-sm-none"></span>
    <span data-mq="sm" class="d-none d-sm-block d-md-none"></span>
    <span data-mq="md" class="d-none d-md-block d-lg-none"></span>
    <span data-mq="lg" class="d-none d-lg-block d-xl-none"></span>
    <span data-mq="xl" class="d-none d-xl-block"></span>
</div>

JAVASCRIPT :

//Define function that returns the currently used media query
function getBsMq(){
    var currMq;
    var mqDetector = $('#mq-detector [data-mq]');
    mqDetector.each(function(i){
        if ($(this).is(':visible')) {
            currMq = $(this).attr('data-mq');
        }
    });
    return currMq;
}


//Call the function and get the currently used media query
alert(getBsMq());
AlexLaforge
  • 499
  • 3
  • 19
0

You can use matchMedia and a wrapper library enquire.js which registers media queries and emits events when they are matched/unmatched.

Usage

Let's use these Bootstrap CSS media queries as an example taken from the docs.

/* Extra small devices (phones, less than 768px) */
/* No media query since this is the default in Bootstrap */

/* Small devices (tablets, 768px and up) */
@media (min-width: @screen-sm-min) { ... }

/* Medium devices (desktops, 992px and up) */
@media (min-width: @screen-md-min) { ... }

/* Large devices (large desktops, 1200px and up) */
@media (min-width: @screen-lg-min) { ... }

To see when each of these rules get applied, use enquire.js to register the media queries and supply appropriate match and unmatch functions, as below:

let rules = [
    '(max-width: 768px)',  // extra small devices, default
    '(min-width: 768px)',  // small devices
    '(min-width: 992px)',  // medium devices
    '(min-width: 1200px)'  // large devices
];

for (let rule of rules) {
    enquire.register(rule, {
      match: function() {
        console.log(rule + ' matched');
      },      

      unmatch: function() {
        console.log(rule + ' unmatched');
      } 
    });
}

enquire.js uses matchMedia which supports only the modern browsers, no IE9 for example. So polyfill will be needed for legacy browsers to make this work.

Demo

Karolis Ramanauskas
  • 1,045
  • 1
  • 9
  • 14
0

I used this to only stick the navbar at https://ducttapedanyol.com in bootstrap on large screens:

if ($(this).width() >= 979) { // Detect screen size
$(document).ready(function () {

    var menu = $('.menu');
    var origOffsetY = menu.offset().top;

    function scroll() {
       if ($(window).scrollTop() >= origOffsetY) {
          $('.menu').addClass('sticky');
          $('.fix').addClass('fix-tall');
       } else {
          $('.menu').removeClass('sticky');
          $('.fix').removeClass('fix-tall');
       }


    }

    document.onscroll = scroll;

});
}
Topher
  • 141
  • 1
  • 2
  • 9
0

I have revised codes in this link to Bootsrap 4 not alpha or beta. Codes as below;

    /* **********************************************************
        Detect bootrap 4 media query type
        https://getbootstrap.com/docs/4.0/utilities/display/
   ********************************************************** */


    $("body").append("<div style='visibilty:hidden' class='viewport-check'><span class='d-block d-sm-none'>xs</span><span class='d-none d-sm-block d-md-none'>sm</span><span class='d-none d-md-block d-lg-none'>md</span><span class='d-none d-lg-block d-xl-none'>lg</span><span class='d-none d-xl-block'>xl</span></div>");

    var Bootstrap4MediaQuery = "";

    //> Checks if the span is set to display block via CSS
    function FnDetectMediaQuery(_QsTarget) {
        var _QsTarget = $(_QsTarget).css('display') == 'block';
        return _QsTarget;
    }

    if(FnDetectMediaQuery('.viewport-check .d-block') == true)
    {
        Bootstrap4MediaQuery = "xs";
    }
    else if(FnDetectMediaQuery('.viewport-check .d-sm-block') == true)
    {
        Bootstrap4MediaQuery = "sm";
    }
    else if(FnDetectMediaQuery('.viewport-check .d-md-block') == true)
    {
        Bootstrap4MediaQuery = "md";
    }
    else if(FnDetectMediaQuery('.viewport-check .d-lg-block') == true)
    {
        Bootstrap4MediaQuery = "lg";
    }
    else if(FnDetectMediaQuery('.viewport-check .d-xl-block') == true)
    {
        Bootstrap4MediaQuery = "xl";
    }
    else
    {
        Bootstrap4MediaQuery = "";
    }

    console.log("Bootstrap4MediaQuery: " + Bootstrap4MediaQuery);
Kerberos
  • 1,228
  • 6
  • 24
  • 48
0

I'd use window.matchMedia with window.addEventListener('resize'). Example below, specifically function getActiveBreakpoint() will tell you which breakpoint is active, but will also tell you which ones are lt- (less then) and gt- (greater then) in form of helper classes i.e. gt-xs gt-sm md lt-lg lt-xl, see https://jsfiddle.net/Lqtmc8yo/1/

/*
// from bootstrap/scss/_variables.scss
$grid-breakpoints: (
    xs: 0,
    sm: 576px,
    md: 768px,
    lg: 992px,
    xl: 1200px
  ) !default;
*/

const breakpoints = {
    xs: 0,
    sm: 576,
    md: 768,
    lg: 992,
    xl: 1200,
}
const orderedKeys = ['xs', 'sm', 'md', 'lg', 'xl']

const getActiveBreakpoint = () => {
    let breakpoint = ''
    let classList = []

    orderedKeys.some((k, i) => {
        const n = orderedKeys[i + 1]
        let query = ''
        query += `(min-width: ${breakpoints[k]}px)`
        if (n) {
            query += `and (max-width: ${breakpoints[n] - 1}px)`
        }
        if (window.matchMedia(query).matches) {
            breakpoint = k
            classList = [...orderedKeys.slice(0, i).map(b => `gt-${b}`), k, ...orderedKeys.slice(i + 1, orderedKeys.length).map(b => `lt-${b}`)]
            return true
        }
        return false
    })
    return { breakpoint, classList, className: classList.join(' ') }
}


const calculate = () => {
  const result = getActiveBreakpoint()
  document.getElementById('result').innerHTML = `
       breakpoint: ${result.breakpoint}
       <br>
       className: ${result.className}
     `
}

window.addEventListener('resize', calculate)
calculate()
<div id="result"></div>
bentael
  • 1,987
  • 2
  • 21
  • 27
0

This already answered on stackoverflow from Terryfrancis is still useful in my Bootstrap 4 application, when I wanted to change the class of a non-bootstrap module into .col-md in my Bootstrap 4 application.

I used both onload and window resize function:

// on load
if ($(window).width() > 575 && $(window).width() < 992) {
   $('div').addClass('col-md-6').removeClass('col-md-4');
} else if ($(window).width() > 992) {
    $('div').addClass('col-md-4').removeClass('col-md-6');
}

// on user resizes browser window
 $( window ).resize(function() {
if ($(window).width() > 575 && $(window).width() < 992) {
   $('div').addClass('col-md-6').removeClass('col-md-4');
} else if (jQuery(window).width() > 992) {
    $('div').addClass('col-md-4').removeClass('col-md-6');
}
});