jQuery 为什么 window.width 小于媒体查询中设置的视口宽度
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18546067/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why is the window.width smaller than the viewport width set in media queries
提问by ermarus
I am quite puzzled and still unsure how to explain this in proper words. So far i've used and set up my media queries with Breakpoint. An used Breakpoint-variable looks like e.g.:
我很困惑,仍然不确定如何用正确的语言来解释这一点。到目前为止,我已经使用 Breakpoint 使用并设置了我的媒体查询。一个使用过的断点变量看起来像:
$menustatictofixed: min-width 900px;
$breakpoint-to-ems is set to true. I've laid out the page with all its Breakpoint variables based on the pixel values of the following jQuery snippet:
$breakpoint-to-ems 设置为 true。我已经根据以下 jQuery 代码段的像素值布置了页面及其所有断点变量:
$('body').append('<div style="position: fixed; bottom: 0; right: 0; display: inline-block; font-weight: bold; padding: 5px 7px; border-radius: 5px 0 0 0; background: green; color: white; z-index: 9999;">Viewport width <span id="width"></span> px</div>');
var viewportWidth = $(window).width()
$('#width').text(viewportWidth);
$(window).resize(function() {
var viewportWidth = $(window).width();
$('#width').text(viewportWidth);
});
Everything looked proper and clean. But over the last one or two days i had issues setting up the last breakpoints for a pattern and to get things behave predictable. Somehow the things that appeared to add up clean and fine in the first place, which i logically highly doubt now, are in fact improper and somehow a mess. Cuz if you take a look at the following screenshotsomehow the width of the window (in Chrome) differs to the width from the jQuery snippet utilising window.width. There isn't also a difference if i would replace window.width by window.innerWidth to rule out scrollbars eventually. The only way to receive proper results is by adding 15 pixels to the equation:
一切看起来都很干净。但是在过去的一两天里,我在为模式设置最后一个断点并使事情变得可预测时遇到了问题。不知何故,一开始看起来很干净的事情,我现在在逻辑上高度怀疑,实际上是不正确的,不知何故一团糟。因为如果你看一下下面的截图,窗口的宽度(在 Chrome 中)与使用 window.width 的 jQuery 片段的宽度不同。如果我将 window.width 替换为 window.innerWidth 以最终排除滚动条,也没有区别。获得正确结果的唯一方法是在等式中添加 15 个像素:
var viewportWidth = $(window).width() + 15;
Is the only issue in the whole equation that window.width is the wrong choice of function and it would be better to go with e.g. document.documentElement.clientWidth or something else or ... ? And for what the 15 pixels are standing for which fixed the problem above in a bit hacky way? Best regards Ralf
整个等式中唯一的问题是 window.width 是函数的错误选择,最好使用例如 document.documentElement.clientWidth 或其他东西或...?15 个像素代表什么,以一种有点hacky 的方式解决了上述问题?最好的问候拉尔夫
采纳答案by Snugug
The answer is scrollbars, and the solution is tricky.
答案是滚动条,解决方案很棘手。
Media queries are interesting. They don't behave precisely the same across browser, meaning using them can sometimes not be so easy. In -webkit/-blink on OS X and IE10 on Win8 for example, scrollbars are overlaid onto the page. In -moz, however, scrollbars are notoverlaid onto the page. The best way to get the "viewable area" of the page is the following line of vanilla JavaScript (assuming you have a valid HTML document):
媒体查询很有趣。它们在浏览器中的表现并不完全相同,这意味着使用它们有时并不那么容易。例如,在 OS X 上的 -webkit/-blink 和 Win8 上的 IE10 中,滚动条覆盖在页面上。但是,在 -moz 中,滚动条不会覆盖在页面上。获取页面“可视区域”的最佳方法是以下原生 JavaScript 行(假设您有一个有效的 HTML 文档):
document.body.parentNode.clientWidth
What this will do is find the body
element, find it's parent (which in a valid document will be the html
element), and then find it's width after rendering. This will give you the width you're interested in seeing. It's also a useless width to have.
这将做的是找到body
元素,找到它的父元素(在有效文档中将是html
元素),然后在渲染后找到它的宽度。这将为您提供您有兴趣看到的宽度。它也是一个无用的宽度。
Why, you may ask, is having the actual client width useless? It's not because it varies from browser to browser, because it does. It's because that's not what the width
media queries are actually testing! What width
media queries test iswindow.innerWidth
, which is what you're in essence using now.
您可能会问,为什么实际客户端宽度没有用?这不是因为它因浏览器而异,因为它确实如此。这是因为这不是width
媒体查询实际测试的内容!什么width
媒体查询测试是window.innerWidth
,这是你在本质上现在使用的是什么。
So what is the solution to this problem? Well I'd say the solution is to use content based media queries instead of device based media queries and be OK with some wiggle room in your queries (especially if that wiggle room is approx. 15px
). If you haven't already, read the articles Vexing Viewportsand A Pixel Identity Crisisto get an idea as to why a potential 15px
shimmer in your MQ definitions isn't the worst thing in the world (there are probably bigger fish to fry).
那么这个问题的解决方案是什么?好吧,我想说的解决方案是使用基于内容的媒体查询而不是基于设备的媒体查询,并且可以在您的查询中留出一些回旋余地(特别是如果回旋余地大约15px
)。如果您还没有读过文章,请阅读令人烦恼的视口和像素身份危机,以了解为什么15px
MQ 定义中的潜在闪光并不是世界上最糟糕的事情(可能还有更大的鱼要炸)。
So, in conclusion continue using $breakpoint-to-ems: true
and choose your media queries based on when content breaks to window.innerWidth
as it's the only sane way of handling cross-browser issues. From a cursory glance of various issues, it appears as if most browsers and OSes are moving to an overlay scrollbar (as of Firefox 24every OS X browser will have one, Ubuntu's Unity UI introduced them), so in an effort to be future friendly, I'd suggest not worrying about the scroll bar offset and be OK with sites looking slightly different across browser. Remember, as Ethan Marcotte so eloquently put:
因此,总而言之,继续使用$breakpoint-to-ems: true
并根据内容中断的时间选择您的媒体查询,window.innerWidth
因为这是处理跨浏览器问题的唯一明智方法。从各种问题的粗略看,似乎大多数浏览器和操作系统都在转向覆盖滚动条(从Firefox 24 开始,每个 OS X 浏览器都会有一个,Ubuntu 的 Unity UI引入了它们),因此为了未来友好,我建议不要担心滚动条偏移,并且可以在浏览器中看起来略有不同的网站。请记住,正如伊桑·马科特 (Ethan Marcotte) 雄辩地指出的那样:
The Web is an Inherently Unstable Medium
网络是一种内在不稳定的媒介
回答by Justin
This is what worked for me: CSS media queries and JavaScript window width do not match.
这对我有用: CSS 媒体查询和 JavaScript 窗口宽度不匹配。
Instead of using $(window).width();
which includes scrollbars get the inner width like this:
而不是使用$(window).width();
包含滚动条的内部宽度是这样的:
function viewport() {
var e = window, a = 'inner';
if (!('innerWidth' in window )) {
a = 'client';
e = document.documentElement || document.body;
}
return { width : e[ a+'Width' ] , height : e[ a+'Height' ] };
}
var vpWidth = viewport().width; // This should match your media query
回答by Tushar Gupta - curioustushar
IT's because of the scrollbar's
这是因为 scrollbar's
The most correct solution I found is to use media queries to pass the actual window size to Javascript. You have to follow these steps:
我发现的最正确的解决方案是使用媒体查询将实际窗口大小传递给 Javascript。您必须按照以下步骤操作:
- Add a hidden element to your page,
- Use media queries to alter the
max-width
property of that element, - Read back the
max-width
property of that element through Javascript.
- 向页面添加隐藏元素,
- 使用媒体查询来改变该
max-width
元素的属性, max-width
通过 Javascript读回该元素的属性。
For instance, add the following element to your page:
例如,将以下元素添加到您的页面:
<div id="currentMedia"></div>
Then write the following CSS rules:
然后编写以下 CSS 规则:
#currentMedia {
display: none;
}
@media (max-width: 720px) {
// Make arrows in the carousel disappear...
#currentMedia {
max-width: 720px;
}
}
Then, from the Javascript side, you can write:
然后,从 Javascript 方面,您可以编写:
if (parseInt(jQuery("#currentMedia").css("max-width"), 10) <= 720) {
// Code HERE..
}
And it will be accurate regardless of the scrollbar size, since the value comes from the same media query that triggers the carousel's disappearance.
无论滚动条的大小如何,它都将是准确的,因为该值来自触发轮播消失的同一媒体查询。
I tested this solution on all major recent browsers, and it gives correct results.
我在所有主要的近期浏览器上测试了这个解决方案,它给出了正确的结果。
You will find the big summary of what properties are supported on what browsers on this page on quirksmode.org.
您将在 quirksmode.org 上的此页面上找到哪些浏览器支持哪些属性的大摘要。
Your best bet is probably to grab an element in the page (using document.body where supported, or document.getElementById or whatever), walk its offsetParent chain to find the topmost element, then examine that element's clientWidth and clientHeight.
最好的办法可能是获取页面中的一个元素(使用受支持的 document.body 或 document.getElementById 或其他),遍历它的 offsetParent 链以找到最顶层的元素,然后检查该元素的 clientWidth 和 clientHeight。
innerWidthdocumentation
内宽文档
.innerWidth()
method is not applicable to window
and document
objects; for these, use .width()
instead.
.innerWidth()
方法不适用于window
和document
对象;对于这些,请.width()
改用。
回答by Gruffy
Similar to @Snugugs's answer but worked better for my use case:
类似于@Snugugs 的答案,但对我的用例效果更好:
CSS (Note I am using LESS so @tabletMin and @desktopMin translate to breakpoint variables I have set elsewhere:
CSS(注意我使用的是 LESS,所以 @tabletMin 和 @desktopMin 转换为我在其他地方设置的断点变量:
#cssWidth {
display:none;
content:'mobile';
}
/* Responsive styles (Tablet) */
@media (min-width: @tabletMin) {
#cssWidth {
content:'tablet';
}
/* Other tablet CSS... */
}
/* Responsive styles (Desktop) */
@media (min-width: @desktopMin) {
#cssWidth {
content:'desktop';
}
/* Other Desktop CSS... */
}
And then in JS:
然后在 JS 中:
getView = function() {
// If #cssWidth element does not exist, create it and prepend it do body
if ($('#cssWidth').length === 0) {
$('body').prepend($(document.createElement('div')).attr('id', 'cssWidth'));
}
// Return the value of the elements 'content' property
return $('#cssWidth').css('content');
};
The getView() function will then return the string 'mobile', 'tablet' or 'desktop' dependant on the width the media queriessee.
然后 getView() 函数将根据媒体查询看到的宽度返回字符串 'mobile'、'tablet' 或 'desktop' 。
This could be extended to fit more viewport widths, just add more rules in the CSS with other values.
这可以扩展以适应更多视口宽度,只需在 CSS 中添加更多规则和其他值。
回答by Amidou Zabre
function getWindowWidth() {
var windowWidth = 0;
if (typeof(window.innerWidth) == 'number') {
windowWidth = window.innerWidth;
}
else {
if (document.documentElement && document.documentElement.clientWidth) {
windowWidth = document.documentElement.clientWidth;
}
else {
if (document.body && document.body.clientWidth) {
windowWidth = document.body.clientWidth;
}
}
}
return windowWidth;
}
回答by kontur
@Snugug 's answer gives a really good explanation as to why this is happening, and @TusharGupta has a good solution as well that references the mediaquery detected width to javascript. Below solution goes the other way around by using javascript detected width to trigger layout changes.
@Snugug 的回答很好地解释了为什么会发生这种情况,@TusharGupta 也有一个很好的解决方案,将 mediaquery 检测到的宽度引用到 javascript。下面的解决方案通过使用 javascript 检测到的宽度来触发布局更改来反过来。
In case you need to sync mediaqueries with your javascript pixel width detection, one way of approaching the problem is to trigger css layout changes based on classes you add with javascript.
如果您需要将媒体查询与 javascript 像素宽度检测同步,解决该问题的一种方法是根据您使用 javascript 添加的类触发 css 布局更改。
So, instead of writing mediaqueries, write those declarations nested under a class, say:
因此,不要编写媒体查询,而是编写嵌套在类下的声明,例如:
html.myMobileBP { ... }
And in your javascript/jQuery, add this class like:
在您的 javascript/jQuery 中,添加此类,如:
if ($(window).width() < myMobileBPPixelSize) {
$("html").addClass("myMobileBP");
}
To drive this even further, you might want to consider lack of javascript support. Define mediaqueries that are furthermore wrapped in a html.no-js
class, then with javascript remove the .no-js
class and apply the above solution of adding breakpoints via javascript classes.
为了进一步推动这一点,您可能需要考虑缺乏 javascript 支持。定义进一步包装在html.no-js
类中的媒体查询,然后使用 javascript 删除.no-js
该类并应用上述通过 javascript 类添加断点的解决方案。
回答by Potoroaca Anamaria
Use classes on body to define if you are on mobile, tablet or desktop instead using pixels.
使用 body 上的类来定义您是在移动设备、平板电脑还是台式机上,而不是使用像素。
For me it did not work document.body.clientWidth
or innerWidth
.
My functionality crashes between 1023-1040px even if my js code must do this statement:
对我来说它不起作用document.body.clientWidth
或innerWidth
. 即使我的 js 代码必须执行以下语句,我的功能也会在 1023-1040px 之间崩溃:
if($(window).width()<1024)
The solution was to put on body a new class for less than 1024 and name it "small-res" and use it than in my code instead of pixels verification:
解决方案是在 body 上放置一个小于 1024 的新类并将其命名为“small-res”并在我的代码中使用它而不是像素验证:
if($(body).hasClass('small-res'))
I recommend it to you too.
我也推荐给你。