Como detectar pontos de interrupção responsivos do Twitter Bootstrap 3 usando JavaScript?

139

Atualmente , o Twitter Bootstrap 3 possui os seguintes pontos de interrupção responsivos: 768px, 992px e 1200px, representando dispositivos pequenos, médios e grandes, respectivamente.

Como posso detectar esses pontos de interrupção usando JavaScript?

Gostaria de ouvir com JavaScript todos os eventos relacionados acionados quando a tela muda. E para poder detectar se a tela é para dispositivos pequenos, médios ou grandes.

Existe algo já feito? Quais são as suas sugestões?

Rubens Mariuzzo
fonte
Você pode usar o IntersectionObserver para detectar quando uma <div class="d-none d-?-block"></div>alteração de visibilidade (insira o ponto de interrupção desejado). Essas classes CSS são para o Bootstrap 4 ... usam o que funciona no Bootstrap 3. Muito mais desempenho do que ouvir eventos de redimensionamento de janelas.
214188 Matt

Respostas:

241

Edit: Esta biblioteca está agora disponível através do Bower e NPM. Veja o repositório do github para obter detalhes.

RESPOSTA ATUALIZADA:

Disclaimer: Eu sou o autor.

Aqui estão algumas coisas que você pode fazer usando a versão mais recente (Responsive Bootstrap Toolkit 2.5.0):

// Wrap everything in an IIFE
(function($, viewport){

    // Executes only in XS breakpoint
    if( viewport.is('xs') ) {
        // ...
    }

    // Executes in SM, MD and LG breakpoints
    if( viewport.is('>=sm') ) {
        // ...
    }

    // Executes in XS and SM breakpoints
    if( viewport.is('<md') ) {
        // ...
    }

    // Execute only after document has fully loaded
    $(document).ready(function() {
        if( viewport.is('xs') ) {
            // ...
        }
    });

    // Execute code each time window size changes
    $(window).resize(
        viewport.changed(function() {
            if( viewport.is('xs') ) {
                // ...
            }
        })
    ); 

})(jQuery, ResponsiveBootstrapToolkit);

A partir da versão 2.3.0, você não precisa dos quatro <div>elementos mencionados abaixo.


RESPOSTA ORIGINAL:

Eu não acho que você precise de um script ou biblioteca enorme para isso. É uma tarefa bastante simples.

Insira os seguintes elementos imediatamente antes </body>:

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

Essas 4 divs permitem verificar o ponto de interrupção atualmente ativo. Para uma fácil detecção de JS, use a seguinte função:

function isBreakpoint( alias ) {
    return $('.device-' + alias).is(':visible');
}

Agora, para executar uma determinada ação apenas no menor ponto de interrupção que você poderia usar:

if( isBreakpoint('xs') ) {
    $('.someClass').css('property', 'value');
}

Detectar alterações após o DOM estar pronto também é bastante simples. Tudo que você precisa é de um ouvinte de redimensionamento de janelas leve como este:

var waitForFinalEvent = function () {
      var b = {};
      return function (c, d, a) {
        a || (a = "I am a banana!");
        b[a] && clearTimeout(b[a]);
        b[a] = setTimeout(c, d)
      }
    }();

var fullDateString = new Date();

Depois de equipado, você pode começar a ouvir alterações e executar funções específicas do ponto de interrupção, como:

$(window).resize(function () {
    waitForFinalEvent(function(){

        if( isBreakpoint('xs') ) {
            $('.someClass').css('property', 'value');
        }

    }, 300, fullDateString.getTime())
});
Maciej Gurban
fonte
3
Não funciona para mim. viewport.current () sempre gera 'não reconhecido'. Estou fazendo algo errado?
Starbugs
Você tem um violino? Edit: Pode ser que você inclua seus scripts, incluindo RBT na seção head, em vez de body? Isso impediria que os divs de visibilidade fossem adicionados ao corpo, interrompendo a funcionalidade.
Maciej Gurban
@MaciejGurban Eu não consigo fazê-lo funcionar também. Estou usando o Rails 4.2. Estou incluindo o bootstrap na minha cabeça, mas o seu script no corpo, mas ele continua dizendo não reconhecido. Ok, meu problema, eu adicionei tudo no corpo. Mas isso é realmente necessário?
30515 Dennis
Mais uma vez, é difícil dizer o problema sem um violino ou código de amostra. Você pode fazer uma pergunta sobre ele no SO e referenciá-lo aqui, ou abrir um problema no github. Você seguiu a ordem de incluir todas as partes como estão no CodePen ? Somente essa função não está funcionando? O problema poderia ser como este ?
Maciej Gurban
1
Como isso pode ser usado com o bootstrap 4?
Calonthar #
64

Se você não tiver necessidades específicas, basta fazer o seguinte:

if ($(window).width() < 768) {
    // do something for small screens
}
else if ($(window).width() >= 768 &&  $(window).width() <= 992) {
    // do something for medium screens
}
else if ($(window).width() > 992 &&  $(window).width() <= 1200) {
    // do something for big screens
}
else  {
    // do something for huge screens
}

Edit: Eu não vejo por que você deve usar outra biblioteca js quando você pode fazer isso apenas com o jQuery já incluído no seu projeto Bootstrap.

mtt
fonte
Obrigado, você também pode fornecer ao ouvinte todos os eventos que são acionados na alteração da dimensão da tela?
Rubens Mariuzzo 02/02
Não acho que haja eventos na mudança de dimensão da tela. Tudo relacionado à dimensão da tela (consultas de mídia) está na folha de estilo.
Mts2
2
Eu sei disso, só estou procurando um comportamento semelhante em JS. Na verdade, ouça a alteração da dimensão da tela com: $(window).bind('resize')... mas há outros eventos relacionados à orientação da tela do celular que afetam a dimensão da tela.
Rubens Mariuzzo 02/02
A orientação do dispositivo ainda é um recurso experimental: developer.mozilla.org/en-US/docs/Web/API/DeviceOrientationEvent Eu sugiro que você use.on('resize')
mtt
1
Já ouvi casos em que essa maneira de detectar estado causa problemas. É melhor usar algo que verifique se há elementos auxiliares visíveis - apenas para estar a salvo de qualquer caixa de canto.
Manuel Arwed Schmidt
11

Você já deu uma olhada no Response.js? Ele foi projetado para esse tipo de coisa. Combine Response.band e Response.resize.

http://responsejs.com/

Response.resize(function() {
    if ( Response.band(1200) )
    {
       // 1200+
    }    
    else if ( Response.band(992) )
    {
        // 992+
    }
    else if ( Response.band(768) )
    {
        // 768+
    }
    else 
    {
        // 0->768
    }
});
Mousius
fonte
Biblioteca interessante, embora não tenha sido projetada com o Twitter Bootstrap 3 em mente. Enfim, parece que ele pode ser facilmente adaptado ao TWBS3.
Rubens Mariuzzo 02/02
11

Você pode usar o tamanho da janela e codificar os pontos de interrupção. Usando Angular:

angular
    .module('components.responsiveDetection', [])
    .factory('ResponsiveDetection', function ($window) {
        return {
            getBreakpoint: function () {
                var w = $window.innerWidth;
                if (w < 768) {
                    return 'xs';
                } else if (w < 992) {
                    return 'sm';
                } else if (w < 1200) {
                    return 'md';
                } else {
                    return 'lg';
                }
            }
        };
    });
srlm
fonte
Eu gosto desta resposta. Nenhuma outra biblioteca (nem mesmo o jQuery) é necessária.
dprothero
11

Detectar o ponto de interrupção responsivo do Twitter Bootstrap 4.1.x usando JavaScript

O Bootstrap v.4.0.0 (e a versão mais recente do Bootstrap 4.1.x ) introduziu as opções de grade atualizadas ; portanto, o antigo conceito de detecção pode não ser aplicado diretamente (consulte as instruções de migração ):

  • Adicionado um novo smnível de grade abaixo 768pxpara um controle mais granular. Temos agora xs, sm, md, lg, e xl;
  • xs As classes de grade foram modificadas para não exigir o infixo.

Eu escrevi a função de utilitário pequeno que respeita os nomes de classes de grade atualizados e uma nova camada de grade:

/**
 * 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;
};

Detectar o ponto de interrupção responsivo do Bootstrap v4-beta usando JavaScript

O Bootstrap v4-alpha e o Bootstrap v4-beta tiveram uma abordagem diferente nos pontos de interrupção da grade, então aqui está a maneira herdada de obter o mesmo:

/**
 * 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;
}

Eu acho que seria útil, pois é fácil de integrar a qualquer projeto. Ele usa classes de exibição responsivas nativas do próprio Bootstrap.

Farside
fonte
7

Aqui minha própria solução simples:

jQuery:

function getBootstrapBreakpoint(){
    var w = $(document).innerWidth();
    return (w < 768) ? 'xs' : ((w < 992) ? 'sm' : ((w < 1200) ? 'md' : 'lg'));
}

VanillaJS:

function getBootstrapBreakpoint(){
    var w = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
    return (w < 768) ? 'xs' : ((w < 992) ? 'sm' : ((w < 1200) ? 'md' : 'lg'));
}
hckr
fonte
5

Usar essa abordagem com o Response.js é melhor. Os gatilhos Response.resize em cada janela são redimensionados, onde o cruzamento só será acionado se o ponto de interrupção for alterado

Response.create({
    prop : "width",
    breakpoints : [1200, 992, 768, 480, 320, 0]
});

Response.crossover('width', function() {
    if (Response.band(1200)) {
        // 1200+

    } else if (Response.band(992)) {
        // 992+

    } else if (Response.band(768)) {
        // 768+

    } else if (Response.band(480)) {
        //480+

    } else {
        // 0->320

    }
});

Response.ready(function() {
    $(window).trigger('resize');
});
berkayunal
fonte
4

Não deve haver problemas com alguma implementação manual como a mencionada por @oozic.

Aqui estão algumas bibliotecas que você pode dar uma olhada:

  • Response.js - plugin jQuery - use atributos de dados html e também possui uma API js.
  • enquire.js - enquire.js é uma biblioteca JavaScript leve e pura para responder a consultas de mídia CSS
  • SimpleStateManager - um gerenciador de estado javascript para sites responsivos. É construído para ser leve, não tem dependências.

Observe que essas bibliotecas foram projetadas para funcionar independentemente do bootstrap, da base etc. Você pode configurar seus próprios pontos de interrupção e se divertir.

Matias
fonte
3
O Enquire.js parece promissor.
Rubens Mariuzzo 02/02
4

Você pode adicionar isso ao seu projeto de inicialização para verificar visualmente o ponto de interrupção ativo

    <script type='text/javascript'>

        $(document).ready(function () {

            var mode;

            $('<div class="mode-informer label-info" style="z-index:1000;position: fixed;bottom:10px;left:10px">%mode%</div>').appendTo('body');


            var checkMode = function () {

                if ($(window).width() < 768) {
                    return 'xs';
                }
                else if ($(window).width() >= 768 && $(window).width() < 992) {
                    return 'sm';
                }
                else if ($(window).width() >= 992 && $(window).width() < 1200) {
                    return 'md';
                }
                else {
                    return 'lg';
                }
            };

            var compareMode = function () {
                if (mode !== checkMode()) {
                    mode = checkMode();

                    $('.mode-informer').text(mode).animate({
                        bottom: '100'
                    }, 100, function () {
                        $('.mode-informer').animate({bottom: 10}, 100)
                    });
                }
            };

            $(window).on('resize', function () {
                compareMode()
            });

            compareMode();

        });

    </script>

Aqui está o BOOTPLY

effe
fonte
4

Com base na resposta de Maciej Gurban (o que é fantástico ... se você gosta disso, basta votar na resposta dele). Se você estiver criando um serviço para consulta, poderá retornar o serviço ativo no momento com a configuração abaixo. Isso poderia substituir completamente outras bibliotecas de detecção de ponto de interrupção (como enquire.js, se você inserir alguns eventos). Observe que eu adicionei um contêiner com um ID aos elementos DOM para acelerar a travessia do DOM.

HTML

<div id="detect-breakpoints">
    <div class="breakpoint device-xs visible-xs"></div>
    <div class="breakpoint device-sm visible-sm"></div>
    <div class="breakpoint device-md visible-md"></div>
    <div class="breakpoint device-lg visible-lg"></div>
</div>

COFFEESCRIPT (AngularJS, mas isso é facilmente conversível)

# this simple service allows us to query for the currently active breakpoint of our responsive app
myModule = angular.module('module').factory 'BreakpointService', ($log) ->

  # alias could be: xs, sm, md, lg or any over breakpoint grid prefix from Bootstrap 3
  isBreakpoint: (alias) ->
    return $('#detect-breakpoints .device-' + alias).is(':visible')

  # returns xs, sm, md, or lg
  getBreakpoint: ->
    currentBreakpoint = undefined
    $visibleElement = $('#detect-breakpoints .breakpoint:visible')
    breakpointStringsArray = [['device-xs', 'xs'], ['device-sm', 'sm'], ['device-md', 'md'], ['device-lg', 'lg']]
    # note: _. is the lodash library
    _.each breakpointStringsArray, (breakpoint) ->
      if $visibleElement.hasClass(breakpoint[0])
        currentBreakpoint = breakpoint[1]
    return currentBreakpoint

JAVASCRIPT (AngularJS)

var myModule;

myModule = angular.module('modules').factory('BreakpointService', function($log) {
  return {
    isBreakpoint: function(alias) {
      return $('#detect-breakpoints .device-' + alias).is(':visible');
    },
    getBreakpoint: function() {
      var $visibleElement, breakpointStringsArray, currentBreakpoint;
      currentBreakpoint = void 0;
      $visibleElement = $('#detect-breakpoints .breakpoint:visible');
      breakpointStringsArray = [['device-xs', 'xs'], ['device-sm', 'sm'], ['device-md', 'md'], ['device-lg', 'lg']];
      _.each(breakpointStringsArray, function(breakpoint) {
        if ($visibleElement.hasClass(breakpoint[0])) {
          currentBreakpoint = breakpoint[1];
        }
      });
      return currentBreakpoint;
    }
  };
});
Pedra
fonte
3

Por que não usar o jQuery para detectar a largura atual do CSS da classe de contêiner de bootstrap?

ou seja ..

if( parseInt($('#container').css('width')) > 1200 ){
  // do something for desktop screens
}

Você também pode usar $ (window) .resize () para impedir que seu layout "suja a cama" se alguém redimensionar a janela do navegador.

Mark Williams
fonte
3

Em vez de inserir o abaixo muitas vezes em cada página ...

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

Basta usar o JavaScript para inseri-lo dinamicamente em todas as páginas (observe que eu o atualizei para trabalhar com o Bootstrap 3 com .visible-*-block:

// Make it easy to detect screen sizes
var bootstrapSizes = ["xs", "sm", "md", "lg"];
for (var i = 0; i < bootstrapSizes.length; i++) {
    $("<div />", {
        class: 'device-' + bootstrapSizes[i] + ' visible-' + bootstrapSizes[i] + '-block'
    }).appendTo("body");
}
Phillip Quinlan
fonte
2

Não tenho pontos de reputação suficientes para comentar, mas para aqueles que estão tendo problemas para serem "não reconhecidos" quando tentam usar o ResponsiveToolKit de Maciej Gurban, eu também estava recebendo esse erro até perceber que Maciej realmente faz referência ao kit de ferramentas na parte inferior do página em seu CodePen

Eu tentei fazer isso e de repente funcionou! Portanto, use o ResponsiveToolkit, mas coloque seus links na parte inferior da página:

Não sei por que faz a diferença, mas faz.

Michael Ackary
fonte
2

Aqui está outra maneira de detectar a viewport atual sem colocar os números de tamanho da viewport no seu javascript.

Consulte trechos de css e javascript aqui: https://gist.github.com/steveh80/288a9a8bd4c3de16d799

Após adicionar esses trechos aos arquivos css e javascript, você pode detectar a viewport atual como esta:

viewport.is('xs') // returns boolean

Se você deseja detectar um intervalo de viewport, use-o assim

viewport.isEqualOrGreaterThan('sm') // returns true for sm, md and lg
steveh80
fonte
2

O CSS do Bootstrap para a .containerclasse é assim:

.container {
    padding-right: 15px;
    padding-left: 15px;
    margin-right: auto;
    margin-left: auto;
}
@media (min-width: 768px) {
    .container {
        width: 750px;
    }
}
@media (min-width: 992px) {
    .container {
        width: 970px;
    }
}
@media (min-width: 1200px) {
    .container {
        width: 1170px;
    }
}

Portanto, isso significa que podemos confiar com segurança jQuery('.container').css('width')para detectar pontos de interrupção sem as desvantagens de confiar jQuery(window).width().

Podemos escrever uma função como esta:

function detectBreakpoint() {
    // Let's ensure we have at least 1 container in our pages.
    if (jQuery('.container').length == 0) {
        jQuery('body').append('<div class="container"></div>');
    }

    var cssWidth = jQuery('.container').css('width');

    if (cssWidth === '1170px') return 'lg';
    else if (cssWidth === '970px') return 'md';
    else if (cssWidth === '750px') return 'sm';

    return 'xs';
}

E então teste como

jQuery(document).ready(function() {
    jQuery(window).resize(function() {
        jQuery('p').html('current breakpoint is: ' + detectBreakpoint());
    });

    detectBreakpoint();
});
FlavioEscobar
fonte
Isso funcionará apenas nas larguras especificadas; qualquer coisa no meio falhará. Poderia ser melhor para: Primeiro, parseInt em cssWidth var cssWidth = parseInt( jQuery('.container').css('width') ); segundo, use faixas if ( cssWidth < 768) { return 'xs'; } else if (cssWidth >= 768 && cssWidth <= 992) { return 'sm'; } else if (cssWidth > 992 && cssWidth <= 1200) { return 'md'; } else { return 'lg'; }
Kakoma
2

Use CSS :beforee contentpropriedade para imprimir o estado do ponto de interrupção no <span id="breakpoint-js">modo que o JavaScript apenas precise ler esses dados para transformá-lo em uma variável a ser usada em sua função.

(execute o trecho para ver o exemplo)

NOTA: Adicionei algumas linhas de CSS para usar o <span>sinalizador vermelho no canto superior do meu navegador. Apenas certifique-se de mudar de volta display:none;antes de publicar seu material publicamente.

// initialize it with jquery when DOM is ready
$(document).on('ready', function() {
    getBootstrapBreakpoint();
});

// get bootstrap grid breakpoints
var theBreakpoint = 'xs'; // bootstrap336 default = mobile first
function getBootstrapBreakpoint(){
   theBreakpoint = window.getComputedStyle(document.querySelector('#breakpoint-js'),':before').getPropertyValue('content').replace(/['"]+/g, '');
   console.log('bootstrap grid breakpoint = ' + theBreakpoint);
}
#breakpoint-js {
  /* display: none; //comment this while developping. Switch back to display:NONE before commit */
  /* optional red flag layout */
  position: fixed;
  z-index: 999;
  top: 0;
  left: 0;
  color: white;
  padding: 5px 10px;
  background-color: red;
  opacity: .7;
  /* end of optional red flag layout */
}
#breakpoint-js:before {
  content: 'xs'; /* default = mobile first */
}
@media screen and (min-width: 768px) {
  #breakpoint-js:before {
    content: 'sm';
  }
}
@media screen and (min-width: 992px) {
  #breakpoint-js:before {
    content: 'md';
  }
}
@media screen and (min-width: 1200px) {
  #breakpoint-js:before {
    content: 'lg';
  }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">

<div class="container">
  <span id="breakpoint-js"></span>
  <div class="page-header">
    <h1>Bootstrap grid examples</h1>
    <p class="lead">Basic grid layouts to get you familiar with building within the Bootstrap grid system.</p>
  </div>
</div>

MartinDubeNet
fonte
1

Eu criei um método jQuery nativo para detecção de tamanho de tela do Twitter Bootstrap. Aqui está:

// Screen size ID will be stored in this variable (global var for JS)
var CurrentBootstrapScreenSize = 'unknown';

$(document).ready(function () {

    // <div> objects for all screen sizes required for screen size detection.
    // These <div> is hidden for users eyes.
    var currentScreenSizeDetectorObjects = $('<div>').css({
            'position':'absolute',
            'top':'-200px'
        }).addClass('current-screen-size').append([
            $('<div>').addClass('device-xs visible-xs').html('&nbsp;'),
            $('<div>').addClass('device-sm visible-sm').html('&nbsp;'),
            $('<div>').addClass('device-md visible-md').html('&nbsp;'),
            $('<div>').addClass('device-lg visible-lg').html('&nbsp;')
        ]);

    // Attach <div> objects to <body>
    $('body').prepend(currentScreenSizeDetectorObjects);

    // Core method for detector
    function currentScreenSizeDetectorMethod() {
        $(currentScreenSizeDetectorObjects).find('div').each(function() {
            var className = $(this).attr('class');
            if($(this).is(':visible')) {
                if(String(className).match(/device-xs/)) CurrentBootstrapScreenSize = 'xs';
                else if(String(className).match(/device-sm/)) CurrentBootstrapScreenSize = 'sm';
                else if(String(className).match(/device-md/)) CurrentBootstrapScreenSize = 'md';
                else if(String(className).match(/device-lg/)) CurrentBootstrapScreenSize = 'lg';
                else CurrentBootstrapScreenSize = 'unknown';
            };
        })
        console.log('Current Bootstrap screen size is: '+CurrentBootstrapScreenSize);
        $('.CurrentBootstrapScreenSize').first().html('Bootstrap current screen size: <b>' + CurrentBootstrapScreenSize + '</b>' );
    }

    // Bind screen size and orientation change
    $(window).bind("resize orientationchange", function() {
        // Execute screen detection
        currentScreenSizeDetectorMethod();
    });

    // Execute screen detection on page initialize
    currentScreenSizeDetectorMethod();

});

JSFillde: https://jsfiddle.net/pstepniewski/7dz6ubus/

JSFillde como exemplo de tela cheia: https://jsfiddle.net/pstepniewski/7dz6ubus/embedded/result/

Piotr Stępniewski
fonte
1

Para qualquer pessoa interessada nisso, escrevi uma detecção de ponto de interrupção baseada em pontos de interrupção CSS usando TypeScript e Observables. não é muito difícil criar o ES6, se você remover os tipos. No meu exemplo, eu uso o Sass, mas também é fácil remover isso.

Aqui está o meu JSFiddle: https://jsfiddle.net/StefanJelner/dorj184g/

HTML:

<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.7/Rx.min.js"></script>
<div id="result"></div>

SCSS:

body::before {
  content: 'xs';
  display: none;

  @media screen and (min-width: 480px) {
    content: 's';
  }

  @media screen and (min-width: 768px) {
    content: 'm';
  }

  @media screen and (min-width: 1024px) {
    content: 'l';
  }

  @media screen and (min-width: 1280px) {
    content: 'xl';
  }
}

TypeScript:

import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Observable } from 'rxjs/Observable';

class BreakpointChangeService {
    private breakpointChange$: BehaviorSubject<string>;

    constructor(): BehaviorSubject<string> {
        // initialize BehaviorSubject with the current content of the ::before pseudo element
        this.breakpointChange$ = new Rx.BehaviorSubject(this.getBreakpoint());

        // observe the window resize event, throttle it and combine it with the BehaviorSubject
        Rx.Observable
            .fromEvent(window, 'resize')
            .throttleTime(0, Rx.Scheduler.animationFrame)
            .withLatestFrom(this.breakpointChange$)
            .subscribe(this.update.bind(this))
        ;

        return this.breakpointChange$;
    }

    // method to get the content of the ::before pseudo element
    private getBreakpoint(): string {
        // see https://www.lullabot.com/articles/importing-css-breakpoints-into-javascript
        return window.getComputedStyle(document.body, ':before').getPropertyValue('content').replace(/[\"\']/g, '');
    }

    private update(_, recent): void {
        var current = this.getBreakpoint();
        if(recent !== current) { this.breakpointChange$.next(current); }
    }
}

// if the breakpoint changes, react on it
var $result = document.getElementById('result');
new BreakpointChangeService().subscribe(breakpoint => {
    $result.innerHTML = Date.now()+': '+breakpoint;
});

Espero que isso ajude alguém.

Stefan Jelner
fonte
1

Bootstrap4 com jQuery, solução simplificada

<div class="device-sm d-sm-none"></div>
<div class="device-md d-md-none"></div>
<div class="device-lg d-lg-none"></div>
<div class="device-xl d-xl-none"></div>
<script>
var size = $('.device-xl').is(':hidden') ? 'xl' : ($('.device-lg').is(':hidden') ? 'lg'
    : ($('.device-md').is(':hidden') ? 'md': ($('.device-sm').is(':hidden') ? 'sm' : 'xs')));
alert(size);
</script>
Alex R
fonte
1

Eu não estava realmente satisfeito com as respostas dadas, que parecem muito complicadas de usar, então escrevi minha própria solução. No entanto, por enquanto, isso depende de sublinhado / lodash para funcionar.

https://github.com/LeShrimp/GridSizeEvents

Você pode usá-lo assim:

GridSizeEvents.addListener(function (newSize, oldSize) {
    // Will output eg. "xs -> sm"
    console.log(oldSize + ' -> ' + newSize);
});

Isso funciona como padrão para o Bootstrap 3, pois os pontos de interrupção são codificados para 768px, 992px e 1200px. Para outras versões, você pode facilmente adaptar o código.

Internamente, isso usa matchMedia () e, portanto, garante a produção de resultados sincronizados com o Bootstrap.

MaximeW
fonte
1

Talvez isso ajude alguns de vocês, mas existe um plug-in que ajuda a detectar em qual ponto de interrupção atual do Bootstrap v4 você vê: https://www.npmjs.com/package/bs-breakpoints

Simples de usar (pode ser usado com ou sem jQuery):

$(document).ready(function() {
  bsBreakpoints.init()
  console.warn(bsBreakpoint.getCurrentBreakpoint())

  $(window).on('new.bs.breakpoint', function (event) {
    console.warn(event.breakpoint)
  })
})
Johann-S
fonte
1

Aqui está a minha solução (Bootstrap 4):

<div class="alert alert-warning row">
    <div class="col">
        Bootstrap breakpoint is
    </div>
    <div class="col">
        <div class="d-block d-sm-none">
            XS
        </div>
        <div class="d-none d-sm-block d-md-none">
            SM
        </div>
        <div class="d-none d-md-block d-lg-none">
            MD
        </div>
        <div class="d-none d-lg-block d-xl-none">
            MD
        </div>
        <div class="d-none d-xl-block">
            MD
        </div>
    </div>
</div>
Antonio Petricca
fonte
0

Para quem usa o knockout.js , eu queria algumas propriedades observáveis ​​do knockout.js que me informassem quando os pontos de interrupção fossem atingidos. Optei por usar o suporte do Modernizr para consultas de mídia no estilo css, para que os números correspondessem às definições de autoinicialização e para obter os benefícios de compatibilidade do modernizr. Meu modelo de exibição knockout é o seguinte:

var viewModel = function() {
    // depends on jquery, Modernizr
    var self = this;
    self.widthXsOrLess = ko.observable();
    self.widthSmOrLess = ko.observable();
    self.widthMdOrLess = ko.observable();
    var setWindowSizeVars = function() {
        self.widthXsOrLess(!Modernizr.mq('(min-width: 768px)'));
        self.widthSmOrLess(!Modernizr.mq('(min-width: 992px)'));
        self.widthMdOrLess(!Modernizr.mq('(min-width: 1200px)'));
    };
    $(window).resize(setWindowSizeVars);
    setWindowSizeVars();
};
rogersillito
fonte
0

Aqui está uma boa maneira de detectá-lo (talvez engraçado, mas funciona) e Você pode usar o elemento necessário para que o código fique claro:

Exemplo: css:

@media (max-width: 768px) {
    #someElement
    {
         background: pink
    }
}

e no documento por jQuery:

if($('#someElement').css('background') == 'pink')
{
    doWhatYouNeed();
}

é claro que a propriedade css é qualquer.

Świeżu
fonte
0

Como o bootstrap 4 será lançado em breve, pensei em compartilhar uma função que o suporte (xl agora é uma coisa) e executa jQuery mínimo para concluir o trabalho.

/**
 * Get the Bootstrap device size
 * @returns {string|boolean} xs|sm|md|lg|xl on success, otherwise false if Bootstrap is not working or installed
 */
function findBootstrapEnvironment() {
    var environments = ['xs', 'sm', 'md', 'lg', 'xl'];
    var $el = $('<span />');
    $el.appendTo($('body'));
    for (var i = environments.length - 1; i >= 0; i--) {
        var env = environments[i];
        $el.addClass('hidden-'+env);
        if ($el.is(':hidden')) {
            $el.remove();
            return env;
        }
    }
    $el.remove();
    return false;
}
carcus88
fonte
0

Bootstrap 4

setResponsiveDivs();

function setResponsiveDivs() {
    var data = [
        {id: 'visible-xs', class: 'd-block d-sm-none'},
        {id: 'visible-sm', class: 'd-none d-sm-block d-md-none'},
        {id: 'visible-md', class: 'd-none d-md-block d-lg-none'},
        {id: 'visible-lg', class: 'd-none d-lg-block d-xl-none'},
        {id: 'visible-xl', class: 'd-none d-xl-block'}
    ];

    for (var i = 0; i < data.length; i++) {
        var el = document.createElement("div");
        el.setAttribute('id', data[i].id);
        el.setAttribute('class', data[i].class);
        document.getElementsByTagName('body')[0].appendChild(el);
    }
}

function isVisible(type) {
    return window.getComputedStyle(document.getElementById('visible-' + type), null).getPropertyValue('display') === 'block';
}

// then, at some point
window.onresize = function() {
    console.log(isVisible('xs') === true ? 'xs' : '');
    console.log(isVisible('sm') === true ? 'sm' : '');
    console.log(isVisible('md') === true ? 'md' : '');
    console.log(isVisible('lg') === true ? 'lg' : '');
    console.log(isVisible('xl') === true ? 'xl' : '');
};

ou minificado

function setResponsiveDivs(){for(var e=[{id:"visible-xs","class":"d-block d-sm-none"},{id:"visible-sm","class":"d-none d-sm-block d-md-none"},{id:"visible-md","class":"d-none d-md-block d-lg-none"},{id:"visible-lg","class":"d-none d-lg-block d-xl-none"},{id:"visible-xl","class":"d-none d-xl-block"}],s=0;s<e.length;s++){var l=document.createElement("div");l.setAttribute("id",e[s].id),l.setAttribute("class",e[s]["class"]),document.getElementsByTagName("body")[0].appendChild(l)}}function isVisible(e){return"block"===window.getComputedStyle(document.getElementById("visible-"+e),null).getPropertyValue("display")}setResponsiveDivs();

Patrioticcow
fonte
0

Se você usar Knockout , poderá usar a seguinte ligação personalizada para vincular o ponto de interrupção da viewport atual (xs, sm, md ou lg) a um observável em seu modelo. A ligação...

  • agrupa os 4 divscom visible-??classe em uma div com id detect-viewporte a adiciona ao corpo se ela ainda não existir (para que você possa reutilizar essa ligação sem duplicar essas divs)
  • define o ponto de interrupção da viewport atual para o limite observável consultando qual das divs está visível
  • atualiza o ponto de interrupção da viewport atual quando a janela é redimensionada

ko.bindingHandlers['viewport'] = {
    init: function(element, valueAccessor) {
        if (!document.getElementById('detect-viewport')) {
            let detectViewportWrapper = document.createElement('div');
            detectViewportWrapper.id = 'detect-viewport';
            
            ["xs", "sm", "md", "lg"].forEach(function(breakpoint) {
                let breakpointDiv = document.createElement('div');
                breakpointDiv.className = 'visible-' + breakpoint;
                detectViewportWrapper.appendChild(breakpointDiv);
            });

            document.body.appendChild(detectViewportWrapper);
        }

        let setCurrentBreakpoint = function() {
            valueAccessor()($('#detect-viewport div:visible')[0].className.substring('visible-'.length));
        }
      
        $(window).resize(setCurrentBreakpoint);
        setCurrentBreakpoint();
    }
};

ko.applyBindings({
  currentViewPort: ko.observable()
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>

<div data-bind="viewport: currentViewPort"></div>
<div>    
    Current viewport breakpoint: <strong data-bind="text: currentViewPort"></strong>
</div>
<div>
    (Click the <em>full page</em> link of this snippet to test the binding with different window sizes)
</div>

Philip Bijker
fonte
0

Já faz um tempo desde o OP, mas aqui está a minha solução para isso usando o Bootstrap 3. No meu caso de uso, eu estava apenas segmentando linhas, mas o mesmo poderia ser aplicado ao contêiner etc.

Apenas mude .row para o que quiser.

jQuery(document).ready(function ($) {

    var alterClass = function () {

        var ww = document.body.clientWidth;

        if (ww < 768) {

            $('.row').addClass('is-xs').removeClass('is-sm').removeClass('is-lg').removeClass('is-md');

        } else if (ww >= 768 && ww < 992) {

            $('.row').addClass('is-sm').removeClass('is-xs').removeClass('is-lg').removeClass('is-md');

        } else if (ww >= 992 && ww < 1200) {

            $('.row').addClass('is-md').removeClass('is-xs').removeClass('is-lg').removeClass('is-sm');

        } else if (ww >= 1200) {

            $('.row').addClass('is-lg').removeClass('is-md').removeClass('is-sm').removeClass('is-xs');

        };
    };

    // Make Changes when the window is resized
    $(window).resize(function () {
        alterClass();
    });

    // Fire when the page first loads
    alterClass();
});
Jason
fonte