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

时间:2017-06-22 00:52:19

标签: javascript css media-queries responsive

我一直在寻找一种轻量级,灵活的跨浏览器解决方案,用于在JavaScript中访问CSS媒体查询,而不受其断点值的约束。

CSS-tricks发布了CSS3 animations-based solution,这似乎很明显,但它建议使用Enquire.js

Enquire.js似乎仍然需要在脚本中硬编码媒体查询大小,例如

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

问题

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

尝试解决方案

我已经制作了自己的版本,可以在IE9 +中运行,使用隐藏元素,使用:content属性在Query触发时添加我想要的内容(与ZeroSixThree's solution相同的起点): / p>

HTML

<body>
    <lots of stuff>
    <span id="mobile-test"></span>
</body>

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

使用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 'contnet' 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
    }
});

这样,Media Query的断点完全由CSS处理。如果更改断点,则无需更新脚本。怎么办呢?

4 个答案:

答案 0 :(得分:2)

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

另一位专家大卫·沃尔什Device State Detection with CSS Media Queries and JavaScript提供了另一种满足您要求的方式:

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

var state = window.getComputedStyle(
    document.querySelector('.state-indicator'), ':before'
).getPropertyValue('content')

答案 1 :(得分:1)

试试这个

const mq = window.matchMedia( "(min-width: 500px)" );

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

if (mq.matches) {

  // window width is at least 500px
} else {
  // window width is less than 500px
}

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

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

}

答案 2 :(得分:0)

我找到了一个骇人但简单的解决方案:

@media (min-width: 800px) {
.myClass{
    transition-property: customNS-myProp;
}

此css属性只是一个标记,可以在JS中知道是否已达到断点。根据规范,过渡属性可以包含任何内容,并且受IE支持(请参见https://developer.mozilla.org/en-US/docs/Web/CSS/transition-propertyhttps://developer.mozilla.org/en-US/docs/Web/CSS/custom-ident)。

然后仅在js中检查过渡属性是否具有值。例如在TS中使用JQuery:

const elements: JQuery= $( ".myClass" );
        $.each( elements, function (index, element) {
            const $element = $( element );
            const transition = $element.css( "transition-property" );
            if (transition == "custNS-myProp") {
                // handling                     ...
            }
        });

当然,在Wiki中有一个警告词,即css属性标识符的域正在演变,但是我想如果您为该值加上前缀(例如在此处带有customNS),则可以永久避免冲突。

将来,当IE支持它们时,请使用自定义属性而不是过渡属性          https://developer.mozilla.org/en-US/docs/Web/CSS/--*

答案 3 :(得分:0)

我通过为不可见元素创建宽度规则来获取断点值。

HTML:

<div class="secret-media-breakpoints">
    <span class="xs"></span>
    <span class="tiny"></span>
    <span class="sm"></span>
    <span class="md"></span>
    <span class="lg"></span>
    <span class="xl"></span>
</div>

CSS:

$grid-breakpoints: (
    xs:   0,
    tiny: 366px,
    sm:   576px,
    md:   768px,
    lg:   992px,
    xl:   1200px
);

.secret-media-breakpoints {
    display: none;

    @each $break, $value in $grid-breakpoints {
        .#{$break} {
            width: $value;
        }
    }
}

JavaScript:

app.breakpoints = {};
$('.secret-media-breakpoints').children().each((index, item) => {
    app.breakpoints[item.className] = $(item).css('width');
});