我的立场:使用 flexbox 时粘性元素不粘

My position: sticky element isn't sticky when using flexbox

我被困在这个问题上了一会儿,我想我会分享这个 position: sticky + flexbox 陷阱:

我的粘性 div 在我将视图切换到 flex box 容器之前工作正常,突然 div 在包裹在 flexbox parent 中时不粘了。

.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 showing the problem

由于弹性框元素默认为 stretch,因此所有元素的高度都相同,无法滚动。

向粘性元素添加 align-self: flex-start 将高度设置为自动,允许滚动,并修复它。

目前这在所有主流浏览器中都是 supported,但 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 showing the solution

您也可以尝试将子 div 添加到包含内容的 flex 项目,然后将 position: sticky; top: 0; 分配给它。

这对我来说适用于双列布局,其中第一列的内容需要粘性,第二列显示为可滚动。

在我的例子中,其中一个父容器应用了 overflow-x: hidden;,这将破坏 position: sticky 功能。您需要删除该规则。

任何父元素都不应应用上述 CSS 规则。此条件适用于(但不包括)'body' 元素的所有父元素。

我制作了一个临时的 flexbox table 并遇到了这个问题。为了解决这个问题,我只是将粘性的 header 行放在 flexbox 的外面,就在它之前。

对于我的情况,align-self: flex-start(或justify-self: flex-start)解决方案不起作用。我还需要保留 overflow-x: hidden,因为有些容器会水平滑动。

我的解决方案需要嵌套 display: flexoverflow-y: auto 以获得所需的行为:

  • header可以动态调整高度,防止玩position: absoluteposition: fixed
  • 内容垂直滚动,水平受限于视图宽度
  • 粘性元素可以在垂直方向的任何位置,粘在 header
  • 的底部
  • 其他元素可以水平滑动
    • 看起来 SO 片段工具无法在 child 元素上呈现 width 以正确演示水平滑动,或者我的实际布局上可能有一些其他设置使其工作。 ..
    • 请注意,为了让 overflow-x: auto 在具有 overflow-x: hidden
    • 的 parent 下的元素中正常工作,需要一个不执行任何其他操作的包装器元素

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>

根据我的经验,全球 solution/rule:

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

相反(对于 flex 布局)将带有粘性元素的 tables/divs 放在 flex 子容器 中(例如使用 { flex: 1 1 auto },但是 without { display : flex } ), 那么一切都应该按预期工作。

如果您在父元素中使用 flex,请对要设置粘性的元素使用 align-self: flex-start

position: sticky;
align-self: flex-start;
top: 0;
overflow-y: auto;