it-swarm.com.ru

Chrome/Safari не заполняет 100% высоты родительского элемента flex

Я хочу иметь вертикальное меню с определенной высотой.

Каждый ребенок должен заполнить рост родителя и иметь выравниваемый по середине текст.

Количество детей случайное, поэтому мне приходится работать с динамическими значениями.

Div .container содержит случайное количество дочерних элементов (.item), которые всегда должны заполнять рост родителя. Для этого я использовал flexbox. 

Для создания ссылок с текстом, выровненным по середине, я использую технику display: table-cell. Но использование табличных дисплеев требует использования высоты 100%.

Моя проблема в том, что .item-inner { height: 100% } не работает в webkit (Chrome). 

  1. Есть ли решение этой проблемы? 
  2. Или есть другой метод, чтобы все .item заполняли высоту родительского элемента текстом, выровненным по вертикали к середине?

Пример здесь jsFiddle, должен быть просмотрен в Firefox и Chrome

.container {
  height: 20em;
  display: flex;
  flex-direction: column;
  border: 5px solid black
}
.item {
  flex: 1;
  border-bottom: 1px solid white;
}
.item-inner {
  height: 100%;
  width: 100%;
  display: table;
}
a {
  background: orange;
  display: table-cell;
  vertical-align: middle;
}
<div class="container">
  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>

  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>

  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>
</div>

164
Ricardo Castañeda

Решение

Используйте вложенные гибкие контейнеры.

Избавьтесь от высоты в процентах. Избавьтесь от свойств таблицы. Избавьтесь от vertical-align. Избегайте абсолютного позиционирования. Просто придерживайтесь flexbox до конца.

Примените display: flex к элементу flex (.item), сделав его контейнером flex. Это автоматически устанавливает align-items: stretch, который говорит дочернему элементу (.item-inner) увеличить полную высоту родительского элемента.

Важно: Удалите указанные высоты из гибких элементов, чтобы этот метод работал. Если для дочернего элемента указана высота (например, height: 100%), он будет игнорировать align-items: stretch, исходящий от родителя. Чтобы stretch по умолчанию работал, рост ребенка должен вычисляться как auto(полное объяснение ). 

Попробуйте это (без изменений в HTML):

.container {
    display: flex;
    flex-direction: column;
    height: 20em;
    border: 5px solid black
}

.item {
    display: flex;                      /* new; nested flex container */
    flex: 1;
    border-bottom: 1px solid white;
}

.item-inner {
    display: flex;                      /* new; nested flex container */
    flex: 1;                            /* new */

    /* height: 100%;                    <-- remove; unnecessary */
    /* width: 100%;                     <-- remove; unnecessary */
    /* display: table;                  <-- remove; unnecessary */  
}

a {
    display: flex;                      /* new; nested flex container */
    flex: 1;                            /* new */
    align-items: center;                /* new; vertically center text */
    background: orange;

    /* display: table-cell;             <-- remove; unnecessary */
    /* vertical-align: middle;          <-- remove; unnecessary */
}
<div class="container">
  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>

  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>

  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>
</div>

jsFiddle demo


Объяснение

Моя проблема в том, что .item-inner { height: 100% } не работает в WebKit (Chrome).

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

10.5 Высота содержимого: свойство height

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

auto
Высота зависит от значений других свойств.

Другими словами, чтобы процентная высота работала с дочерним потоком, у родителя must должна быть заданная высота.

В вашем коде контейнер верхнего уровня имеет определенную высоту: .container { height: 20em; }

Контейнер третьего уровня имеет определенную высоту: .item-inner { height: 100%; }

Но между ними контейнер второго уровня - .item - не имеет определенной высоты. Webkit видит это как недостающую ссылку.

.item-inner говорит Chrome: дай мне height: 100%. Chrome обращается к родителю (.item) для справки и отвечает: 100% чего? Я ничего не вижу (игнорируя существующее там правило flex: 1). В результате применяется height: auto (высота содержимого) в соответствии со спецификацией.

Firefox, с другой стороны, теперь принимает высоту изгиба родителя как ссылку на процентную высоту ребенка. IE11 и Edge также допускают гибкие высоты.

Кроме того, Chrome будет принимать flex-grow в качестве адекватной родительской ссылки , если используется вместе с flex-basis (любое числовое значение работает ( auto не будет), включая flex-basis: 0). Однако на момент написания этой статьи это решение не работает в Safari.

#outer {
  display: flex;
  flex-direction: column;
  height: 300px;
  background-color: white;
  border: 1px solid red;
}
#middle {
  flex-grow: 1;
  flex-basis: 1px;
  background-color: yellow;
}
#inner {
  height: 100%;
  background-color: lightgreen;
}
<div id="outer">
  <div id="middle">
    <div id="inner">
      INNER
    </div>
  </div>
</div>


Четыре решения

1. Укажите высоту для всех родительских элементов

Надежным кросс-браузерным решением является указание высоты для всех родительских элементов. Это предотвращает отсутствие ссылок, которые браузеры на основе Webkit считают нарушением спецификации.

Обратите внимание, что min-height и max-height недопустимы. Это должно быть свойство height.

Подробнее здесь: Работа со свойством CSS height и процентными значениями

2. Относительное и абсолютное позиционирование CSS

Примените position: relative к родителю и position: absolute к ребенку. 

Задайте размер дочернего элемента с помощью height: 100% и width: 100% или используйте свойства смещения: top: 0, right: 0, bottom: 0, left: 0.

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

3. Удалите ненужные контейнеры HTML (рекомендуется)

Есть ли необходимость в двух контейнерах вокруг button? Почему бы не удалить .item или .item-inner, или оба? Хотя элементы button иногда не работают как контейнеры flex , они могут быть элементами flex. Подумайте о том, чтобы сделать button дочерним по отношению к .container или .item и удалить бесплатную разметку.

Вот пример:

.container {
    height: 20em;
    display: flex;
    flex-direction: column;
    border: 5px solid black
}

a {
    flex: 1;
    background: orange;
    border-bottom: 1px solid white;
    display: flex;                   /* nested flex container (for aligning text) */
    align-items: center;             /* center text vertically */
    justify-content: center;         /* center text horizontally */
}
<div class="container">
    <a>Button</a>
    <a>Button</a>
    <a>Button</a>
</div>

4. Вложенные Flex-контейнеры (рекомендуется)

Избавьтесь от высоты в процентах. Избавьтесь от свойств таблицы. Избавьтесь от vertical-align. Избегайте абсолютного позиционирования. Просто придерживайтесь flexbox до конца.

Примените display: flex к элементу flex (.item), сделав его контейнером flex. Это автоматически устанавливает align-items: stretch, который говорит дочернему элементу (.item-inner) увеличить полную высоту родительского элемента.

Важно: Удалите указанные высоты из гибких элементов, чтобы этот метод работал. Если для дочернего элемента указана высота (например, height: 100%), он будет игнорировать align-items: stretch, исходящий от родителя. Чтобы stretch по умолчанию работал, рост ребенка должен вычисляться как auto(полное объяснение ). 

Попробуйте это (без изменений в HTML):

.container {
    display: flex;
    flex-direction: column;
    height: 20em;
    border: 5px solid black
}

.item {
    display: flex;                      /* new; nested flex container */
    flex: 1;
    border-bottom: 1px solid white;
}

.item-inner {
    display: flex;                      /* new; nested flex container */
    flex: 1;                            /* new */

    /* height: 100%;                    <-- remove; unnecessary */
    /* width: 100%;                     <-- remove; unnecessary */
    /* display: table;                  <-- remove; unnecessary */  
}

a {
    display: flex;                      /* new; nested flex container */
    flex: 1;                            /* new */
    align-items: center;                /* new; vertically center text */
    background: orange;

    /* display: table-cell;             <-- remove; unnecessary */
    /* vertical-align: middle;          <-- remove; unnecessary */
}
<div class="container">
  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>

  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>

  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>
</div>

jsFiddle

297
Michael_B

Решение: удалите height: 100% в .item-inner и добавьте display: flex в .item

Демо: https://codepen.io/tronghiep92/pen/NvzVoo

4
nghiepit

У меня была похожая проблема в iOS 8, 9 и 10, и приведенная выше информация не могла ее исправить, однако я нашел решение после дня работы над этим. Конечно, это не будет работать для всех, но в моем случае мои элементы были сложены в столбец и имели нулевую высоту, когда это должна была быть высота содержимого. Переключение css на row и wrap устранило проблему. Это работает, только если у вас есть один предмет, и они сложены, но, так как мне потребовался день, чтобы выяснить это, я решил поделиться своим исправлением!

.wrapper {
    flex-direction: column; // <-- Remove this line
    flex-direction: row; // <-- replace it with
    flex-wrap: wrap; // <-- Add wrapping
}

.item {
    width: 100%;
}
0
Designer023

Для мобильного Safari Есть исправление браузера. вам нужно добавить -webkit-box для устройств iOS.

Ex.

display: flex;
display: -webkit-box;
flex-direction: column;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-webkit-flex-direction: column;
align-items: stretch;

если вы используете свойство align-items: stretch; для родительского элемента, удалите height : 100% из дочернего элемента.

0
Narasinghe