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>

4 ответа

Решение

Эта проблема

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

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

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

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

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

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

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

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

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

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

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

Также Chrome примет flex-grow в качестве адекватной родительской ссылки, если используется в сочетании с flex-basis (работает любое значение, в том числе 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 элементы иногда терпят неудачу как гибкие контейнеры, они могут быть гибкими элементами. Рассмотреть вопрос о создании 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. Вложенные гибкие контейнеры (рекомендуется)

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

Применять display: flex к гибкому элементу (.item), делая его гибким контейнером. Это автоматически устанавливает 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

У меня сработало указание атрибута flex для контейнера:

.container {
    flex: 0 0 auto;
}

Это гарантирует, что высота установлена ​​и не увеличивается.

Решение: Удалить height: 100% in .item-inner and add display: flex in .item

Demo: https://codepen.io/tronghiep92/pen/NvzVoo

Для мобильного 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% от дочернего элемента.

У меня была похожая проблема в 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%;
}

У меня была похожая ошибка, но при использовании фиксированного числа для высоты, а не в процентах. Это также был гибкий контейнер внутри тела (не имеющий заданной высоты). Оказалось, что в Safari мой гибкий контейнер по какой-то причине имел высоту 9 пикселей, но во всех других браузерах он отображал правильную высоту 100 пикселей, указанную в таблице стилей.

Мне удалось заставить его работать, добавив оба height а также min-height свойства в класс CSS.

Следующее работало для меня как в Safari 13.0.4, так и в Chrome 79.0.3945.130:

.flex-container {
  display: flex;
  flex-direction: column;
  min-height: 100px;
  height: 100px;
}

Надеюсь это поможет!

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