Chrome / Safari не заполняет 100% высоту родителя flex

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

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

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

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

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

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

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

пример здесь jsFiddle, следует просмотреть в Firefox и Хром

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

3 ответов


Проблема

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

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

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

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

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

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

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

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

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

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

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

кроме того, 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 элементы иногда терпят неудачу как контейнеры 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 к пункту флекс (.item), что делает его контейнер. Это автоматически устанавливает align-items: stretch, который говорит ребенку (.item-inner), чтобы расширить полную высоту родителя.

важно: удалите указанные высоты из элементов flex для работы этого метода. если у ребенка указана высота (например,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


Решение: Удалить height: 100% на .пункт-внутренний и добавить display: flex на .пункт

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


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

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

.item {
    width: 100%;
}