使用JavaScript检测动态媒体查询?

Tim*_*mah 4 javascript css media-queries responsive

我一直在寻找一种轻量,灵活,跨浏览器的解决方案,以在JavaScript中访问CSS媒体查询,而不会在JavaScript代码中重复CSS断点。

CSS技巧发布了一个基于CSS3动画的解决方案,该解决方案似乎很有帮助,但是建议改用Enquire.js。

Enquire.js似乎仍然需要在脚本中对Media Query大小进行硬编码,例如

enquire.register("screen and (max-width:45em)", { // do stuff }
Run Code Online (Sandbox Code Playgroud)

问题

到目前为止,所有用于访问Java媒体查询的解决方案似乎都依赖于在脚本中硬编码的断点。如何以允许仅在CSS中定义断点而不依赖的方式访问断点.on('resize')?

尝试的解决方案

我已经制作了自己的版本,可以在IE9 +中使用,使用了一个隐藏元素,该元素使用该:content属性添加查询触发时想要的任何内容(与ZeroSixThree解决方案相同的起点):

的HTML

<body>
    <p>Page content</p>
    <span id="mobile-test"></span>
</body>
Run Code Online (Sandbox Code Playgroud)

的CSS

#mobile-test {
    display:none;
    content: 'mq-small';
}
@media screen only and (min-width: 25em) {
    #mobile-test {
        content: 'mq-medium';
    }
}
@media screen only and (min-width: 40em) {
    #mobile-test {
        content: 'mq-large';
    }
}
Run Code Online (Sandbox Code Playgroud)

使用jQuery的JavaScript

// Allow resizing to be assessed only after a delay, to avoid constant firing on resize. 
var resize;
window.onresize = function() {
    clearTimeout(resize);
    // Call 'onResize' function after a set delay
    resize = setTimeout(detectMediaQuery, 100);
};

// Collect the value of the 'content' property as a string, stripping the quotation marks
function detectMediaQuery() {
    return $('#mobile-test').css('content').replace(/"/g, '');
}

// Finally, use the function to detect the current media query, irrespective of it's breakpoint value
$(window).on('resize load', function() {
    if (detectMediaQuery() === 'mq-small') {
        // Do stuff for small screens etc
    }
});
Run Code Online (Sandbox Code Playgroud)

这样,Media Query的断点完全由CSS处理。如果您更改断点,则无需更新脚本。如何才能做到这一点?

Tai*_*sco 5

尝试这个

const mq = window.matchMedia( "(min-width: 500px)" );
Run Code Online (Sandbox Code Playgroud)

matchs属性根据查询结果返回true或false,例如

if (mq.matches) {

  // window width is at least 500px
} else {
  // window width is less than 500px
}
Run Code Online (Sandbox Code Playgroud)

您还可以添加事件侦听器,该侦听器在检测到更改时将触发:

// media query event handler
if (matchMedia) {
  const mq = window.matchMedia("(min-width: 500px)");
  mq.addListener(WidthChange);
  WidthChange(mq);
}

// media query change
function WidthChange(mq) {
  if (mq.matches) {
    // window width is at least 500px
  } else {
    // window width is less than 500px
  }

}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢@Taioli,但这仍然涉及将断点值硬编码到 JavaScript 中。我试图找出如何实现这个结果*没有*硬编码断点值 (2认同)
  • 多年后,我仍然不明白为什么当它错过了问题的要点时,它会被投票——而不是在 JavaScript 中硬编码断点值。 (2认同)

ita*_*ode 4

请参阅专家 David Walsh 发表的这篇文章,使用 CSS 媒体查询和 JavaScript 进行设备状态检测:

CSS

.state-indicator {
    position: absolute;
    top: -999em;
    left: -999em;
}
.state-indicator:before { content: 'desktop'; }

/* small desktop */
@media all and (max-width: 1200px) {
    .state-indicator:before { content: 'small-desktop'; }
}

/* tablet */
@media all and (max-width: 1024px) {
    .state-indicator:before { content: 'tablet'; }
}

/* mobile phone */
@media all and (max-width: 768px) {
    .state-indicator:before { content: 'mobile'; }
}
Run Code Online (Sandbox Code Playgroud)

JS

var state = window.getComputedStyle(
    document.querySelector('.state-indicator'), ':before'
).getPropertyValue('content')
Run Code Online (Sandbox Code Playgroud)

另外,这是 javascript 大师 Nicholas C. Zakas 提出的一个聪明的解决方案:

  // Test a media query.
  // Example: if (isMedia("screen and (max-width:800px)"){}
  // Copyright 2011 Nicholas C. Zakas. All rights reserved.
  // Licensed under BSD License.
  var isMedia = (function () {

    var div;

    return function (query) {

      //if the <div> doesn't exist, create it and make sure it's hidden
      if (!div) {
        div = document.createElement("div");
        div.id = "ncz1";
        div.style.cssText = "position:absolute;top:-1000px";
        document.body.insertBefore(div, document.body.firstChild);
      }

      div.innerHTML = "_<style media=\"" + query + "\"> #ncz1 { width: 1px; }</style>";
      div.removeChild(div.firstChild);
      return div.offsetWidth == 1;
    };
  })();
Run Code Online (Sandbox Code Playgroud)