为什么window.width小于媒体查询中设置的视口宽度

时间:2013-08-31 08:16:37

标签: jquery css css3 media-queries breakpoint-sass

我很困惑,仍然不确定如何用恰当的话来解释这一点。到目前为止,我已经使用Breakpoint设置了我的媒体查询。使用的断点变量看起来像例如:

$menustatictofixed: min-width 900px;

$ breakpoint-to-ems设置为true。我根据以下jQuery代码段的像素值布置了包含所有Breakpoint变量的页面:

$('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);
});

一切看起来都很干净。但是在过去的一两天里,我遇到了为模式设置最后断点并让事情表现出可预测性的问题。在某种程度上,首先看起来干净整洁的东西,我现在在逻辑上非常怀疑,实际上是不合适的,不知何故是一团糟。 Cuz,如果你看一下以下screenshot窗口的宽度(在Chrome中)与使用window.width的jQuery片段的宽度不同。如果我用window.innerWidth替换window.width来最终排除滚动条也没有区别。获得正确结果的唯一方法是在等式中添加15个像素:

var viewportWidth = $(window).width() + 15;

整个等式中唯一的问题是window.width是错误的函数选择,最好是选择例如: document.documentElement.clientWidth或其他什么或......?对于15个像素代表什么,以一点点hacky方式修复了上面的问题?最好的问候拉尔夫

7 个答案:

答案 0 :(得分:47)

这对我有用: CSS media queries and JavaScript window width do not match

不使用包含滚动条的$(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

答案 1 :(得分:24)

答案是滚动条,解决方案很棘手。

媒体查询很有意思。它们在浏览器中的行为并不完全相同,这意味着使用它们有时可能不那么容易。例如,在OS X上的-webkit / -blink和Win8上的IE10中,滚动条覆盖在页面上。但是,在-moz中,滚动条重叠在页面上。获取页面“可视区域”的最佳方法是使用以下的vanilla JavaScript行(假设您有一个有效的HTML文档):

document.body.parentNode.clientWidth

这将是找到body元素,找到它的父元素(在有效文档中将是html元素),然后在渲染后找到它的宽度。这将为您提供您有兴趣看到的宽度。 这也是一个无用的宽度。

您可能会问,为什么实际的客户端宽度无用?这不是因为它因浏览器而异,因为它确实如此。这是因为这不是width媒体查询实际测试的内容! width媒体查询测试的内容 window.innerWidth,这就是您现在实际使用的内容。

那么这个问题的解决方案是什么?好吧,我会说解决方案是使用基于内容的媒体查询而不是基于设备的媒体查询,并且在查询中有一些摆动空间(特别是如果那个摆动空间大约是15px)。如果您还没有,请阅读文章Vexing ViewportsA Pixel Identity Crisis,以了解为什么MQ定义中潜在的15px闪烁不是世界上最糟糕的事情(可能有更大的鱼来煎炸。

因此,最后继续使用$breakpoint-to-ems: true并根据内容何时中断到window.innerWidth选择媒体查询,因为这是处理跨浏览器问题的唯一理智方式。从粗略浏览各种问题看,似乎大多数浏览器和操作系统都在转移到覆盖滚动条(从Firefox 24开始,每个OS X浏览器都会有一个,Ubuntu的Unity UI introduced them),所以为了对未来的友好,我建议不要担心滚动条的偏移量,并且浏览器中的网站看起来略有不同。请记住,正如Ethan Marcotte雄辩地说的那样:

  

网络本质上是不稳定的媒介

答案 2 :(得分:5)

IT是因为scrollbar's

我找到的最正确的解决方案是使用媒体查询将实际窗口大小传递给Javascript。您必须按照以下步骤操作:

  • 向页面添加隐藏元素
  • 使用媒体查询来更改该元素的max-width属性
  • 通过Javascript读回该元素的max-width属性。

例如,将以下元素添加到您的页面:

<div id="currentMedia"></div>

然后编写以下CSS规则:

#currentMedia {
    display: none;
}

@media (max-width: 720px) {
    // Make arrows in the carousel disappear...

    #currentMedia {
        max-width: 720px;
    }
}

然后,从Javascript方面,您可以写:

if (parseInt(jQuery("#currentMedia").css("max-width"), 10) <= 720) {
    // Code HERE..
}

无论滚动条大小如何,它都是准确的,因为该值来自触发轮播消失的相同媒体查询。

我在最近的所有主流浏览器上都测试了这个解决方案,它给出了正确的结果。

您可以找到哪些浏览器on this page on quirksmode.org支持的属性的大摘要。

你最好的选择可能是抓取页面中的元素(使用document.body支持,或者document.getElementById或其他),遍历其offsetParent链以找到最顶层的元素,然后检查该元素的clientWidth和clientHeight。 / p>

innerWidth文档

.innerWidth()方法不适用于windowdocument个对象;对于这些,请改用.width()

答案 3 :(得分:1)

与@ Snugugs的答案类似,但对我的用例更有效:

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... */
    }

然后在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');
    };

getView()函数将返回字符串&#39; mobile&#39;,#39; tablet&#39;或者&#39;桌面&#39;取决于媒体查询的宽度。

这可以扩展到适合更多视口宽度,只需在CSS中添加更多规则和其他值。

答案 4 :(得分:0)

@Snugug的答案给出了一个非常好的解释,为什么会发生这种情况,@ TusharGupta也有一个很好的解决方案,它将mediaquery检测到的宽度引用到javascript。下面的解决方案是使用javascript检测到的宽度来触发布局更改。

如果您需要使用javascript像素宽度检测同步媒体查询,解决问题的一种方法是根据您使用javascript添加的类触发css布局更改。

因此,不要编写mediaqueries,而是编写嵌套在类下的声明,例如:

html.myMobileBP { ... }

在你的javascript / jQuery中,添加如下类:

if ($(window).width() < myMobileBPPixelSize) {
    $("html").addClass("myMobileBP");
}

为了进一步推动这一点,您可能需要考虑缺少javascript支持。定义进一步包含在html.no-js类中的媒体查询,然后使用javascript删除.no-js类并应用上述通过javascript类添加断点的解决方案。

答案 5 :(得分:0)

follow this link

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;
}

答案 6 :(得分:-1)

使用body上的类来定义您是使用移动设备,平板电脑还是桌面,而不是使用像素。

对我来说,它无效document.body.clientWidthinnerWidth。 即使我的js代码必须执行此语句,我的功能也会在1023-1040px之间崩溃:

if($(window).width()<1024)

解决方案是将一个新类别设置为少于1024,并将其命名为“small-res”并使用它而不是我的代码而不是像素验证:

if($(body).hasClass('small-res')) 

我也推荐给你。