绝对定位的弹性项目不会从 IE11 的正常流程中移除

Absolutely positioned flex item is not removed from the normal flow in IE11

我们有两个 div 包含内容,第三个 div 是具有绝对位置的背景。

容器是一个 flexbox。

在 Chrome 和 Safari 中一切正常,但 Firefox 和 IE11 因素在绝对定位 div 中,并在 space 之间分配div好像有 3 个 div 连续。

我制作了 jsfiddle 示例。有什么办法可以修复这个错误吗? https://jsfiddle.net/s18do03e/2/

div.container {
  display: flex;
  flex-direction: row;
  width: 100%;
  height: 300px;
  justify-content: space-between;
  width: 100%;
  outline: 1px solid;
}
div.c1 {
  background: #aaeecc;
  width: 100px;
  position: relative;
  z-index: 50;
  top: 20px;
  display: flex;
}
div.c2 {
  background: #cceeaa;
  width: 200px;
  position: relative;
  z-index: 50;
  top: 20px;
  display: flex;
}
div.bg {
  background: #ccc;
  width: 100%;
  height: 100%;
  z-index: 0;
  left: 0px;
  top: 0px;
  position: absolute;
  display: flex;
}
<div class="container">
  <div class="c1">Content 1</div>
  <div class="c2">Content 2</div>
  <div class="bg">Background</div>
</div>

更新:此问题已在 Firefox 中解决(从 2017 年 3 月发布的 v52 开始)。问题在IE11中依然存在


就像你在问题中写的那样:

Firefox calculates absolute positioned div, and distributes space between divs like there are 3 divs in a row.

Firefox 正在考虑第三个 div (.bg),它是绝对定位的 in-flow flex 项目,并将其分解到其 space-between计算。 (IE11 也这样做;Chrome 和 Edge 忽略它。)

显然,这不符合当前的 flexbox 规范:

4.1. Absolutely-Positioned Flex Children

As it is out-of-flow, an absolutely-positioned child of a flex container does not participate in flex layout.

这里有一些解决方法:

为什么不把绝对定位的div移到另外两个之间呢?

而不是这个:

<div class="container">
    <div class="c1">Content 1</div>
    <div class="c2">Content 2</div>
    <div class="bg">Background</div>
</div>

试试这个:

<div class="container">
    <div class="c1">Content 1</div>
    <div class="bg">Background</div>
    <div class="c2">Content 2</div>
</div>

div.container {
  display: flex;
  flex-direction: row;
  width: 100%;
  height: 300px;
  justify-content: space-between;
  width: 100%;
  outline: 1px solid;
}
div.c1 {
  background: #aaeecc;
  width: 100px;
  position: relative;
  z-index: 50;
  top: 20px;
  display: flex;
}
div.c2 {
  background: #cceeaa;
  width: 200px;
  position: relative;
  z-index: 50;
  top: 20px;
  display: flex;
}
div.bg {
  background: #ccc;
  width: 100%;
  height: 100%;
  z-index: 0;
  left: 0px;
  top: 0px;
  position: absolute;
  display: flex;
}
<div class="container">
  <div class="c1">Content 1</div>
  <div class="bg">Background</div>
  <div class="c2">Content 2</div>
</div>

或...从 flex 容器中删除 .bg

<div class="container">
    <div class="c1">Content 1</div>
    <div class="c2">Content 2</div>
</div>
<div class="bg">Background</div>

div.container {
  display: flex;
  flex-direction: row;
  width: 100%;
  height: 300px;
  justify-content: space-between;
  width: 100%;
  outline: 1px solid;
}
div.c1 {
  background: #aaeecc;
  width: 100px;
  position: relative;
  z-index: 50;
  top: 20px;
  display: flex;
}
div.c2 {
  background: #cceeaa;
  width: 200px;
  position: relative;
  z-index: 50;
  top: 20px;
  display: flex;
}
div.bg {
  background: #ccc;
  width: 100%;
  height: 100%;
  z-index: 0;
  left: 0px;
  top: 0px;
  position: absolute;
  display: flex;
}
<div class="container">
  <div class="c1">Content 1</div>
  <div class="c2">Content 2</div>
</div>
<div class="bg">Background</div>

或...使用 flex order 属性 重新排列 flex 项目。

将此添加到您的代码中:

.c2 { order: 1; }

div.container {
  display: flex;
  flex-direction: row;
  width: 100%;
  height: 300px;
  justify-content: space-between;
  width: 100%;
  outline: 1px solid;
}
div.c1 {
  background: #aaeecc;
  width: 100px;
  position: relative;
  z-index: 50;
  top: 20px;
  display: flex;
}
div.c2 {
  background: #cceeaa;
  width: 200px;
  position: relative;
  z-index: 50;
  top: 20px;
  display: flex;
  order: 1;
}
div.bg {
  background: #ccc;
  width: 100%;
  height: 100%;
  z-index: 0;
  left: 0px;
  top: 0px;
  position: absolute;
  display: flex;
}
<div class="container">
  <div class="c1">Content 1</div>
  <div class="c2">Content 2</div>
  <div class="bg">Background</div>
</div>

这是因为 justify-content: space-between; 均匀分布项目 第一个项目在开头,最后一个在结尾。所以只需在 <div class="c1">Content 1</div><div class="c2">Content 2</div> 之间输入 <div class="bg">Background</div> 像这样

<div class="container">
    <div class="c1">Content 1</div>
    <div class="bg">Background</div>
    <div class="c2">Content 2</div>

</div>

你可以在https://developer.mozilla.org/en-US/docs/Web/CSS/justify-content

上看到原因

作为替代方案,您可以在内容选择器中使用 flex 属性:

    div.c1 {
      background: #aaeecc;
      width: 100px;
      position: relative;
      z-index: 50; top: 20px;
      display: flex;

      flex: 1; /* add this */
    }

这将设置 flex-grow。它可能不完全是您所需要的,但也许它可以帮助其他无法重新排序内容 div 或将它们从 flex 包装器中取出的人。

这是演示: https://jsfiddle.net/s18do03e/14/

有时无法重新排序,例如使用 ::before::after 时。在这些情况下,您可以手动 order 元素。

在你的情况下,你需要做:

.c1 {
  order: -1;
}
.c2 {
  order: 10;
}

order 属性 是 flex 规范的一部分,允许您重新订购弹性项目 (reference on MDN)。它非常方便用于多种用途,包括在内。

我使用 -1 因为该值是有序的,所以将其设置为负数可确保它优先于所有其他默认值,并且您不需要为 ::before 指定值。出于同样的原因,使用 10 可确保第二个 div 排在最后,即使您向容器中添加了一堆元素。您可以将其增加到 100 或其他任何值。

不过,Firefox 的行为似乎违反直觉。 position: absolute 通常会删除通常 dom 流程中的元素,我希望该元素也会从 flex 流程中删除,就像在 Safari 和 Chrome 中一样。我不确定规范是否阐明了这一点。