我一直在寻找一种轻量级,灵活的跨浏览器解决方案,用于在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处理。如果更改断点,则无需更新脚本。怎么办呢?
答案 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-property和https://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');
});