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

235

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

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

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

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>

Рикардо Кастаньеда
источник
1
теперь это исправлено - bugs.chromium.org/p/chromium/issues/detail?id=426898
vsync
3
Это не относится конкретно к OP, но может быть уместно для гуглеров, которые приземляются здесь для «абсолютной высоты отображения сафари 100% не работает» или чего-то подобного. У меня есть элемент , как это внутри гибкого контейнера и должен был указать top:0и left:0иметь вид , как и следовало ожидать.
AlexMA
1
@vsync еще не был исправлен: stackoverflow.com/questions/46226298/…
TylerH

Ответы:

408

Решение

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

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

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

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

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

демоверсия jsFiddle


объяснение

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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удалить ненужную наценку.

Вот пример:

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

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

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

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

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

jsFiddle

Майкл Бенджамин
источник
3
Я исправил проблему, используя высоту: авто
Alfrex92
просто несколько замечаний, взятых из пояснительной ссылки этого замечательного поста - "align-items: stretch" заставляет flex-дочерние элементы расширяться поперек оси контейнера - то есть, чтобы растягивать дочерние элементы до высоты, flex-контейнер должен иметь flex-direction как строка
немного почему
3
Я могу подтвердить, что использование вложенных flex-контейнеров работает лучше всего. Мы неправильно использовали flexbox в нашем меню. Вместо использования flex: 1 и display: flex в родительских контейнерах мы использовали height: 100% в некоторых местах. Все работало, как и ожидалось, после того, как мы заменили соответствующие определения. Спасибо @Michael_B за подсказку! :)
flocbit
1
@JamesHarrington, CSS со временем вырос и стал сложным ;-)
DerMike
Каждое решение должно быть другим ответом. Как я могу голосовать за конкретное решение таким образом?
Jp_
14

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

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

nghiepit
источник
Спасибо, это помогло мне. Сгибают ли дети автоматически растяжку на высоту своего контейнера? Вот почему это работает?
Рис Кенни
@ReeceKenney, да, на твои вопросы. Это объясняется в моем ответе. Смотрите решение № 4.
Майкл Бенджамин
10

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

.container {
    flex: 0 0 auto;
}

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

huseyin39
источник
6

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

Narasinghe
источник
2

У меня была похожая проблема в 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%;
}
Designer023
источник
0

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

Мне удалось получить его на работу, добавляя как 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;
}

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

Карлтон Линдсей
источник