在 JavaScript 中使用 window.matchMedia 执行媒体查询

对于构建网站的人来说,响应式网页设计 已经成为确保内容尽可能多地提供给用户的自然方法。这通常是通过 CSS 媒体查询 来实现的。但是,也存在 JavaScript 替代方案。

介绍 window.matchMedia

在 JavaScript 中使用媒体查询的方法是通过 window.matchMedia。基本上,您只需使用与 CSS 相同的方法,但使用 JavaScript 调用

var widthQuery = window.matchMedia("(min-width: 600px)");

此查询返回一个 MediaQueryList 对象,您可以对其执行以下操作

matches
查询是否匹配的布尔值。
media
序列化媒体查询列表。
addListener
向媒体查询添加事件监听器。比轮询值或类似操作更受欢迎。
removeListener
从媒体查询中删除事件监听器。

因此,确定媒体查询是否匹配的简单方法是使用 matches 属性

var widthMatch = window.matchMedia("(min-height: 500px)").matches;

添加监听器非常容易

function getOrientationValue (mediaQueryList) {
    console.log(mediaQueryList.matches);
}

portraitOrientationCheck = window.matchMedia("(orientation: portrait)");
portraitOrientationCheck.addListener(getOrientationValue);

演示和代码

我整理了一个 window.matchMedia 演示,您可以在其中看到一些查询的实际操作。尝试调整窗口大小并观察值的变化。

该演示的完整 JavaScript 代码,当然可以在 GitHub 上获得,如下所示


(function () {
    var matchMediaSupported = document.querySelector("#matchmedia-supported"),
        width600 = document.querySelector("#width-600"),
        height500 = document.querySelector("#height-500"),
        portraitOrientation = document.querySelector("#portrait-orientation"),
        width600Check,
        height500Check,
        portraitOrientationCheck;

    if (window.matchMedia) {
        matchMediaSupported.innerHTML = "supported";

        // Establishing media check
        width600Check = window.matchMedia("(min-width: 600px)"),
        height500Check = window.matchMedia("(min-height: 500px)"),
        portraitOrientationCheck = window.matchMedia("(orientation: portrait)");

        // Add listeners for detecting changes
        width600Check.addListener(setWidthValue);
        height500Check.addListener(setHeightValue);
        portraitOrientationCheck.addListener(setOrientationValue);
    }

    function setWidthValue (mediaQueryList) {
        width600.innerHTML = mediaQueryList.media;
    }

    function setHeightValue (mediaQueryList) {
        height500.innerHTML = mediaQueryList.matches;
    }

    function setOrientationValue (mediaQueryList) {
        portraitOrientation.innerHTML = mediaQueryList.matches;
    }

    // Setting initial values at load
    function setValues () {
        width600.innerHTML = width600Check.matches;
        height500.innerHTML = height500Check.matches;
        portraitOrientation.innerHTML = portraitOrientationCheck.matches;
    }

    window.addEventListener("DOMContentLoaded", setValues, false);
})();

Web 浏览器支持

目前,window.matchMedia 已在以下浏览器中实现

  • Firefox 6+
  • Google Chrome 9+
  • Safari 5.1+。注意:不支持 addListener
  • Firefox 移动版
  • Android 上的 Google Chrome 测试版。注意:不支持 addListener
  • iOS 上的 Safari 5。注意:不支持 addListener
  • Android 原生浏览器。注意:不支持 addListener

它也计划在 Internet Explorer 10 中实现。

对于较旧/不支持的 Web 浏览器,您可以尝试使用 matchMedia() polyfill,虽然它不支持 addListener

关于 Robert Nyman [荣誉编辑]

Mozilla Hacks 的技术布道者和编辑。发表演讲和博客,内容涉及 HTML5、JavaScript 和开放 Web。Robert 是 HTML5 和开放 Web 的坚定支持者,自 1999 年以来一直在从事 Web 前端开发 - 在瑞典和纽约市。他经常在 http://robertnyman.com 上发布博客,并且喜欢旅行和结识新朋友。

更多 Robert Nyman [荣誉编辑] 的文章…


15 条评论

  1. Moldován Eduárd

    哦,这看起来很棒。我很快就会尝试一下。

    2012 年 6 月 5 日 下午 6:34

    1. Robert Nyman

      酷!希望对您有所帮助!

      2012 年 6 月 6 日 下午 11:06

  2. d7ke

    这看起来非常强大。

    2012 年 6 月 5 日 下午 1:45

    1. Robert Nyman

      我也这么认为 - 很好地补充了 CSS 中的媒体查询。

      2012 年 6 月 6 日 下午 11:06

  3. John A. Bilicki III

    永远不要使用专有的 Microsoft JScript innerHTML 方法(或相关方法),因为它们无法在 DOM 中正确注册节点。要设置节点的文本,请使用 nodeValue。示例…

    document.getElementById(‘example-span’).nodeValue = ‘awesome’;

    document.getElementById(‘example-div’).firstChild.nodeValue = ‘awesome’;

    …即使有人设法将其添加到任何给定的标准中,也不能否定它使用起来极其不可靠。

    2012 年 6 月 7 日 下午 6:30

    1. Robert Nyman

      我不一定同意你的观点。这取决于具体情况以及你想做什么。我 很久以前与 Opera 的 Anne van Kesteren 共同撰写了这篇文章

      因此,是的,它可能存在潜在风险,但我个人认为它并没有排除所有使用场景。

      2012 年 6 月 7 日 上午 10:44

  4. John A. Bilicki III

    Robert,人们没有意识到的是,它实际上并没有正确注册 DOM。尝试在最后一个 readyState 关闭后通过 AJAX 加载的 ID 并通过 innerHTML 倾倒到 DOM 后,给它赋予焦点,这将不会发生,它也不仅限于给元素赋予焦点。如果将 (X)HTML 添加到 DOM 相当于加冕,那么 innerHTML 就会夺取王冠,并将其扔到那个人头上。

    2012 年 6 月 7 日 上午 11:30

    1. Robert Nyman

      我了解它的一些问题,但我认为这并不意味着它在所有情况下都不可用。

      2012 年 6 月 7 日 上午 11:52

      1. John A. Bilicki III

        我发现它唯一有用的情况是只读,用于直接查看 XHTML,尽管现在我们有了 Firebug,即使没有 Firebug,您也可以序列化 XHTML…

        var c = document.getElementById(‘target_element’).cloneNode(true);
        var s = new XMLSerializer();
        var str = s.serializeToString(c);
        alert(str);

        因此,只读对于快速调试来说是最佳选择,但我永远不会同意任何写入操作。除此之外,我们必须同意不同意。除了那篇好文章之外,没有好的演示来说明如何使用它以及它如何有用,那么新代码是毫无用处的。

        2012 年 6 月 7 日 下午 12:08

        1. Robert Nyman

          是的,我们同意不同意。:-)
          感谢您喜欢这篇文章!

          2012 年 6 月 8 日 下午 2:02

  5. rdeck

    我将在本周末付诸实践!

    2012 年 7 月 17 日 下午 3:15

    1. Robert Nyman

      希望证明对您有用!

      2012 年 7 月 31 日 上午 8:36

  6. Alon

    非常感谢!!
    一直在寻找这个

    2012 年 11 月 8 日 下午 2:38

  7. Mat

    在句子“The way to approch media queries in JavaScript”中,“approach”拼写错误。这很有趣,因为你在下一行拼写正确了。很棒的文章,非常有用!

    2013 年 2 月 2 日 下午 12:39

    1. Robert Nyman [编辑]

      感谢!只是一个小的拼写错误。

      2013 年 2 月 4 日 下午 3:02

本文的评论已关闭。