防止 100vw 造成水平滚动

76
如果一个元素设置为width: 100vw;,并且存在垂直滚动条,则该元素的宽度将等于视口加上滚动条的宽度。
是否有可能防止这种情况发生?
是否有可能在不禁用整个页面的水平滚动条的情况下防止这种情况?除了更改我的CSS/标记以使元素占据body宽度的100%之外,我想不到任何其他方法。
经过测试,适用于Chrome版本43.0.2357.81m&FF 36.0.1&Opera 20.0.1387.91(在Windows 8.1上)。
如下所示是所需的代码: Example html
<div class="parent">
    <div class="box"></div>
</div>
<div class="tall"></div>

CSS

body { margin: 0; }
html { box-sizing: border-box; }
*, *::before, *::after {
    box-sizing: inherit;
    position: relative;
}
.parent {
    background: rgba(0, 0, 0, .4);
    height: 100px;
    width: 5rem;
    margin-bottom: 25px;
}

.box {
    position: absolute;
    top: 0;
    left: 0;
    background: rgba(0, 0, 0, .4);
    height: 50px;
    width: 100vw;
}

.tall {
    height: 100rem;
}

1
可能有许多原因。发布您的代码。 - Arbel
也许将边距设置为0? - vals
你试过使用 overflow: hidden 吗? - lmgonzalves
13个回答

46

基本上答案是否定的,如果你有垂直滚动条,就没有办法使100vw等于可见视口的宽度。以下是我发现的解决此问题的方法。

警告:我尚未测试这些解决方案的浏览器支持情况


简短摘要

如果您需要一个元素的宽度为可见视口(减去滚动条),则需要将其设置为 body 的 100%。如果有垂直滚动条,则不能使用 vw 单位。


1. 将所有祖先元素设置为 position: static

确保所有 .box 的祖先元素都被设置为 position: static;,然后将 .box 设置为 width: 100%;,这样它就可以占据 body 的100%宽度。不过,有时需要将其中一个祖先元素设置为 position: absolute;position: relative;

示例

2. 将元素移至非静态祖先元素之外

如果无法将祖先元素设置为 position: static;,则需要将 .box 移到它们之外。这样可以将元素设置为 body 的 100% 宽度。

示例

3. 删除垂直滚动条

如果您不需要垂直滚动,则可以通过将 <html> 元素设置为 overflow-y: hidden; 来删除垂直滚动条。

示例

4. 去除水平滚动条 这并不能解决问题,但在某些情况下可能适用。

<html> 元素的样式设置为 overflow-y: scroll; overflow-x: hidden; 可以防止出现水平滚动条,但是 100vw 元素仍会溢出。

示例

视口百分比长度规范

视口百分比长度相对于初始包含块的大小。当初始包含块的高度或宽度发生变化时,它们会相应缩放。但是,当根元素的 overflow 属性值为 auto 时,任何滚动条都被认为不存在。请注意,视口上滚动条的存在会影响初始包含块的大小。

看起来有一个错误,因为 vw 单位只应包括根元素的 overflow 属性值为 auto 时滚动条的宽度。但是我已经尝试将根元素设置为 overflow: scroll; ,但没有改变。

示例


15

由于该 bug 在现代浏览器中仍然存在,本文提供了一种更为完善的方法。在许多情况下,设置 overflow-x: hidden 可能会导致问题或不良反应。

这里提供了一个完整的示例:http://codepen.io/bassplayer7/pen/egZKpm

我的方法是确定滚动条的宽度并使用 calc() 函数将 100vw 减去滚动条的宽度。这有点复杂,因为在我的情况下,我需要从一个定义了宽度的盒子中取出内容的宽度,所以我还需要声明边距。

以下是代码的一些注释:首先,我发现 20px 对于滚动条来说似乎是一个比较普遍的魔数。我使用了一个 SCSS 变量(当然也可以使用其他语言)和 @supports 之外的代码作为回退方案。

此外,这并不能完全保证永远不会出现滚动条。因为它需要 JavaScript,所以未启用 JavaScript 的用户将看到水平滚动条。您可以通过设置 overflow-x: hidden,然后在 JavaScript 运行时添加一个覆盖它的类来解决这个问题。

完整的 SCSS 代码:

$scroll-bar: 20px;

:root {
    --scroll-bar: 8px;
}

.screen-width {
  width: 100vw;
  margin: 0 calc(-50vw + 50%);

    .has-scrollbar & {
        width: calc(100vw - #{$scroll-bar});
        margin: 0 calc(-50vw + 50% + #{$scroll-bar / 2});
    }

    @supports (color: var(--scroll-bar)) {
        .has-scrollbar & {
            width: calc(100vw - var(--scroll-bar));
            margin: 0 calc(-50vw + 50% + (var(--scroll-bar) / 2));
        }
    }
}

通过删除#{$scroll-bar}引用并替换为px值,将上述内容转换为纯CSS。

然后,此JavaScript将设置CSS自定义属性:

function handleWindow() {
    var body = document.querySelector('body');

    if (window.innerWidth > body.clientWidth + 5) {
        body.classList.add('has-scrollbar');
        body.setAttribute('style', '--scroll-bar: ' + (window.innerWidth - body.clientWidth) + 'px');
    } else {
        body.classList.remove('has-scrollbar');
    }
}

handleWindow();

另外提一下,苹果电脑的用户可以通过以下步骤测试:进入“系统偏好设置” -> “通用” -> “滚动条显示”选择“始终”。



9

使用 max-width 属性与 width:100vw,解决了我的问题。

这是我使用的代码:

.full{
     height: 100vh;
     width: 100vw;
     max-width: 100%;
    }

该属性的作用是将最大宽度限制为viewport的大小,从而消除水平滚动条。

更多信息请参考https://www.w3schools.com/cssref/pr_dim_max-width.asp

max-width 属性定义了元素的最大宽度。

如果内容超过最大宽度,元素的高度会被自动调整。

如果内容小于最大宽度,则 max-width 属性无效。


5
可以。不过,width: 100% 的效果与此相同。我看不到它有任何优势。我是否漏掉了什么? - SuperNova
max-width 对我起作用了 - Conor Egan

4

内边距和边框可能会产生影响。外边距也是如此。使用box-sizing属性来计算包括这些属性在内的宽度。如果有必要,可以从宽度中删除外边距。

* {
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
}
body {
    margin: 0; /* interferes with 100vw */
}
.parent {
    width: 100vw;
    max-width: 100%; /* see below */
}
.box {
    width: 100%; /* For those good old-fashioned browsers with no vw or calc() support */
    width: -webkit-calc(100vw - [your horizontal margin, if any]);
    width: -moz-calc(100vw - [your horizontal margin, if any]);
    width: calc(100vw - [your horizontal margin, if any]);
    max-width: 100%
}

如果存在重新布局导致出现滚动条,似乎需要添加max-width: 100%;。这种情况似乎不会发生在没有干扰滚动条的浏览器中(如iOS、OS X、IE 11 Metro),但可能会影响所有其他浏览器。


如果你要使用box-sizing的前缀,那么你肯定也需要一些calc的前缀。 - Bram Vanroy
2
我不明白这如何解决问题。我希望该元素等于100vw减去滚动条宽度,而不是100vw减去其父级边距。你是说vw在计算中加入了边距吗?因为那听起来不正确。 - hal
1
@NiklasBrunberg 这是我期望的行为,但实际上并不是发生的情况。我会尝试组织一个例子。 - hal
我已经根据你的fiddle有了一个可行的解决方案:https://jsfiddle.net/1jh1cybc/4/ 我会更新我的答案。 - Niklas Brunberg
2
@NiklasBrunberg 嗯,但是使用max-width 100%只是覆盖了vw设置的宽度。所以你可以直接将宽度改为100%。我希望宽度实际上是100vw(父元素不一定是视口的100%)。我已经更改了jsfiddle以显示父元素不是100%宽度的问题。 - hal
显示剩余12条评论

3

我曾经也遇到过这个问题,一开始考虑使用CSS变量来解决。但因为CSS变量不支持IE11,所以我尝试了其他方法:

我通过计算滚动条的宽度来解决了这个问题:将body的宽度(不包括滚动条)从window的宽度(包括滚动条)中减去。我将其添加到body的100%中,使用变量plusScrollBar进行实现。

JS:

    // calculate width of scrollbar and add it as inline-style to the body
var checkScrollBars = function() {
    var b = $('body');
    var normalw = 0;
    var scrollw = 0;
    normalw = window.innerWidth;
    scrollw = normalw - b.width();

    var plusScrollBar = 'calc(' + '100% + ' + scrollw + 'px)'
    document.querySelector('body').style.minWidth = plusScrollBar;
}();

CSS:

html{
    overflow-x: hidden;
}

我为什么喜欢这个:它考虑到了不同的滚动条宽度或者不同的滚动条并不被视为保留空间。 :)


FYI - 使用这个需要对其进行调整/去抖动,否则在调整大小/设备旋转时,您的主体将变为固定宽度。 - Steve Perks
100%是流动的 ;) - Cyd

1

我遇到了同样的问题,当我添加以下内容时它被解决了:

html, body { overflow-y: auto; }

我添加了注释:

/* this fixes a 100vw issue, removing the horizontal scrollbar when it's unneeded */

它至少在Firefox、Chrome、Opera和Internet Explorer 11上运行(我使用browserling测试了IE)。
我不知道为什么它能够运行,也不知道它是否在所有情况下都能够运行。
编辑:水平滚动条消失了,但是我注意到仍然可以使用光标键和触摸屏水平滚动...

1
这在Firefox中似乎可以工作,但在Chrome中不行(截至2020年5月26日的最新版本)。 - Inigo

0

overflow-x: clip; 可以完成这个任务。


3
虽然这段代码可能回答了问题,但提供有关它如何以及/或为什么解决问题的附加上下文将改善答案的长期价值。您可以在帮助中心找到有关编写良好答案的更多信息:https://stackoverflow.com/help/how-to-answer。祝你好运! - nima

-1

我曾经遇到过同样的问题。当我将vw单位更改为百分比时,水平滚动条消失了。


1
这将其设置为其父级的百分比。它对您起作用,因为那个时刻的父级碰巧是屏幕宽度的幸运情况。这并不总是正确的,并且无法解决vw的问题。 - Jimbo Jonny

-1
如果您正在使用一个框架(例如ASP.NET),其中可能会有一个包装在HTML周围的父元素,那么将HTML的max-width设置为100%将解决问题,而不使用“创可贴”解决方案overflow-x: hidden
html {
   max-width: 100%;
}

-2

我通过在相关页面添加body{overflow-x:hidden}来解决了我的网站上的这个问题。

在你的示例上也可以使用。


我在我的回答中解决了这个问题。虽然不是一个解决方案,但在某些情况下可能是合适的,因为100vw元素仍将溢出并丢失部分元素。请查看我的回答中的第四点。 - hal

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