如何检测浏览器窗口是否有滚动条?

6
我需要能够检测浏览器窗口是否有滚动条(垂直和水平)。我一直在使用这段代码,但在Firefox 5中它无法可靠地工作。
JFL.GetScrollbarState = function () {
    var myWidth = 0;
    var myHeight = 0;
    if (document.documentElement && document.documentElement.clientWidth) {
        myWidth = document.documentElement.clientWidth;
        myHeight = document.documentElement.clientHeight;
    } else {
        myWidth = document.body.clientWidth;
        myHeight = document.body.clientHeight;
    }
    return ({
        vScrollbar: document.body.scrollHeight > myHeight,
        hScrollbar: document.body.scrollWidth > myWidth
    });
}

有没有更好的方法可以跨浏览器实现这个功能。 我的浏览器目标是 Firefox 4-5、Chrome、Safari 4+ 和 Opera 10+。
如果您想知道为什么需要知道是否存在滚动条,那是因为我有一些旋转的CSS3过渡效果(由于它们的旋转特性),可能会暂时超出当前文档大小的边缘(从而使文档暂时变大)。 如果最初没有滚动条,则CSS3过渡效果可能会在过渡期间导致滚动条出现,然后在过渡结束时消失,从而产生丑陋的滚动条闪烁现象。 如果我知道不存在滚动条,则可以临时添加一个设置overflow-x或overflow-y为hidden的类,并在CSS3过渡期间防止滚动条闪烁。 如果已经存在滚动条,则无需做任何事情,因为它们可能会移动一点,但在过渡期间不会开/关。
额外加分如果能够判断滚动条是否必需并且是否实际存在。

你尝试过使用 offsetHeight 而不是 clientHeight 吗? - kazinix
3个回答

5

在一些浏览器(Safari和IE)中使用David提出的滚动版本时遇到了闪烁问题,因此我采用了这段代码,它没有闪烁问题:

function getScrollBarState() {
    var result = {vScrollbar: true, hScrollbar: true};
    try {
        var root = document.compatMode=='BackCompat'? document.body : document.documentElement;
        result.vScrollbar = root.scrollHeight > root.clientHeight;
        result.hScrollbar = root.scrollWidth > root.clientWidth;
    } catch(e) {}
    return(result);
}

这是我使用的方法的衍生版本,而且这种通用技术在fanfavorite发布的帖子中也有提到。它似乎在我尝试的每个浏览器中都可以工作,即使是IE6。对于我的目的,我希望任何失败都返回有滚动条的消息,所以我以这种方式编写了失败条件。

注意:此代码无法检测CSS是否已经强制启用或禁用滚动条。此代码只能检测是否调用了自动滚动条。如果您的页面可能有控制滚动条的CSS设置,则可以获取CSS并先进行检查。


我发现有些情况下这种方法不起作用。在Chrome 15中,存在一些奇怪的布局情况,其中document.documentElement比document.body要大得多,导致出现滚动条,而此代码仅查看document.body。因此,我又开始寻找一个通用的解决方案,可以在任何地方都能使用。 - jfriend00
此代码检测滚动条是否存在。滚动条可能会被显式设置:body { overflow: scroll; } 或者被显式隐藏 body { overflow: hidden; } 在这种情况下,您的代码会报告一个错误的正面或负面。 - Šime Vidas
1
@ŠimeVidas - 这段代码并不尝试检测滚动条是否手动设置。如果是这种情况或者在您的情况下有可能发生,请先获取CSS并检查。该代码尝试检测是否存在自动滚动条的大小触发器。如果您有更好的方法,请随意发布。 - jfriend00
我发现可以通过评估表达式 window.innerWidth - document.documentElement.clientWidth 来检测垂直滚动条 - 如果存在滚动条,则该值将为 17,否则它将为 0。然而,在 IE7/8 中未实现 window.innerWidth,似乎没有办法在这两个浏览器中检索到该值... :( - Šime Vidas
@ŠimeVidas - 如果您在CSS中明确设置滚动条始终处于开启状态,则您的JavaScript检测滚动条是否开启就更加简单:if (true){ /* 当然它是开启的...您已经这样设置了! */ } :) - Jimbo Jonny


1

这其实很简单。在现代浏览器中都可以使用:

// try scrolling by 1 both vertically and horizontally
window.scrollTo(1,1);

// did we move vertically?
if (window.pageYOffset != 0) {
 console.log("houston, we have vertical scrollbars");
}

// did we move horizontally?
if (window.pageXOffset != 0) {
 console.log("houston, we have horizontal scrollbars");
}

// reset window to default scroll state
window.scrollTo(0,0);

不错!我必须进行适应,以防窗口已经滚动了一些,以保留当前的滚动位置并从那里滚动一个像素。我知道我没有要求在IE中运行,但是对于其他人来说,这在IE9中可以工作,但在IE6中无法工作(我没有尝试过IE7和IE8)。 - jfriend00
我用来在不同地方测试它的 jsFiddle:http://jsfiddle.net/jfriend00/4NhUQ/ - jfriend00
1
FYI,我正在研究如何使它在所有浏览器中运行(只是为了完整性),但事实证明这种技术在IE6中永远不会起作用,因为即使没有滚动条,IE6也会使用scrollTo或scrollBy滚动文档,因此该技术始终认为在IE6中存在滚动条。 - jfriend00
是的,这种技术在任何低于v9版本的IE浏览器中都不起作用。我认为在旧版IE中根本不可能实现它。 - David Titarenco
所以,事实证明这种技术在Safari中存在问题。 window.scrollTo(1,1)和window.scrollTo(0,0)的连续调用会导致窗口在Safari中实际移动。 我在其他浏览器中没有发现任何移动,但在Safari中确实会移动。 这是一个问题,因为我不希望每次查询是否有滚动条时窗口内容都会抖动。 我又回到了寻找好的技术的起点。 真糟糕。 我想取消接受的答案,但SO不允许我这样做。 - jfriend00
如果视窗没有滚动到顶部,这种技术也会出现问题。 - jfriend00

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接