【发布时间】:2013-12-09 11:30:25
【问题描述】:
当 bootstrap-responsive.css 媒体查询生效时,哪种方式是最快速、最简单的触发方式?
开始行动 = 当您将窗口大小调整为移动设备宽度并且网站更改为响应式移动设备时
希望问题清楚
【问题讨论】:
-
你需要用 JavaScript 来做。
标签: javascript jquery css twitter-bootstrap media-queries
当 bootstrap-responsive.css 媒体查询生效时,哪种方式是最快速、最简单的触发方式?
开始行动 = 当您将窗口大小调整为移动设备宽度并且网站更改为响应式移动设备时
希望问题清楚
【问题讨论】:
标签: javascript jquery css twitter-bootstrap media-queries
改进出色的@falsarella 答案,这是一个适用于 Bootstrap 4 的较短版本:
#mq-detector {
visibility: hidden;
}
<div id="mq-detector">
<span data-mq="xs" class="d-block d-sm-none"></span>
<span data-mq="sm" class="d-none d-sm-block d-md-none"></span>
<span data-mq="md" class="d-none d-md-block d-lg-none"></span>
<span data-mq="lg" class="d-none d-lg-block d-xl-none"></span>
<span data-mq="xl" class="d-none d-xl-block"></span>
</div>
//Define function that returns the currently used media query
function getBsMq(){
var currMq;
var mqDetector = $('#mq-detector [data-mq]');
mqDetector.each(function(i){
if ($(this).is(':visible')) {
currMq = $(this).attr('data-mq');
}
});
return currMq;
}
//Call the function and get the currently used media query
alert(getBsMq());
【讨论】:
Terryfrancis 中的 already answered on stackoverflow 在我的 Bootstrap 4 应用程序中仍然有用,当我想在我的 Bootstrap 4 应用程序中将非引导模块的类更改为 .col-md 时.
我同时使用了 onload 和 window resize 功能:
// on load
if ($(window).width() > 575 && $(window).width() < 992) {
$('div').addClass('col-md-6').removeClass('col-md-4');
} else if ($(window).width() > 992) {
$('div').addClass('col-md-4').removeClass('col-md-6');
}
// on user resizes browser window
$( window ).resize(function() {
if ($(window).width() > 575 && $(window).width() < 992) {
$('div').addClass('col-md-6').removeClass('col-md-4');
} else if (jQuery(window).width() > 992) {
$('div').addClass('col-md-4').removeClass('col-md-6');
}
});
【讨论】:
我会将window.matchMedia 与window.addEventListener('resize') 一起使用。下面的示例,特别是函数getActiveBreakpoint() 将告诉您哪个断点处于活动状态,但还会告诉您哪些是lt-(小于)和gt-(大于)以帮助类的形式,即gt-xs gt-sm md lt-lg lt-xl,请参阅https://jsfiddle.net/Lqtmc8yo/1/
/*
// from bootstrap/scss/_variables.scss
$grid-breakpoints: (
xs: 0,
sm: 576px,
md: 768px,
lg: 992px,
xl: 1200px
) !default;
*/
const breakpoints = {
xs: 0,
sm: 576,
md: 768,
lg: 992,
xl: 1200,
}
const orderedKeys = ['xs', 'sm', 'md', 'lg', 'xl']
const getActiveBreakpoint = () => {
let breakpoint = ''
let classList = []
orderedKeys.some((k, i) => {
const n = orderedKeys[i + 1]
let query = ''
query += `(min-width: ${breakpoints[k]}px)`
if (n) {
query += `and (max-width: ${breakpoints[n] - 1}px)`
}
if (window.matchMedia(query).matches) {
breakpoint = k
classList = [...orderedKeys.slice(0, i).map(b => `gt-${b}`), k, ...orderedKeys.slice(i + 1, orderedKeys.length).map(b => `lt-${b}`)]
return true
}
return false
})
return { breakpoint, classList, className: classList.join(' ') }
}
const calculate = () => {
const result = getActiveBreakpoint()
document.getElementById('result').innerHTML = `
breakpoint: ${result.breakpoint}
<br>
className: ${result.className}
`
}
window.addEventListener('resize', calculate)
calculate()
<div id="result"></div>
【讨论】:
这是我基于 @falsarella 想法的 bootstrap 4 解决方案
*注意:使用下面的“整页”选项来测试这个sn-p,否则它会返回错误的屏幕类型,基于sn-p iframe size
/**
* @returns STRING current screen type like: xs, sm, md, lg or xl
*/
function getScreenType() {
!function initHelpers() {
if ($('div.mq-detector').length !== 0) return;
$('body').append(_mqDetector());
// helpers
function _mqDetector() {
return `
<div class="mq-detector invisible">
<div
class="d-block d-sm-none"
data-type="xs"></div>
<div
class="d-none d-sm-block d-md-none"
data-type="sm"></div>
<div
class="d-none d-md-block d-lg-none"
data-type="md"></div>
<div
class="d-none d-lg-block d-xl-none"
data-type="lg"></div>
<div
class="d-none d-xl-block"
data-type="xl"></div>
</div>
`;
}
}();
// @then
return $('div.mq-detector').children().filter(':visible').data('type');
}
console.log(getScreenType())
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">
【讨论】:
我已经修改了this 链接中的代码,该链接指向 Bootsrap 4,而不是 alpha 或 beta。代码如下;
/* **********************************************************
Detect bootrap 4 media query type
https://getbootstrap.com/docs/4.0/utilities/display/
********************************************************** */
$("body").append("<div style='visibilty:hidden' class='viewport-check'><span class='d-block d-sm-none'>xs</span><span class='d-none d-sm-block d-md-none'>sm</span><span class='d-none d-md-block d-lg-none'>md</span><span class='d-none d-lg-block d-xl-none'>lg</span><span class='d-none d-xl-block'>xl</span></div>");
var Bootstrap4MediaQuery = "";
//> Checks if the span is set to display block via CSS
function FnDetectMediaQuery(_QsTarget) {
var _QsTarget = $(_QsTarget).css('display') == 'block';
return _QsTarget;
}
if(FnDetectMediaQuery('.viewport-check .d-block') == true)
{
Bootstrap4MediaQuery = "xs";
}
else if(FnDetectMediaQuery('.viewport-check .d-sm-block') == true)
{
Bootstrap4MediaQuery = "sm";
}
else if(FnDetectMediaQuery('.viewport-check .d-md-block') == true)
{
Bootstrap4MediaQuery = "md";
}
else if(FnDetectMediaQuery('.viewport-check .d-lg-block') == true)
{
Bootstrap4MediaQuery = "lg";
}
else if(FnDetectMediaQuery('.viewport-check .d-xl-block') == true)
{
Bootstrap4MediaQuery = "xl";
}
else
{
Bootstrap4MediaQuery = "";
}
console.log("Bootstrap4MediaQuery: " + Bootstrap4MediaQuery);
【讨论】:
我准备了一个超轻量级库来处理窗口宽度和引导断点更改时触发的事件 - responsive-breakpoint-tester
var viewport = new ResponsiveTester();
$('body').on('in.screen.xs', function(event, devices) {
// Code executed when viewport is was changed to xs
});
$('body').on('out.screen.xs', function(event, devices) {
// Code executed when viewport is no longer xs
});
还包括其他功能,例如当前断点检查:
if (viewport.is('xs')) {
// Executed only on xs breakpoint
}
if (viewport.is('!=xs')) {
// Executed on all breakpoints that are not equal xs (sm, md, lg)
}
if (viewport.is('<md')) {
// Executed on breakpoints that are smaller than md (xs, sm)
}
if (viewport.is('<=md')) {
// Executed on breakpoints that are smaller or equal to md (xs, sm, md)
}
if (viewport.is('>md')) {
// Executed on breakpoints that are larger than md (lg)
}
支持 Bootstrap 4 和 Foundation 配置,更多信息请访问GitHub Repository
【讨论】:
此代码添加正文标记ld、md、sd或xd类
$(function(){
var device_width_detect = '';
function device_detec(){
if ($(this).width() >= 1280) {
device_width_detect = 'ld';
}else if ($(this).width() < 1280 && $(this).width()>= 992) {
device_width_detect = 'md';
}else if ($(this).width() < 992 && $(this).width()>= 768) {
device_width_detect = 'sd';
}else if ($(this).width() < 768) {
device_width_detect = 'xd';
}
$('body').removeClass( "ld md sd xd" ).addClass( device_width_detect );
}
device_detec();
$(window).on('resize', device_detec);
});
【讨论】:
我用它只在大屏幕上的引导程序中将导航栏粘贴在https://ducttapedanyol.com:
if ($(this).width() >= 979) { // Detect screen size
$(document).ready(function () {
var menu = $('.menu');
var origOffsetY = menu.offset().top;
function scroll() {
if ($(window).scrollTop() >= origOffsetY) {
$('.menu').addClass('sticky');
$('.fix').addClass('fix-tall');
} else {
$('.menu').removeClass('sticky');
$('.fix').removeClass('fix-tall');
}
}
document.onscroll = scroll;
});
}
【讨论】:
更简单
$(window).on('resize', function () {
if ($('<div class="visible-lg">').css('display')=='block') {
// Do something for lg
}
// ...
});
【讨论】:
您可以使用matchMedia 和包装库enquire.js 注册媒体查询并在匹配/不匹配时发出事件。
让我们以这些 Bootstrap CSS 媒体查询为例,取自 the docs。
/* Extra small devices (phones, less than 768px) */
/* No media query since this is the default in Bootstrap */
/* Small devices (tablets, 768px and up) */
@media (min-width: @screen-sm-min) { ... }
/* Medium devices (desktops, 992px and up) */
@media (min-width: @screen-md-min) { ... }
/* Large devices (large desktops, 1200px and up) */
@media (min-width: @screen-lg-min) { ... }
要查看何时应用这些规则,请使用enquire.js 注册媒体查询并提供适当的match 和unmatch 函数,如下所示:
let rules = [
'(max-width: 768px)', // extra small devices, default
'(min-width: 768px)', // small devices
'(min-width: 992px)', // medium devices
'(min-width: 1200px)' // large devices
];
for (let rule of rules) {
enquire.register(rule, {
match: function() {
console.log(rule + ' matched');
},
unmatch: function() {
console.log(rule + ' unmatched');
}
});
}
enquire.js 使用matchMedia 其中supports only the modern browsers,例如没有IE9。因此,旧版浏览器需要polyfill 才能完成这项工作。
【讨论】:
我想出了一种使用窗口调整大小事件的方法,但依赖于 Twitter Bootstrap 的媒体查询,而不是硬编码它们的断点:
<span id="mq-detector">
<span class="visible-xs"></span>
<span class="visible-sm"></span>
<span class="visible-md"></span>
<span class="visible-lg"></span>
</span>
#mq-detector {
visibility: hidden;
}
var currMqIdx = undefined;
var mqDetector = $("#mq-detector");
var mqSelectors = [
mqDetector.find(".visible-xs"),
mqDetector.find(".visible-sm"),
mqDetector.find(".visible-md"),
mqDetector.find(".visible-lg")
];
var checkForResize = function() {
for (var i = 0; i <= mqSelectors.length; i++) {
if (mqSelectors[i].is(":visible")) {
if (currMqIdx != i) {
currMqIdx = i;
console.log(mqSelectors[i].attr("class"));
}
break;
}
}
};
$(window).on('resize', checkForResize);
checkForResize();
【讨论】:
基于@falsarella's solution,js部分可以简化为:
var currMqIdx = undefined;
var checkForResize = function() {
currMqIdx = $('#mq-detector span').index($('#mq-detector span:visible'));
};
$(window).on('resize', checkForResize);
checkForResize();
currMqIdx 是一个 int 值,从 0 到 3。currMqIdx 越大,媒体越宽。
【讨论】:
对于那些喜欢这种不影响他们实际标记的人来说,以下作品:
$(function(){
...
var mqClasses = ["visible-xs", "visible-sm", "visible-md", "visible-lg"];
var mq = $("<span id='mqDetector' style='visibility:hidden'></span>").appendTo($("body"));
$.each(mqClasses, function(idx, val) {
mq.append("<span class='" + val + "'></span>");
});
function checkMQ() {
var visible = mq.find(":visible").get(0).className;
return visible.slice(-2);
};
function checkResize(){
switch(checkMQ){
case 'xs' : ...; break;
case 'sm' : ...; break;
...
}
}
$(window).on('resize', checkResize);
checkResize(); //do it once when page loads.
【讨论】:
:visible 有一些问题。有时,所有尺寸(xs、sm、md、lg)都只是false。我最终使用了function checkMQ() { var found; mq.children().each(function() { if ($(this).css("display") !== "none") { found = $(this); return false; } return true; }); return found.attr("class").slice(-2);}。
其他答案的一个问题是每次调整大小都会触发更改事件。如果您的 javascript 正在做一些重要的事情,这可能会非常昂贵。
当超过阈值时,下面的代码只会调用一次更新函数。
要进行测试,请抓住窗口大小手柄,然后快速拖动调整大小以查看浏览器是否阻塞。
<script>
// Global state variable
var winSize = '';
window.onresize = function () {
var newWinSize = 'xs'; // default value, check for actual size
if ($(this).width() >= 1200) {
newWinSize = 'lg';
} else if ($(this).width() >= 992) {
newWinSize = 'md';
} else if ($(this).width() >= 768) {
newWinSize = 'sm';
}
if( newWinSize != winSize ) {
doSomethingOnSizeChange();
winSize = newWinSize;
}
};
</script>
【讨论】:
(newWinSize != winSize) 时触发执行。
var winSize下面有var newWinSize = '';
这适用于我与 Bootstrap 3 结合使用:
<div id="media-width-detection-element"></div>
<style type="text/css">
#media-width-detection-element {
display: none;
width: 0px;
}
@media (min-width: 768px) {
#media-width-detection-element {
width: 768px;
}
}
@media (min-width: 992px) {
#media-width-detection-element {
width: 992px;
}
}
@media (min-width: 1200px) {
#media-width-detection-element {
width: 1200px;
}
}
</style>
<script type="text/javascript">
//<![CDATA[
function xs() {
return $("#media-width-detection-element").css("width") === "0px";
}
function sm() {
return $("#media-width-detection-element").css("width") === "768px";
}
function md() {
return $("#media-width-detection-element").css("width") === "992px";
}
function lg() {
return $("#media-width-detection-element").css("width") === "1200px";
}
//]]>
</script>
隐藏的 DIV 会根据实际使用的 CSS 最小宽度设置更改宽度。然后我的javascript简单检查DIV的当前。
【讨论】:
xs,即使调整窗口大小也没有其他提醒,也没有响应,即不能调整窗口大小。
xs 以外的任何内容,或者您需要将代码移出框架。要在调整大小时弹出它,只需将警报放入 $(window).resize(function() { /*PUT ALERT HERE*/ });
使用 jquery 你可以找到当前窗口的大小,然后相应地做你的事情。
$(window).resize(function() {
if ($(this).width() >= 1280) {
//do something
}
else if ($(this).width() < 1280 && $(this).width()>= 980) {
//do something
}
...
});
/* Large desktop */
@media (min-width: 1200px) { ... }
/* Portrait tablet to landscape and desktop */
@media (min-width: 768px) and (max-width: 979px) { ... }
/* Landscape phone to portrait tablet */
@media (max-width: 767px) { ... }
/* Landscape phones and down */
@media (max-width: 480px) { ... }
【讨论】: