59
votes

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?

Thanks in advance

7
You might also want to use this tiny snippet, which displays the current device type directly at the top of your page.SunnyRed

7 Answers

160
votes

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;
        }
    }
}
42
votes

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 
    }
    
6
votes

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.

5
votes

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.

3
votes

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!

    })
});
0
votes

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.

-1
votes

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