当使用flexbox时,我的sticky元素不再保持粘性定位

260

我卡在这个问题上一段时间,想和大家分享一下 position: sticky + flexbox 的一个坑:

我的粘性div在被嵌套在flexbox容器中之前是工作正常的,但当它被包裹在一个flexbox父容器中时,突然间就不再粘了。

.flexbox-wrapper {
  display: flex;
  height: 600px;
}
.regular {
  background-color: blue;
}
.sticky {
  position: -webkit-sticky;
  position: sticky;
  top: 0;
  background-color: red;
}
<div class="flexbox-wrapper">
  <div class="regular">
    This is the regular box
  </div>
  <div class="sticky">
    This is the sticky box
  </div>
</div>

展示问题的JSFiddle


这种行为在支持“position: sticky”的所有浏览器中都存在,还是只存在于某一个/某些浏览器中? - TylerH
2
@TylerH 我相信所有浏览器都是这样的。在Chrome和Safari中它都是这样运作的。 - bholtbholt
谢谢。我可以确认这个问题和解决方案在 Firefox 中也会发生。 - TylerH
9个回答

504
由于弹性盒子元素默认为stretch,所有元素的高度相同,无法滚动。
align-self: flex-start添加到粘性元素中可将高度设置为自动,从而允许滚动并解决该问题。
目前,这在所有主流浏览器中得到支持,但Safari仍然需要添加-webkit-前缀,而除Firefox以外的其他浏览器在使用position: sticky表格时存在一些问题。

.flexbox-wrapper {
  display: flex;
  overflow: auto;
  height: 200px;          /* Not necessary -- for example only */
}
.regular {
  background-color: blue; /* Not necessary -- for example only */
  height: 600px;          /* Not necessary -- for example only */
}
.sticky {
  position: -webkit-sticky; /* for Safari */
  position: sticky;
  top: 0;
  align-self: flex-start; /* <-- this is the fix */
  background-color: red;  /* Not necessary -- for example only */
}
<div class="flexbox-wrapper">
  <div class="regular">
    This is the regular box
  </div>
  <div class="sticky">
    This is the sticky box
  </div>
</div>

JSFiddle展示解决方案


56
仅当在包含 Flex 元素内滚动时才有效,当滚动整个窗口时它不会固定(至少在 Firefox 中是如此)。因此,对于那些经历矛盾行为的人来说,更有可能是他们有相互矛盾的期望(就像我一样)。 - aequalsb
@aequalsb 你知道如何让它在整个页面滚动时保持固定吗? - Douglas Gaskell
@Douglas 这个问题有误导性,因为它暗示了问题出在 flexbox 上,但实际上问题更多地与包含 sticky 元素有关。看看这个 fiddle:https://jsfiddle.net/9y87zL5c/,其中第二个红框按预期工作,但第一个红框不粘住——所以...这与 flexbox 无关(因此是矛盾的期望)...另外...我添加了一堆胡言乱语,以便更准确地查看结果。 - aequalsb
3
我在 Firefox 87 中使用它没有问题。正常工作。 - Shahriar
1
@Siri女士,使用top: 0top: 100px在Edge中都可以使答案生效。我的Flexbox测试不使用overflowheight。正如答案所示,您绝对需要topalign-self - Goal Man
显示剩余2条评论

88
在我的情况下,一个父容器应用了overflow-x:hidden;,这将破坏position: sticky的功能。您需要删除该规则。 任何父级元素都不应应用上述CSS规则。此条件适用于所有父级元素,但不包括'body'元素。

1
你也不能在html元素上使用overflow-x:hidden - Samuel Liew
1
非常感谢。我总是在使用position: sticky时遇到困难,直到阅读了你的回复,才知道有这个条件存在。:) - Raphael Aleixo
1
@SamuelLiew,是的,你可以在HTML元素上使用overflow-x: hidden; - TheoPlatica
1
哇,这个方法可行!在我的情况下,overflow:hidden是从粘性列的父级三层上设置的。我使用了Bulma的“section”布局助手,它显然应用了overflow:hidden。但是,在我的情况下,不仅应该隐藏overflow-x,还应该隐藏overflow-y。 - alds
2
我刚刚测试了一下:你可以在body标签上使用overflow-x: hidden;,但是你不能在任何其他父元素上使用overflow: hidden; - mateostabio
显示剩余6条评论

34
如果您在父元素中使用了弹性布局,请对要设置为粘性的元素使用align-self: flex-start
position: sticky;
align-self: flex-start;
top: 0;
overflow-y: auto;

但是当使用align-self: flex-start时,例如top: 100px;无效。我该怎么做? - Siri

16

您也可以尝试向flex项目添加一个子div,并将内容放在其中,然后将 position: sticky; top: 0; 分配给该子div。

对于我来说,这在双列布局中非常有效,其中第一列的内容需要粘性并且第二列可以滚动。


完全同意,这是我能找到的最简单可靠的选项。通过控制容器的高度,您还可以控制何时停止粘贴。 - Ibrahim ben Salah

8
对于我的情况,align-self: flex-start(或者justify-self: flex-start)的解决方案不适用。我需要同时保留overflow-x: hidden,因为某些容器会水平滑动。
我的解决方案需要嵌套使用display: flexoverflow-y: auto才能得到所需的行为:
- 标题可以动态调整高度,这可以避免使用position: absolute或者position: fixed - 内容在垂直方向上滚动,但是水平方向上受视图宽度限制 - 粘性元素可以放置在任意高度,停靠在标题底部 - 其他元素可以水平滑动 - 注意:似乎 SO 代码片段工具不能正确地呈现子元素的width以展示水平滑动,或许是我实际布局中的其他设置使其可以正常工作... - 需要一个仅作外壳的包装元素,才能允许父元素带有 overflow-x: hidden 时使overflow-x: auto在子元素中正确工作。

body {
  height: 100vh;
  width: 100vw;
  display: flex;
  flex-direction: column;
}

body>header {
  background-color: red;
  color: white;
  padding: 1em;
}

.content {
  overflow-x: hidden;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}

article {
  position: relative;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
}

.horizontal_slide {
  display: flex;
  overflow-x: auto;
  background-color: lightblue;
  padding: .5em;
}

.horizontal_slide>* {
  width: 1000px;
}

.toolbar {
  position: sticky;
  top: 0;
  z-index: 10;
  background-color: lightgray;
  padding: .5em;
  display: flex;
}
<header>Fancy header with height adjusting to variable content</header>
<div class="content">
  <article class="card">
    <h1>One of several cards that flips visibility</h1>
    <div class="overflow_x_wrapper">
      <div class="horizontal_slide">
        <div>Reason why `overflow-x: hidden` on the parent is required
        </div>
        <div>Reason why `overflow-x: hidden` on the parent is required
        </div>
        <div>Reason why `overflow-x: hidden` on the parent is required
        </div>
      </div>
      <div class="toolbar">Sticky toolbar part-way down the content</div>
      <p>Rest of vertically scrollable container with variable number of child containers and other elements</p>
      <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
        dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
  </article>
  </div>


8

确保flex-wrapper已经设置了高度,并将溢出值设置为auto。然后在粘性元素上添加“align-self: flex-start;”。

.flexbox-wrapper {
  display: flex;
  height: 600px;  //<- nessary,and don't assign with %
  overflow:auto;  //<-fix
}
.regular {
  background-color: blue;
}
.sticky {
  position: -webkit-sticky;
  position: sticky;
  top: 0;
  background-color: red;
  align-self: flex-start; // <-fix
}
<div class="flexbox-wrapper">
  <div class="regular">
    This is the regular box
  </div>
  <div class="sticky">
    This is the sticky box
  </div>
</div>


你拯救了我的一天,谢谢!
  • 一个苦于 CSS 的开发者
- Germain

0

这对我有用,但我不知道它是否是你遇到的问题。 我的问题是当视口太小时,flexbox中居中的内容被隐藏了。

/*this is the wrapper of centered content*/
.section {
    overflow-y: auto;
    max-height: none;
    height: 100%;
    min-height: 100vh; /*optional, can be changed to anything*/
}

<div class="section">
   <div class="content">
      Some long content that is centered....
   </div>
</div>

0
我制作了一个临时的flexbox表格并遇到了这个问题。为了解决它,我只需将粘性标题行放在flexbox之外,就在它之前。

0

根据我的经验,全局解决方案/规则:

不要直接将带有粘性元素的结构放在 { display : flex } 容器中。

相反地(对于弹性布局),将带有粘性元素的表格/ div 放在弹性 子容器 中(例如使用 { flex: 1 1 auto },但不要使用 { display : flex } ),然后一切都应该按预期工作。


2
你能举个例子吗? - Roronoa_D._Law

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