CSS overflow-x: visible; 和 overflow-y: hidden; 导致滚动条问题

650

假设你有一些样式和标记:

ul
{
  white-space: nowrap;
  overflow-x: visible;
  overflow-y: hidden;
/* added width so it would work in the snippet */
  width: 100px; 
}
li
{
  display: inline-block;
}
<div>
  <ul>
    <li>1</li> <li>2</li> <li>3</li>
    <li>4</li> <li>5</li> <li>6</li>
    <li>7</li> <li>8</li> <li>9</li>
    <li>1</li> <li>2</li> <li>3</li>
    <li>4</li> <li>5</li> <li>6</li>
    <li>7</li> <li>8</li> <li>9</li>
    <li>1</li> <li>2</li> <li>3</li>
    <li>4</li> <li>5</li> <li>6</li>
    <li>7</li> <li>8</li> <li>9</li>
  </ul>
</div>

当您查看此内容时,<ul> 底部有一个滚动条,即使我已经为 overflow x/y 指定了 visible 和 hidden 值。(在 Chrome 11 和 Opera 上观察到) 我猜这一定是由于某些 W3C 规范或其他原因导致的,但是我无论如何都想不出为什么。JSFiddle更新:我找到了一种方法来通过添加包装在 ul周围的另一个元素来实现相同的结果。Check it out.

你想要什么样的结果?http://jsfiddle.net/Kyle_Sevenoaks/3xv6A/2/ - Kyle
@kyle,它应该看起来更像这样:http://jsfiddle.net/3xv6A/5/。不幸的是,如果我设置`overflow-x hidden;,它会移除滚动条,但是我需要li元素隐藏底部的边框,以便产生所需的虚线效果。我不明白为什么overflow-x: visible`会创建一个滚动条。据我所知,它不应该这样。 - James Khoury
@JamesKhoury,您能否进一步解释一下您的解决方案?我实在是让它起作用。 - George Katsanos
1
@GeorgeKatsanos 这个解决方法:http://jsfiddle.net/3xv6A/9/,依赖于父元素设置为 overflow: hidden;,并在 <ul> 周围插入一个子元素,使其 overflow: visible - James Khoury
@JamesKhoury 你认为它能在http://embed.plnkr.co/2rbaISwvzuKhyPEFpBKD/上工作吗? - George Katsanos
@JamesKhoury 我仍然在所有提议的解决方案中看到滚动条。也许是新的Chrome bug?或者它应该在那里(看看容器底部)。 - kahlan88
10个回答

924
经过一番搜索,我发现已经找到了我的问题的答案:
来自:http://www.brunildo.org/test/Overflowxy2.html 在 Gecko、Safari 和 Opera 中,当与“hidden”结合使用时,“visible” 也变成了“auto”(换句话说,当与除“visible”之外的任何其他值结合时,“visible” 就会变成“auto”)。Gecko 1.8、Safari 3、Opera 9.5 在这方面非常一致。
同时,W3C 规范也是这样规定的:http://www.w3.org/TR/css3-box/#overflow-x “overflow-x”和“overflow-y”的计算值与它们的指定值相同,但某些“visible”组合不可用:如果一个被指定为“visible”,而另一个被指定为“scroll”或“auto”,则将“visible”设置为“auto”。 如果“overflow-y”与“overflow-x”相同,则“overflow”的计算值等于“overflow-x”的计算值;否则,它是“overflow-x”和“overflow-y”的一对计算值。
简而言之:如果您对其中一个使用“visible”,并且对另一个使用除“visible”之外的其他值,则“visible”值将被解释为“auto”。

389
我理解W3C是这样规定的,但背后的动机是什么?我觉得它的行为相当奇怪和不一致,导致需要添加琐碎的HTML元素来解决问题。 - Erwin
37
我同意Erwin的看法,希望有人决定更新规格。 - James Khoury
181
你说得对,但这没有意义。你想要使用 x 和 y 的最常见原因是让其中一个隐藏而另一个可见。 - rescuecreative
134
这太让人沮丧了。为什么我们不能在overflow-y:hidden的情况下允许overflow-x:visible,而不需要使用父/子级Hack呢?在我看来,这相当不可靠。 - Slink
60
这非常令人沮丧。我试图在 Bootstrap 导航栏中创建一些下拉链接,让它们水平滚动,但这会破坏下拉菜单,因为其需要 overflow-y: visible。可恶的 CSS! - Andy
显示剩余19条评论

207

另一个简单的方法,看起来可以解决问题:

在垂直溢出被截断的元素上添加 style="padding-bottom: 250px; margin-bottom: -250px;",其中 250 表示您下拉菜单所需的像素数量等。


32
这会使水平滚动条向下出现那么远。 - nafg
3
这还会阻止元素下方250像素范围内的指针事件。但我找到了一个解决方法,目前正在使用这个解决方案。 - Chris Chudzicki
2
在我的特定情况下,无法删除position: relative或使用包装器,这是唯一有效的解决方案,尽管它还需要为我想要设置overflow-x: hidden的元素内的子元素添加许多丑陋的边距来补偿这种不正常的填充。虽然这很丑陋,但确实帮了我大忙,所以谢谢! - Philip Stratford
99.9%的人遇到这个问题时,没有将容器变高的选项。 - Ben Racicot
1
这会隐藏滚动条,有什么解决方法吗? - Salil Rajkarnikar
显示剩余2条评论

108

使用Cycle jQuery 插件时,我最初找到了一种绕过此问题的CSS方法。Cycle 使用 JavaScript 将我的幻灯片设置为 overflow: hidden,因此将我的图片设置为 width: 100% 后,图片会竖直裁剪,因此我使用 !important 强制使它们可见,并避免显示幻灯片动画,“overflow: hidden” 设置在幻灯片的容器 div 上。希望这对你有用。

更新 - 新解决方案:

原始问题 -> http://jsfiddle.net/xMddf/1/ (即使我使用 overflow-y: visible,它也变成了“auto”,实际上是“scroll”)。

#content {
    height: 100px;
    width: 200px;
    overflow-x: hidden;
    overflow-y: visible;
}

这个新解决方案 -> http://jsfiddle.net/xMddf/2/ (我找到了一个变通方法,使用wrapper div将overflow-xoverflow-y应用于不同的DOM元素,正如James Khoury在解决visiblehidden组合到单个DOM元素的问题时所建议的。)

#wrapper {
    height: 100px;
    overflow-y: visible;
}
#content {
    width: 200px;
    overflow-x: hidden;
}

17
这如何适用?它似乎在overflow-x或overflow-y上无法工作。 - James Khoury
1
@Macumbaomuetre,这更清晰了,谢谢+1。这与我添加的“更新”类似。最初我无法更改包装div,我的解决方案最终类似于:http://jsfiddle.net/3xv6A/338/。 - James Khoury
13
这个解决方案不适用。问题是 overflow-x:visible;overflow-y:hidden;,而不是反过来。 - Jakobovski
3
它确实有效,你只需要交换应用 overflow-x-y 的位置即可:更新后的演示链接 - Just a student
4
只要包装器因某些原因获得宽度,这个就会失败 - https://jsfiddle.net/ad1941k9/16/ - David Meister
显示剩余6条评论

32

对于我的使用情况,将overflow-x:visible; overflow-y:clip添加到具有溢出的div上似乎可以给我所需的效果:在Y轴隐藏溢出,同时不在X轴上给我滚动条(我有一个旋转木马幻灯片,它在缩放图像之前以全尺寸加载图像,这些图像在加载时占据了页面高度的75%,因此不希望有overflow-y)。

没有必要使用父包装器div,只需在溢出元素上设置固定的height。 我意识到这种解决方案可能并不适用于所有人,但肯定可以帮助一些人。


1
请注意,overflow: clip在Safari上尚未得到支持 - Tim Down
@TimDown 支持已于2022年2月2日添加,但我不确定是否已经生效。请参阅开发人员说明 此处-> https://developer.apple.com/safari/technology-preview/release-notes/以及此处-> https://trac.webkit.org/changeset/288973/webkit/ - Andrew West
是的,我也用过这个,运行良好。 - maiakd
1
@AndrewWest 可能是实时的,但考虑到我认识的很多人由于存储空间而无法进行更新,所以剪辑方法仍被认为是“不支持”的:/ - maiakd
2
现在已经是2023年末了,支持情况看起来相当不错:https://caniuse.com/mdn-css_types_overflow_clip。我认为这是目前最好的解决方案。 - undefined
显示剩余5条评论

19

现在有一种新的解决方法 - 如果你将需要设置overflow-y为visible的容器中的position: relative移除,那么你可以同时设置overflow-y为visible且overflow-x为hidden(或者反之亦然,即设置overflow-x为visible且overflow-y为hidden),只需确保具有可视属性的容器没有相对定位。

请参考CSS Tricks中的这篇文章获取更多详细信息-这对我很有效:https://css-tricks.com/popping-hidden-overflow/


8
如果元素是绝对定位,那么这将需要一些JavaScript来正确定位该元素。 - gaurav5430
1
此时您可以使用 position: fixed。防止祖先元素被定位并不是非常现实。 - sallf

19

我在尝试构建一个拥有固定定位的侧边栏,同时又包含可纵向滚动内容和绝对定位的子元素,并且这些子元素应该显示在侧边栏范围之外时遇到了问题。

我的解决方案是分别将以下属性应用于:

  • 侧边栏元素使用 overflow:visible 属性
  • 侧边栏内部包裹元素使用 overflow-y:auto 属性

请查看下面的示例或在线CodePen

html {
  min-height: 100%;
}
body {
  min-height: 100%;
  background: linear-gradient(to bottom, white, DarkGray 80%);
  margin: 0;
  padding: 0;
}

.sidebar {
  position: fixed;
  top: 0;
  right: 0;
  height: 100%;
  width: 200px;
  overflow: visible;  /* Just apply overflow-x */
  background-color: DarkOrange;
}

.sidebarWrapper {
  padding: 10px;
  overflow-y: auto;   /* Just apply overflow-y */
  height: 100%;
  width: 100%;
}

.element {
  position: absolute;
  top: 0;
  right: 100%;
  background-color: CornflowerBlue;
  padding: 10px;
  width: 200px;
}
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?</p>
<div class="sidebar">
  <div class="sidebarWrapper">
    <div class="element">
      I'm a sidebar child element but I'm able to horizontally overflow its boundaries.
    </div>
    <p>This is a 200px width container with optional vertical scroll.</p>
    <p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?</p>
  </div>
</div>


4
我很确定这与其他人提出的解决方案相同,只是使用了 auto 而不是 hidden - James Khoury
嗨,我有一个类似的问题。请你帮忙看一下这里的问题:https://stackoverflow.com/questions/76568278/overflowx-overflowy-wrapper-div-not-working。谢谢。 - TCL
谢谢,我遇到了一个滚动列表的问题,其中每个项目在悬停时都会放大,所以我需要overflow-y可见,而overflow-x滚动。正如文档中所描述的,主要问题是这两个设置不能混合使用,因为overflow-y将变为auto。将列表设置为overflow: visible可以使元素在容器外部打破而不被剪切(在两个方向上),然后在新的父容器上设置overflow-x: auto,使其在x方向上滚动而不是可见,完美! - undefined

12
我遇到了同样的问题,以下解决方案可行(将样式应用于父级块)。
overflow-y: visible;
overflow-x: clip;

10

我采用了内容 + 包装器的方法,但我做了一些与之前所述不同的事情:我确保我的包装器边界与想要在其中方向上可见的内容边界对齐

重要提示:使用相同边界的内容和包装器,根据各种CSS组合(如positionoverflow-*等),很容易让它在一个浏览器或另一个浏览器上工作,但我从未能够使用这种方法将它们全部正确地处理(Edge、Chrome、Safari等)。

但是当我有像这样的东西:

#hack_wrapper {
    position:absolute; 
    width:100%; 
    height:100%; 
    overflow-x:hidden;
}

#content_wrapper {
    position:absolute; 
    width:100%; 
    height:15%; 
    overflow:visible;
}
<!-- #hack_wrapper div created solely for this purpose --> 
<div id="hack_wrapper">
    <div id="content_wrapper">         
          ... this is an example of some content with far too much horizontal content... like, way, way, way too much content.
    </div>
</div>

所有浏览器都很满意。


2

这是对我有效的方法:

在容器上:

  .container {
      overflow-y: visible;
      overflow-x: clip;
  }

关于包含的项目:
  .item {
      width: 500px; /* any fixed value or it did not render in the browser */
  }

2
非常感谢,我从来没有听说过clip,这对于隐藏一个轴并使另一个轴可见非常有帮助。谢谢,伙计! - undefined

-5
一个非常有效的小技巧,如果您只想要第一行可见(但仍然需要溢出):

将间隙设置得非常高,以便确保第二行被推出屏幕-例如:

gap: 10000rem;

这个方法有点取巧,但对于像桌面导航那样需要溢出菜单的东西非常有效...


1
gap 属性仅适用于弹性盒子布局和网格布局,并且只为此设计。如果您没有使用 display: griddisplay: flex,它将不起作用。 - TylerH

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