Абсолютно позиционированный элемент Flex не удаляется из нормального потока в IE11

У нас есть два div с содержимым и третий div, который является фоном с абсолютной позицией.

Контейнер представляет собой флексбокс.

Все отлично работает в Chrome и Safari, но Firefox и IE11 учитывают абсолютный позиционированный div и распределяет пространство между 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>

4 ответа

Решение

Это происходит потому что justify-content: space-between; Распределение предметов равномерно Первый элемент в начале, последний в конце. Так что просто удар <div class="bg">Background</div> между <div class="c1">Content 1</div> а также <div class="c2">Content 2</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

ОБНОВЛЕНИЕ: Эта проблема была решена в Firefox (начиная с версии v52, выпущенной в марте 2017 года). Проблема все еще существует в IE11.


Как вы написали в вопросе:

Firefox вычисляет абсолютный позиционированный div и распределяет пространство между div, как в строке 3 div.

Firefox рассматривает третий div (.bg), который является абсолютно позиционированным, гибким элементом в потоке и делит его на свои space-between расчет. (IE11 делает это тоже; Chrome и Edge игнорируют это.)

Понятно, что это не соответствует текущей спецификации flexbox:

4.1. Абсолютно позиционированные гибкие дети

Поскольку это вне потока, абсолютно позиционированный дочерний элемент гибкого контейнера не участвует в гибком макете.

Вот некоторые обходные пути:

Почему бы не переместить абсолютно позиционированный 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>

ИЛИ... удалить .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>

ИЛИ... используйте гибкий order свойство переупорядочивать гибкие элементы.

Добавьте это к своему коду:

.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>

Иногда невозможно изменить порядок вещей, например, при использовании ::before а также ::after, В этих случаях вы можете вручную order элементы.

В вашем случае вам нужно будет сделать:

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

order собственность является частью flex spec и позволяет вам переупорядочивать flex-элементы ( ссылка на MDN). Это очень удобно для нескольких целей, в том числе.

я использовал -1 поскольку значение является порядковым, поэтому установка его в отрицательное число гарантирует, что оно предшествует всем другим значениям по умолчанию, и вам не нужно указывать значение для ::before, По той же причине, используя 10 гарантирует, что второй div будет последним, даже если вы добавите кучу элементов в контейнер. Вы можете увеличить это до 100 или что угодно.

Тем не менее, поведение Firefox кажется нелогичным. position: absolute обычно удаляет элемент для обычного потока DOM, и я ожидаю, что этот элемент будет удален из flex текут так же, как в Safari и Chrome. Я не уверен, что спецификация проясняет это.

В качестве альтернативы вы можете использовать свойство flex внутри селектора контента:

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

      flex: 1; /* add this */
    }

Это установит flex-grow. Это может быть не совсем то, что вам нужно, но, возможно, это поможет кому-то еще, кто не может переупорядочить элементы содержимого или извлечь их из flex-оболочки.

Вот демоверсия: https://jsfiddle.net/s18do03e/14/

Другие вопросы по тегам