如何将CSS媒体查询的结果传递给JS?

Mat*_*zny 0 html javascript css leaflet

我有一个JS变量来控制页面的样式。我希望它根据屏幕分辨率进行更改。如何使它取决于CSS媒体查询的结果。

我知道我可以直接在JS中检查屏幕分辨率,但是我想将所有样式决定保留在CSS内,而不是将其散布在JS和CSS文件中。

为避免XY问题:我正在使用Leaflet,而JS变量决定是否折叠了列出可用图层的任何地图控制面板。它应该在小屏幕(移动设备)上折叠而不是在大屏幕(适当的显示器)上折叠。

相关代码如下

html,
body {
  height: 100%;
  margin: 0;
}

#map {
  width: 600px;
  height: 400px;
}

@media (min-width: 1000px) {
  #map {
    width: 1000px;
    height: 900px;
  }
}
Run Code Online (Sandbox Code Playgroud)
<!DOCTYPE html>
<html>
<!--based on https://leafletjs.com/examples/layers-control/ example -->

<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.3/dist/leaflet.css" integrity="sha512-Rksm5RenBEKSKFjgI3a41vrjkw4EVPlJ3+OiI65vTjIdo9brlAacEuKOiQ5OFh7cOI1bkDwLqdLw3Zg0cRJAAQ==" crossorigin="" />
  <script src="https://unpkg.com/leaflet@1.3.3/dist/leaflet.js" integrity="sha512-tAGcCfR4Sc5ZP5ZoVz0quoZDYX5aCtEm/eu1KhSLj2c9eFrylXZknQYmxUssFaVJKvvc0dJQixhGjG2yXWiV9Q==" crossorigin=""></script>
  <link rel="stylesheet" href="example.css" />
</head>

<body>
  <div id='map'></div>
  <script>
    var positron = L.tileLayer('https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png', {
        attribution: '#{openstreetmap_copyright_notice}, basemap: &copy; <a href=\"http://cartodb.com/attributions\">CartoDB</a>',
        subdomains: 'abcd',
        maxZoom: 19
      }),
      osmcarto = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
        attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
      });

    var map = L.map('map', {
      center: [39.73, -104.99],
      zoom: 10,
      layers: [positron]
    });

    var baseLayers = {
      "positron": positron,
      "osm-carto": osmcarto
    };

    L.control.layers(baseLayers, {}, {
      collapsed: false
    }).addTo(map); //false/true should be specified by CSS
  </script>
</body>

</html>
Run Code Online (Sandbox Code Playgroud)

T.J*_*der 5

您可以使用它matchMedia来执行此操作,作为一次性检查或(更有用)与回调(更多关于回调选项在这里):

window.matchMedia("(min-width: 1000px)").addListener(function(e) {
    if (e.matches) {
        // The window currently matches the query
    } else {
        // It doesn't
    }
});
Run Code Online (Sandbox Code Playgroud)

为了避免在 JavaScript 中重复查询文本,您可以搜索document.styleSheets并使用它们的media属性。可能不是很有趣,但我无法想象有任何其他方法可以避免重复媒体查询。

例如,这使用screen and它找到的第一个规则(jsFiddle):

// Find the rule
const rule = Array.from(document.styleSheets).reduce((found, sheet) => {
    return found || Array.from(sheet.cssRules || sheet.rules).find(rule => {
        return rule.conditionText && rule.conditionText.startsWith("screen and ");
    });
}, null);
if (rule) {
    const query = rule.conditionText.substring(11);
    console.log("rule found, setting listener for: " + query);
    window.matchMedia(query).addListener(function(e) {
        console.log("matches? ", e.matches);
    });
} else {
    console.log("No rule found");
}
Run Code Online (Sandbox Code Playgroud)

自然,您需要等待通过link元素加载的任何样式表首先加载。


Pau*_*ott 5

非常简单的解决方案,但是这意味着不对JS中的任何宽度属性进行硬编码。

向页面添加一个虚拟的不可见元素。

<div id="dummy"></div>

#dummy::after {
  display: none;
  content: 'false';
}

@media (min-width: 1000px) {
  #dummy::after {
    content: 'true';
  }
}
Run Code Online (Sandbox Code Playgroud)

然后读取contentJS中的值:

var isBigScreen = window.getComputedStyle(
    document.querySelector('#dummy'), ':after'
).getPropertyValue('content');
Run Code Online (Sandbox Code Playgroud)

isBigScreen将为"true""false"。如果屏幕尺寸发生更改,您可能需要添加一些代码以重新检查。

if(isCollapsed === '"false"') {
    isCollapsed = false;
} else {
    isCollapsed = true;
}
Run Code Online (Sandbox Code Playgroud)

可用于将其转换为标准布尔值。