【问题标题】:Twitter Bootstrap - how to detect when media queries startsTwitter Bootstrap - 如何检测媒体查询何时开始
【发布时间】:2013-12-09 11:30:25
【问题描述】:

当 bootstrap-responsive.css 媒体查询生效时,哪种方式是最快速、最简单的触发方式?

开始行动 = 当您将窗口大小调整为移动设备宽度并且网站更改为响应式移动设备时

希望问题清楚

【问题讨论】:

标签: javascript jquery css twitter-bootstrap media-queries


【解决方案1】:

改进出色的@falsarella 答案,这是一个适用于 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());

【讨论】:

  • 最简单,没有依赖关系,也不需要挂钩调整大小事件。干得好!
【解决方案2】:

Terryfrancis 中的 already answered on stackoverflow 在我的 Bootstrap 4 应用程序中仍然有用,当我想在我的 Bootstrap 4 应用程序中将非引导模块的类更改为 .col-md 时.

我同时使用了 onloadwindow resize 功能:

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

【讨论】:

    【解决方案3】:

    我会将window.matchMediawindow.addEventListener('resize') 一起使用。下面的示例,特别是函数getActiveBreakpoint() 将告诉您哪个断点处于活动状态,但还会告诉您哪些是lt-(小于)和gt-(大于)以帮助类的形式,即gt-xs gt-sm md lt-lg lt-xl,请参阅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()
    &lt;div id="result"&gt;&lt;/div&gt;

    【讨论】:

      【解决方案4】:

      这是我基于 @falsarella 想法的 bootstrap 4 解决方案

      *注意:使用下面的“整页”选项来测试这个sn-p,否则它会返回错误的屏幕类型,基于sn-p 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">

      【讨论】:

        【解决方案5】:

        我已经修改了this 链接中的代码,该链接指向 Bootsrap 4,而不是 alpha 或 beta。代码如下;

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

        【讨论】:

          【解决方案6】:

          我准备了一个超轻量级库来处理窗口宽度和引导断点更改时触发的事件 - 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
          });
          

          还包括其他功能,例如当前断点检查:

          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 和 Foundation 配置,更多信息请访问GitHub Repository

          【讨论】:

            【解决方案7】:

            此代码添加正文标记ldmdsdxd

                 $(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);
            
                });
            

            【讨论】:

              【解决方案8】:

              我用它只在大屏幕上的引导程序中将导航栏粘贴在https://ducttapedanyol.com

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

              【讨论】:

                【解决方案9】:

                更简单

                $(window).on('resize', function () {
                  if ($('<div class="visible-lg">').css('display')=='block') {
                    // Do something for lg
                  }
                  // ...
                });
                

                【讨论】:

                  【解决方案10】:

                  您可以使用matchMedia 和包装库enquire.js 注册媒体查询并在匹配/不匹配时发出事件。

                  用法

                  让我们以这些 Bootstrap CSS 媒体查询为例,取自 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) { ... }
                  

                  要查看何时应用这些规则,请使用enquire.js 注册媒体查询并提供适当的matchunmatch 函数,如下所示:

                  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 使用matchMedia 其中supports only the modern browsers,例如没有IE9。因此,旧版浏览器需要polyfill 才能完成这项工作。

                  Demo

                  【讨论】:

                    【解决方案11】:

                    我想出了一种使用窗口调整大小事件的方法,但依赖于 Twitter Bootstrap 的媒体查询,而不是硬编码它们的断点:

                    <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();
                    

                    【讨论】:

                    • Neat :) 我使用你的技巧将 Bootstrap 缩略图设置为相同的高度,请参阅 here
                    • @Jens 太棒了!很高兴它有帮助!
                    • 我喜欢这样可以避免重复引导配置——没有神奇的数字不同步!
                    • @farsarella 你的回答太棒了。干得好!
                    【解决方案12】:

                    基于@falsarella's solution,js部分可以简化为:

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

                    currMqIdx 是一个 int 值,从 0 到 3。currMqIdx 越大,媒体越宽。

                    【讨论】:

                      【解决方案13】:

                      Excellent Tip, @falsarella!

                      对于那些喜欢这种不影响他们实际标记的人来说,以下作品:

                      $(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.
                      

                      【讨论】:

                      • 喜欢这种做法。从现在开始,我将在我的项目中使用它。但我对:visible 有一些问题。有时,所有尺寸(xs、sm、md、lg)都只是false。我最终使用了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);}
                      • 应该不可能,但是 IIRC 3.x 的一些早期版本已经硬编码了一些响应断点,所以如果你改变了你的网格,你必须做一些搜索和替换才能得到所有的变化。也许@screen-zz-(max|min) 值会受到此影响。
                      • 在 3.0.0 上测试过,所以我猜可能是这样。
                      【解决方案14】:

                      其他答案的一个问题是每次调整大小都会触发更改事件。如果您的 javascript 正在做一些重要的事情,这可能会非常昂贵。

                      当超过阈值时,下面的代码只会调用一次更新函数。

                      要进行测试,请抓住窗口大小手柄,然后快速拖动调整大小以查看浏览器是否阻塞。

                      <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>
                      

                      【讨论】:

                      • 所以,只是为了澄清差异:您描述的关键点是仅在 (newWinSize != winSize) 时触发执行。
                      • 这是正确的。当超过阈值时,您的函数只会被调用一次。
                      • @Stickley:你在哪里定义 newWinSize?你不应该在var winSize下面有var newWinSize = '';
                      【解决方案15】:

                      这适用于我与 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>
                      

                      隐藏的 DIV 会根据实际使用的 CSS 最小宽度设置更改宽度。然后我的javascript简单检查DIV的当前。

                      【讨论】:

                      • OP 想知道调整后窗口的宽度。您的答案似乎根本不起作用。在我的 JS fiddle jsfiddle.net/softvar/bQsEV 中检查您的代码
                      • 代码工作正常:jsfiddle.net/JWTt5 ...我会让 OP 决定这是否是正确的答案。
                      • 页面总是提醒xs,即使调整窗口大小也没有其他提醒,也没有响应,即不能调整窗口大小。
                      • 那是因为它在一个框架中。您需要高屏幕分辨率才能让它说出xs 以外的任何内容,或者您​​需要将代码移出框架。要在调整大小时弹出它,只需将警报放入 $(window).resize(function() { /*PUT ALERT HERE*/ });
                      【解决方案16】:

                      使用 jquery 你可以找到当前窗口的大小,然后相应地做你的事情。

                      $(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) { ... }
                      

                      【讨论】:

                      • 这不起作用。在 Chrome 和其他可能的浏览器上,Jquery 为您提供 HTML 内容的宽度,而 CSS 中的 min-width 取决于浏览器窗口本身的宽度。
                      • @BjørnStenfeldt OP 想知道调整后窗口的宽度。您的答案似乎根本不起作用。在我的 JS fiddle jsfiddle.net/softvar/bQsEV 中检查您的代码
                      猜你喜欢
                      • 2013-08-27
                      • 2015-09-22
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2014-01-09
                      • 1970-01-01
                      • 1970-01-01
                      • 2016-09-26
                      相关资源
                      最近更新 更多