61

I have just started to play around with Twitter Bootstrap API for a project I have coming up. The main nav contains 3 main elements:

  • site nav
  • social links nav
  • search the site form

I am using the collapse plugin to collapse the site nav and search form when viewing the site on mobile devices. The mobile view has 2 buttons which when clicked toggle the search form or main nav on/off.

However if I toggle off the search form and then resize my browser to desktop view the search form is still hidden in this view?

I have read about using classes such as visible-mobile etc but these seem to clash with the collapse plugin. I also realise I could probably write my own CSS hacks to fix this but thought I'd ask if there was an easier solution.

Bootstrap has events for show, shown, hide and hidden so I thought maybe I could write some custom JS which would show or hide these items in each particular device view. However I didn't know how to detect which device I'm using at the time.

Thoughts?

starball
  • 20,030
  • 7
  • 43
  • 238
James Howell
  • 1,392
  • 5
  • 24
  • 42
  • You might also want to use this tiny [snippet](http://stackoverflow.com/questions/25783702/bootstrap-3-how-to-determine-which-grid-option-is-currently-used/26758749#26758749), which displays the current device type directly at the top of your page. – SunnyRed Nov 05 '14 at 14:29

7 Answers7

162

If you want to know what environment you're on, try using Bootstrap's own CSS classes. Create an element, add it to the page, apply its helper classes and check if it's hidden to determine if that's the current environment. The following function does just that:

Bootstrap 4

function findBootstrapEnvironment() {
    let envs = ['xs', 'sm', 'md', 'lg', 'xl'];

    let el = document.createElement('div');
    document.body.appendChild(el);

    let curEnv = envs.shift();

    for (let env of envs.reverse()) {
        el.classList.add(`d-${env}-none`);

        if (window.getComputedStyle(el).display === 'none') {
            curEnv = env;
            break;
        }
    }

    document.body.removeChild(el);
    return curEnv;
}

Bootstrap 3

function findBootstrapEnvironment() {
    var envs = ['xs', 'sm', 'md', 'lg'];

    var $el = $('<div>');
    $el.appendTo($('body'));

    for (var i = envs.length - 1; i >= 0; i--) {
        var env = envs[i];

        $el.addClass('hidden-'+env);
        if ($el.is(':hidden')) {
            $el.remove();
            return env;
        }
    }
}

Bootstrap 2

function findBootstrapEnvironment() {
    var envs = ['phone', 'tablet', 'desktop'];

    var $el = $('<div>');
    $el.appendTo($('body'));

    for (var i = envs.length - 1; i >= 0; i--) {
        var env = envs[i];

        $el.addClass('hidden-'+env);
        if ($el.is(':hidden')) {
            $el.remove();
            return env;
        }
    }
}
rmobis
  • 26,129
  • 8
  • 64
  • 65
  • Is there any Javascript API to get this detail apart from checking the markup dynamically? – Easwaramoorthy Kanagaraj Nov 07 '13 at 07:25
  • Seems to be not working, always returning undefined, as per Bootstrap 3.0, use this array: `["xs", "sm", "md", "lg"]` – Fabiano Soriani Nov 08 '13 at 20:21
  • 2
    @EaswaramoorthyKanagaraj, I believe the best, when considering CSS equivalency, would be [`window.matchMedia`](http://devdocs.io/dom/window.matchmedia), but it's not widely supported yet. – rmobis Nov 08 '13 at 20:27
  • @Raphael_ Ok. I too have Googled but didnt find anything specifically in bootstrap. – Easwaramoorthy Kanagaraj Nov 11 '13 at 11:01
  • this just seems to return true at all times? – v3nt Apr 04 '14 at 15:29
  • @danielCrabbe, it actually never returns true, mainly because it doesn't return booleans, but strings. – rmobis Apr 04 '14 at 15:33
  • I have made a small, little, but usefull extra for jQuery . Check it out on gitbub - https://github.com/Parcye/bootstrap_view $.bootstrap_view().activeClass to get the active class or $.bootstrap_view().queryClass() to query the view and get the current class. – Parcye Apr 18 '14 at 13:23
  • My HTML code contains four divs with the respective css classes applied. In JavaScript it is a one-liner: `$('#xs, #sm, #md, #lg').filter(':not(:hidden)').attr('id')` to get the currently active viewport! – Davincho Apr 01 '15 at 12:58
  • 2
    @Davincho That requires you to manually include specific markup on **every** page you want to use that and it surely doesn't look like a good trade-off. – rmobis Apr 01 '15 at 13:44
  • wouldn't it be easier to use the value of `$("body").width()` (or `window.document.body.clientWidth`) ? If less than 768, then it is **xs**, if <992: **sm**, if <1200 **md**, and else **lg** ? – vandenn3 Aug 20 '16 at 20:10
  • 1
    @vandenn3 it would be easier, just not as accurate. Both `$('body').width()` and `window.document.body.clientWidth` don't take the scrollbar width in consideration while the media query does. You could argue that the fix is as simple as adding the scrollbar width but different browsers on different OSes have different scrollbar widths. Also, this way you don't have to rely on your the default breakpoints and it will work even if you've change them. – rmobis Aug 21 '16 at 21:09
  • Well i think this is the best approach as bootstrap 4 platform itself uses the classes to determine environment size ,As other solutions(around stack overflow) Thanks mate – MR_AMDEV Jan 27 '19 at 18:13
43

Building on @Raphael_ and @user568109 's answers, in Bootstrap 3, Responsive is now built in.

To detect device type in Javascript, create an object that is only displayed on your required device using Bootstrap's Responsive classes. Then check its :hidden property.

Example:

  1. Create a <div> panel with no content that would be shown on anything bigger that an eXtra Small device (thanks to @Mario Awad) :

    <div id="desktopTest" class="hidden-xs"></div>
    

    or, to exclude specific devices:

    <div id="desktopTest" class="visible-sm visible-md visible-lg"></div>
    
  2. Check value of #desktopTest:

    if ($('#desktopTest').is(':hidden')) {
        // device is == eXtra Small
    } else {
        // device is >= SMaller 
    }
    
bwegs
  • 3,769
  • 2
  • 30
  • 33
Alastair McCormack
  • 26,573
  • 8
  • 77
  • 100
6

Original answer:
Based on @Alastair McCormack answer, I suggest you to use this code

<div class="visible-xs hidden-sm hidden-md hidden-lg">xs</div>
<div class="hidden-xs visible-sm hidden-md hidden-lg">sm</div>
<div class="hidden-xs hidden-sm visible-md hidden-lg">md</div>
<div class="hidden-xs hidden-sm hidden-md visible-lg">lg</div>

Just add it in the end of your container div, you will get a simple dynamic information about current view.

Update (2019-03-03):
Previous code is not compatible with Bootstrap 4, since all hidden-* and visible-* classes have been removed. Here you have the new code you can use, compatible with both Bootstrap 3 and Bootstrap 4 versions (some credits goes to this SO answer):

<div class="visible-xs hidden-sm hidden-md hidden-lg hidden-xl d-block d-sm-none">xs</div>
<div class="hidden-xs visible-sm hidden-md hidden-lg hidden-xl d-none d-sm-block d-md-none">sm</div>
<div class="hidden-xs hidden-sm visible-md hidden-lg hidden-xl d-none d-md-block d-lg-none">md</div>
<div class="hidden-xs hidden-sm hidden-md visible-lg hidden-xl d-none d-lg-block d-xl-none">lg</div>
<div class="hidden-xs hidden-sm hidden-md hidden-lg visible-xl d-none d-xl-block">xl</div>

You can test it with this fiddle.

Please note that I included hidden-xl and visible-xl too, but I believe they are not really used by any Bootstrap version.

Kar.ma
  • 743
  • 6
  • 12
  • Super simple. I like this. – stealthysnacks Mar 16 '17 at 04:29
  • Yes, that's the idea. The OP asked "how to detect which device I'm using at the time", and I believe this is a quick and effective solution. I always use this, and comment it out (or wrap it in a hidden div) when I need to debug my code. – Kar.ma Mar 17 '17 at 08:25
  • You are right: original visible and hidden classes have been removed in Boostrap 4. I updated the answer. – Kar.ma Mar 03 '19 at 10:56
6

I originally posted answer here, the solution for Bootstrap v.4.x.

JS breakpoint detection for Twitter Bootstrap 4.1.x

The Bootstrap v.4.0.0 (and the latest version Bootstrap 4.1.x) introduced the updated grid options, so the old concept on detection may not directly be applied (see the migration instructions):

  • Added a new sm grid tier below 768px for more granular control. We now have xs, sm, md, lg, and xl;
  • xs grid classes have been modified to not require the infix.

I written the small utility function that respects an updated grid class names and a new grid tier:

/**
 * Detect the current active responsive breakpoint in Bootstrap
 * @returns {string}
 * @author farside {@link https://stackoverflow.com/users/4354249/farside}
 */
function getResponsiveBreakpoint() {
    var envs = {xs:"d-none", sm:"d-sm-none", md:"d-md-none", lg:"d-lg-none", xl:"d-xl-none"};
    var env = "";

    var $el = $("<div>");
    $el.appendTo($("body"));

    for (var i = Object.keys(envs).length - 1; i >= 0; i--) {
        env = Object.keys(envs)[i];
        $el.addClass(envs[env]);
        if ($el.is(":hidden")) {
            break; // env detected
        }
    }
    $el.remove();
    return env;
};

JS breakpoint detection for Bootstrap v4-beta

The latest Bootstrap v4-alpha and Bootstrap v4-beta had different approach on grid breakpoints, so here's the legacy way of achieving the same:

/**
 * Detect and return the current active responsive breakpoint in Bootstrap
 * @returns {string}
 * @author farside {@link https://stackoverflow.com/users/4354249/farside}
 */
function getResponsiveBreakpoint() {
    var envs = ["xs", "sm", "md", "lg"];
    var env = "";

    var $el = $("<div>");
    $el.appendTo($("body"));

    for (var i = envs.length - 1; i >= 0; i--) {
        env = envs[i];
        $el.addClass("d-" + env + "-none");;
        if ($el.is(":hidden")) {
            break; // env detected
        }
    }
    $el.remove();
    return env;
}

I think it would be useful, as it's easy to integrate to any project. It uses native responsive display classes of the Bootstrap itself.

Farside
  • 9,923
  • 4
  • 47
  • 60
  • 1
    Bootstrap 4 beta has changed the classes - they use d-\*-none instead of hidden-\*-up. Here's a version that works for Bootstrap 4 beta - https://gist.github.com/gurubobnz/115d6fb64eb59c6f057a09fd53c721c0 – GuruBob Nov 23 '17 at 22:00
  • 1
    thanks, @GuruBob, I updated the answer! the answer originally was created when just 4-alpha was in place ;) – Farside Nov 23 '17 at 22:48
  • absolutely wonderful. Excellent implementation. Thank you from YouDoer.com :) – Andy Dec 28 '18 at 00:40
3

My answer is using similar mechanism like the one presented by @Raphael_ however, you can do a little bit more with it. Please refer to this answer for details and project's github repository for the most updated version.

Example of breakpoint detection:

if ( viewport.is('xs') ) {
  // do stuff in the lowest resolution
}

Executing code on window resize (without it happening multiple times within a span of milliseconds):

$(window).bind('resize', function() {
    viewport.changed(function() {

      // do some other stuff!

    })
});
Community
  • 1
  • 1
Maciej Gurban
  • 5,615
  • 4
  • 40
  • 55
0

Niche case, but you can apply @Kar.ma's to a Mediawiki with Chameleon (bootstrap skin) installed. Pass the "results" of the DIV as a template argument, then test against that within the template.

Skonesam
  • 3
  • 1
-1

Combining the answers from above, this one works for me:

function findBootstrapDeviceSize() {
  var dsize = ['lg', 'md', 'sm', 'xs'];
  for (var i = dsize.length - 1; i >= 0; i--) {

    // Need to add &nbsp; for Chrome. Works fine in Firefox/Safari/Opera without it.
    // Chrome seem to have an issue with empty div's
    $el = $('<div id="sizeTest" class="hidden-'+dsize[i]+'">&nbsp;</div>');
    $el.appendTo($('body'));

    if ($el.is(':hidden')) {
      $el.remove();
      return dsize[i];
    }
  }

  return 'unknown';
}