使用 JavaScript 检测动态媒体查询而不在脚本中硬编码断点宽度?
Posted
技术标签:
【中文标题】使用 JavaScript 检测动态媒体查询而不在脚本中硬编码断点宽度?【英文标题】:Detect dynamic media queries with JavaScript without hardcoding the breakpoint widths in the script? 【发布时间】:2017-11-25 02:00:12 【问题描述】:我一直在寻找一种轻量级、灵活、跨浏览器的解决方案,用于在 javascript 中访问 CSS 媒体查询,不会在 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 相同的起点):
<body>
<p>Page content</p>
<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 '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
);
这样,媒体查询的断点完全由 CSS 处理。如果您更改断点,则无需更新脚本。如何做到这一点?
【问题讨论】:
window.onresize
处理函数的目的是什么?它似乎将您的detectMediaQuery
函数消除了 100 毫秒,但该函数除了返回一个字符串之外什么也不做。处理程序甚至不使用它。
肯定不理想,那段代码是从this question挪用的
我并不是说它不理想,我是说它看起来完全是死代码,混淆了你的问题。
我的意思是我的代码并不理想 :) 但感谢您提供的信息
【参考方案1】:
我设法通过为不可见元素创建宽度规则来获取断点值。
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');
);
【讨论】:
【参考方案2】:请参阅来自专家 David Walsh Device State Detection with CSS Media Queries and 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';
JS
var state = window.getComputedStyle(
document.querySelector('.state-indicator'), ':before'
).getPropertyValue('content')
此外,这是来自 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;
;
)();
【讨论】:
谢谢,*** JS 解决方案看起来很漂亮,但它仍然依赖于对查询断点进行硬编码。第二个解决方案看起来不错,但是 David Walsh 的解决方案通过使用z-index
而不是 content
解决了浏览器支持问题,然后通过 JS 对象将每个 z-index 值重新分配给所需的文本值
如果您不想将 .state-indicator
元素添加到 DOM,您似乎也可以使用 body:before
(至少在 Chrome 中)。
这些都是巧妙的变通办法,但难道没有一种“官方”的方式可以知道哪些媒体查询在 CSS 中处于活动状态吗?【参考方案3】:
我找到了一个 hackish 但简单的解决方案:
@media (min-width: 800px)
.myClass
transition-property: customNS-myProp;
这个 css 属性只是一个标记,可以在 JS 中知道是否达到了断点。根据规范,transition-property 可以包含任何内容并受 IE 支持(请参阅https://developer.mozilla.org/en-US/docs/Web/CSS/transition-property 和 https://developer.mozilla.org/en-US/docs/Web/CSS/custom-ident)。
如果transition-property 有值,则只需检查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 支持它们时,使用自定义属性而不是 transition-property https://developer.mozilla.org/en-US/docs/Web/CSS/--*.
【讨论】:
【参考方案4】:试试这个
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
【讨论】:
感谢@Taioli,但这仍然涉及将断点值硬编码到 JavaScript 中。我试图找出如何实现这个结果没有硬编码断点值 多年后,我仍然不明白为什么当它错过了问题的要点时,为什么会被赞成——而不是在 JavaScript 中硬编码断点值。 仍然被赞成,仍然错过了这个问题。所以在工作;p以上是关于使用 JavaScript 检测动态媒体查询而不在脚本中硬编码断点宽度?的主要内容,如果未能解决你的问题,请参考以下文章
CSS媒体查询不足以检测超大型移动设备/平板电脑,而不是台式机[重复]
我需要一种使用 jquery 检测 CSS3 媒体查询支持的简单方法
如何使用 Javascript 或 CSS 在 DIV 上应用媒体查询 [重复]