CSS-live.ru

Браузерные баги Flexbox

Перевод материала из github-репозитория Flexbugs с разрешения его владельца — Филипа Уолтона.

Этот репозиторий — поддерживаемый сообществом список проблем с flexbox и кроссбраузерных обходных путей для них. Цель такова, что если вы разрабатываете сайт, используя flexbox, и при этом что-то работает не так, как вы ожидали, то здесь вы можете найти решение.

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

Баги и их обходные пути

  1. Минимальный размер по контенту flex-элементов не учитывается
  2. Flex-элементы столбца, которым установлено align-items:center, переполняют свой контейнер
  3. Min-height для flex-контейнера столбца не применяется к его flex-элементам
  4. Сокращенная запись flex с безразмерными значениями flex-basis игнорируется
  5. Flex-элементы столбца не всегда сохраняют внутренние пропорции
  6. Значение flex по умолчанию изменилось
  7. Flex-basis не учитывает box-sizing:border-box
  8. Flex-basis не поддерживает calc()
  9. Элементы <button> не могут быть flex-контейнерами
  10. align-items: baseline не работает с вложенными flex-контейнерами
  11. Объявления минимального и максимального размера не учитываются при переносе флекс-элементов
  12. Строчные элементы не становятся флекс-элементами

1. Минимальный размер по контенту flex-элементов не учитывается

Демо В каких браузерах проявляется Ссылки на баги
1.1.aбаг
1.1.bобходной путь
1.2.aбаг
1.2.bобходной путь
Chrome
Opera
Safari
Chrome #426898
Firefox #1043520

Когда flex-элементы слишком велики, чтобы уместиться в свой контейнер то алгоритм flex-раскладки предписывает этим элементам пропорционально уменьшаться, в соответствии с их свойством flex-shrink. Но вопреки тому, что позволяет большинство браузеров, им не предполагается уменьшаться неограниченно. Они не должны становиться меньше, чем указывают их свойства минимальной высоты и ширины, а если эти свойства не заданы, то их минимальным размером должен быть минимальный размер их содержимого по умолчанию.

В соответствии с текущей спецификацией flexbox:

По умолчанию, flex-элементы не будут уменьшаться сверх минимального размера их содержимого (длина самого длинного слова или элемента с фиксированным размером). Чтобы это изменить, установите свойство min-width или min-height.

Обходной путь

Спецификация flexbox определяет начальное значение flex-shrink как «1», но говорит, что элементы не должны быть меньше их минимального размера содержимого по умолчанию. Можно добиться практически точно такого же поведения, используя значение 0 для flex-shrink вместо 1 по умолчанию. Если элемент уже принимает размер по содержимому, и ему не заданы значения width, height или flex-basis, то при установке flex-shrink:0 он отобразится точно так же — но избежит этого бага.

2. Flex-элементы столбца, которым установлено align-items:center, переполняют свой контейнер.

Демо В каких браузерах проявляется
2.1.aбаг
2.1.bобходной путь
Internet Explorer 10-11 (исправлено в 12+)

При использовании align-items:center для вертикального flex-контейнера содержимое flex-элемента, если оно слишком велико, будет переполнять свой контейнер в IE 10-11.

Чаще всего это можно исправить путём простой установки max-width:100% для flex-элемента. Если у flex-элемента установлен внутренний отступ или граница, то тогда для учета этой области нужно обязательно применить box-sizing:border-box. Если flex-элементу выставлен внешний отступ, то одно лишь box-sizing не сработает, поэтому вместо этого вам понадобится контейнер с внутренним отступом.

3. Min-height для flex-контейнера столбца не применяется к его flex-элементам

Демо В каких браузерах проявляется Ссылки на баги
3.1.aбаг
3.1.bобходной путь
3.2.aбаг
Internet Explorer 10-11 (исправлено в 12+) IE #802625

Чтобы flex-элементы могли определить свой размер и положение, им необходимо знать размер своего контейнера. Например, если предполагается вертикально отцентрировать flex-элемент, ему необходимо знать высоту своего родительского элемента. Также это относится и к flex-элементам, которым указано, чтобы они растянулись на всё оставшееся место.

В IE 10-11 объявления min-height для вертикальных flex-контейнеров служат для определения размера самих контейнеров, но их дочерний flex-элемент, похоже, не знает размер своих родительских элементов. Контейнеры ведут себя так, как если бы для них всех не была установлена высота.

Обходной путь

Сейчас min-height чаще всего устанавливают элементу body, обычно со значением 100% (или 100vh). Поскольку элемент body никогда не будет иметь содержимого после себя, а появление полосы прокрутки при большом объёме контента, обычно, желательное поведение, то замена min-height на height будет почти всегда работать, как показано в демо-примере 3.1.b.

Однако, существуют случаи, когда нет хорошего обходного пути. В демо-примере 3.2.a показан визуальный дизайн, когда применение min-height оправдано необходимо, а замена на height не работает. В таких случаях, вам, возможно, нужно пересмотреть свой дизайн, или прибегнуть к хаку с определением браузера.

4. Сокращенная запись flex с безразмерными значениями flex-basis игнорируется.

Демо В каких браузерах проявляется
3.1.aбаг
3.1.bобходной путь
Internet Explorer 10-11 (исправлено в 12+)

До выхода IE10 спецификация flexbox заявляла, что при использовании сокращённой записи flex для предпочтительного размера flexbox-элементов требуется единица измерения:

Если <предпочтительным размером> является «0», то, чтобы избежать двусмысленности, он должен быть указан с единицей измерения (напр. «0px»); безразмерный ноль будет интерпретироваться как flex-grow или flex-shrink, либо как синтактическая ошибка.

В спецификации это уже не так, но IE 10-11 всё ещё принимают это за правду. Если вы используете объявление flex: 1 0 0 в одном из этих браузеров, это будет ошибкой и целое правило (включая любые свойства flex’oв) будет проигнорировано.

Обходной путь

При использовании сокращённой записи flex, всегда включайте единицы измерения в часть flex-basis. Например: 1 0 0%.

Важно: использование значения flex наподобие 1 0 0px всё ещё может вызвать проблемы, поскольку многие CSS-минимизаторы конвертируют 0px в 0. Чтобы этого избежать, не забывайте использовать 0% вместо 0px, т.к большинство минимизаторов не трогают процентные значения по другим причинам.

5. Flex-элементы столбца не всегда сохраняют внутренние пропорции.

Демо В каких браузерах проявляется
5.1.aбаг
5.1.bобходной путь
Internet Explorer 10-11 (исправлено в 12+)

Вот что говорит спецификация на март 2014 о том, как определяются размеры для flex-элементов:

Для Flex-элемента, у которого overflow не равно visible, это ключевое слово [auto] указывает в качестве минимального размера наименьшее из следующего: (а) размер по минимальному содержимому, б) вычисленная ширина/высота, если это значение определенное.

Демо-пример 5.1.a содержит изображение, высота которого составляет 200, а ширина 500 пикселей. Однако, его контейнер имеет ширину всего 300 пикселей, таким образом, когда изображение масштабируется, чтобы уместиться в эту область, его вычисленная высота должна быть только 120 пикселей. Приведённый выше текст в цитате не позволяет чётко понять, на чём должен быть основан размер flex-элемента по минимальному содержимому, на реальной или на отмасштабированной высоте изображения.

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

Обходной путь

Можно избежать этой проблемы путём добавления контейнера для элемента, чтобы разместить элемент с внутренней пропорцией. Поскольку это действие приводит к тому, что элемент с внутренними пропорциями больше не будет flex-элементом, он будет подбирать размер обычным способом.

6. Значение flex по умолчанию изменилось

Демо В каких браузерах проявляется
6.1.aбаг
6.1.bобходной путь
Internet Explorer 10 (исправлено в 11+)

Когда IE10 разрабатывался, спецификация от марта 2012 говорила, что исходное значение для свойства flex было none, которое преобразовывается в 0 0 auto. Новейшая спецификация устанавливает исходное значение flex в исходные значения его отдельных составляющих, которые соответствуют initial или 0 1 auto. Заметьте, что это означает, что IE 10 использует разное исходное значение flex-shrink (на тот момент это называлось neg-flex в спецификации) в отличие от любого другого браузера. Другие браузеры (включая IE 11) используют исходное значение 1 вместо 0.

Обходной путь

Если вам требуется поддержка IE 10, самым лучшим решением будет всегда явно устанавливать значение flex-shrink или flex для всех flex-элементов. Демо-пример 6.1.a показывает, как неуказание любой из составляющих свойства flex приводит к ошибке.

7. Flex-basis не учитывает box-sizing:border-box

Демо В каких браузерах проявляется
7.1.abug
7.1.bобходной путь
7.1.cобходной путь
Internet Explorer 10-11 (исправлено в 12+)

Явное значение flex-basis (т.е. любое значение кроме auto) должно действовать так же, как width или height.  Оно определяет исходный размер flex-элемента, и тогда другие свойства flexbox’ов позволяют ему растягиваться или сужаться соответственно.

IE 10-11 всегда предполагает модель content-box при использовании flex-basis для определения размера flex-элемента, даже, если этот элемент устанавливается в box-sizing:border-box. Демо-пример 7.1.a показывает, что элемент с flex-basis в 100% переполняет свой контейнер на величину равную его границе + внутренний отступ.

Обходной путь

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

  1. Вместо установки явного значения basis,  используйте auto, а затем установите явную ширину или высоту. Это показано в демо-примере 7.1.b.
  2. Используйте элемент-обертку без границ и отступов, чтобы он работал по модели content-box. Это показано в демо-примере 7.1.c.   

8. flex-basis не поддерживает calc()

Демо В каких браузерах проявляется
8.1.aбаг
8.1.bобходной путь
Internet Explorer 10-11 (исправлено в 12+)
8.2.aбаг
8.2.bобходной путь
Internet Explorer 10 (исправлено в 11+)

IE 10-11 игнорирует функции calc() в сокращённом объявлении flex.  В демо-примере видно, что flex:0 0 calc(100%/3)  не работает в IE.

В IE 10 функция calc() не работает даже в развернутом объявлении flex-basis. (хотя это работает в IE 11+). В демо-примере 8.2.a показано, как flex-basis: calc(100%/3) не работает в IE 10.

Обходной путь

Поскольку этот баг влияет только на сокращённое объявление flex в IE 11, простым обходным путём будет всегда указывать каждую составляющую flex отдельно. Демо-пример 8.1.b предлагает пример этого решения.

Если также нужна поддержка IE 10, тогда вам придется подстраховаться установкой width или height (в зависимости от свойства flex-direction для контейнера). Можно сделать это путём установки свойства flex-basis в auto, которое прикажет браузеру использовать свойство главного размера элемента (т.е. его width или height). Это показано в демо-примере 8.2.b.   

9. Элементы <button> не могут быть flex-контейнерами

Демо В каких браузерах проявляется Ссылки на баги
9.1.aбаг
9.1.bобходной путь
Firefox Firefox #984869

В отличие от элемента <input> с типами «button» или «submit», HTML5-элемент <button> может содержать дочерние элементы. Это позволяет класть внутрь элемента <button> не только текст, но и другие вещи (напр. иконки) без необходимости прибегать к использованию семантически некорректных тегов, типа <div> или <a>. Однако, Firefox не позволяет элементу <button> быть flex-контейнером.

Обходной путь

Простое решение этой проблемы – использовать обёрточный элемент внутри button и применить к нему display:flex. Затем <button> может быть оформлен как обычно.

10. align-items: baseline не работает с вложенными flex-контейнерами

Демо В каких браузерах проявляется Ссылки на баги
10.1.aбаг
10.1.bобходной путь
Firefox Firefox #1146442

В Firefox вложенные flex-контейнеры не влияют на базовую линию, по которой должны выравниваться другие flex-элементы. В демо-примере 10.1.a видно, как строка слева ошибочно выравнивается со второй строкой текста справа. Она должна выравниваться с первой строкой текста, являющейся внутренним flex-контейнером.

Обходной путь

Этот баг влияет только на вложенные контейнеры с display: flex. Если установить вложенным контейнерам display: inline-flex, то всё будет работать так, как ожидалось. Заметьте, что при использовании inline-flex, вам, вероятно, следует установить ширину 100%.

11. Объявления минимального и максимального размера не учитываются при переносе флекс-элементов

Демо В каких браузерах проявляется Ссылки на баги
11.1.абаг
11.1.бобходной путь
Safari Safari #136041

Safari учитывает ограничения максимального и минимального размера при отрисовке флекс-элементов, но не учитывает их при расчете того, сколько элементов должно быть на одной строке в многострочном флекс-контейнере. Он учитывает только значение flex-basis элемента, а если оно равно auto — то его ширину.

Это не дает использовать сокращение flex:1, потому что при этом flex-basis становится равен 0%, а раз браузер считает ширину флекс-элементов нулевой, то в одной строке их поместится неограниченное количество. В примере 11.1.а видно, как это происходит.

Это также затрудняет создание резиновых макетов, в которых флекс-элементы должны быть не больше величины X, но не меньше Y. Поскольку Safari распределяет элементы по строкам без учета максимального/минимального размера, такой план не сработает.

Обходной путь

Единственный способ справиться с этой загвоздкой — задать для flex-basis такое значение, которое заведомо войдет в диапазон между ограничениями максимального и минимального размера (включительно). Если задана только максимальная или минимальная граница размера, задайте это же значение для flex-basis, если заданы обе, значение flex-basis должно быть где-то в этих пределах. Чтобы учесть все возможные ситуации, может понадобиться задать это значение в процентах или менять его с помощью медиавыражений. В примере 11.1.б можно увидеть, как этот баг Safari обходится заданием одинаковых значений для min-width и flex-basis.

12. Строчные элементы не становятся флекс-элементами

Демо В каких браузерах проявляется
12.1.абаг
12.1.бобходной путь

Internet Explorer 10-11 (исправлено в Edge)

В IE10 строчные элементы, в т.ч. псевдоэлементы ::before и ::after, не становятся флекс-элементами. В IE11 это исправлено для обычных строчных элементов, но для псевдоэлементов ::before и ::after баг остался.

Обходной путь

Чтобы избежать этого, достаточно добавить элементам любое значение display, кроме inline, напр. block, inline-block, flex и т.п. В примере 12.1.б видно, как это работает в IE10-11.

Благодарности

Браузерные баги были описаны в качестве дополнения к статье «Упорядочивание багов кроссбраузерности Flexbox». Этот документ поддерживается @philwalton и @gregwhitworth. Если у вас есть какие-либо вопросы или вы хотели бы принять участие, пожалуйста не стесняйтесь обращаться к любому из нас в твиттер.

Содействие

Если вы обнаружили баг flexbox или хотели бы предложить обходной путь, пожалуйста откройте «issue» или предложите «pull request». Не забудьте представить соответствующие тестовые примеры или скриншоты и указать, в каких браузерах баг обнаружен.

P.S. Это тоже может быть интересно:

13 комментариев

  1. Скорее не баг, а недоработка.
    В общем захожу я такой в спеку
    Кручу в самый низ, а там табличка про все свойства. Нахожу там, что order можно анимировать. Думаю — нифига себе надо попробовать. Час просидел в codepen, и что вы думаете Chrome не умеет анимировать order =)
    Вот пруф Codepen
    Firefox справился с этой задачей. Префиксы не помогают.

    1. Вполне себе баг (раз по спеке должно быть можно)! Надо добавить issue в репозиторий Филипу и написать в багтрекер Хрома. Спасибо!

  2. Ребята, такой важный вопрос: есть контейнер, а внутри содержимое. Всё сделано на flex … Проблема в следующем, когда содержимое выростает за пределы экрана, то наверно так как стоит горизонтальное выравнивание по центру результат следующий, я могу проскролить в самый низ и до этой середины документа, всё что выше уходит за верхний предел экрана и его не увидеть никак, тоесть другими словами как бы верхняя граница становится не там где верхняя часть контейнера, а гораздо ниже и скролла вверх нет, тоесть могу увидеть самый низ документа и до определённого момента остальную часть, самый верх скрывается и туда не скролится…

        1. да, по анимации проблема похожа, сейчас попробую понять решение и применить его, хочу сказать, что я подозревал, что это не баг, а отсутствие опыта, я вообще никогда не верстал и начал сразу с flex так как вижу, что новые версии всех браузеров поддержали новую тенденцию flexbox и считаю, что скоро они просто обязаны полностью заменить все алогичные и бредовые решения в вёрстке ) Во всяком случае надеюсь на это, с flex вёрстка превращается в логичное строение блоков, которое, за исключением подобных нюансов, мне стало понятно в течении часа и я уже смог сверстать первую страницу и самое главное имел в голове примерную картину как это сделать из этих блоков. Дофига написал не по теме багов, просто накипело) Знакомые верстальщики пока скептически относятся к этому flexbox — у из-за поддержки браузеров и особенно наверно потому, что они потратили не один год, чтобы накопить решения типа банального вертикального выравнивания, но будет вам уникальный текст

          1. То ли еще будет, когда Grid Layout пойдет в массы! Есть надежда, что довольно скоро. Там, кажется, вообще ограничений не будет:). На мой взгляд, уже есть смысл присматриваться к нему (у нас как раз недавно несколько статей про него вышли:).

              1. Хром достаточно давно поддерживает за флагом. Ходят слухи, что флаг могут убрать уже этой осенью:)

                1. специально для решения проблемы выложил в сеть. Чтобы увидеть БАГ, нужно зарегаться, почта пока не валидируется, поэтому можете использовать хоть w@w.w пароль от 8 знаков, никаких писем, ничего… И всё, потом понажимайте несколько раз кнопку ADD ToDoList, чтобы заполнить вертикально страницу и вы увидете, то о чём я говорил из-за того, что у основного блока html стоит display: flex и он height: 100% все остальные внутри него и могут выравниваться по центру благодаря justify-content: center;. НО, как вы увидете при заполнении страницы контентом, он выравнивает его и скрывает верхнюю часть за пределами видимости и не скролит туда. Поможете мне с этим ? вот ссылка http://todolist.inclouds.com.ua

                  1. Да, похоже, что в данном случае это именно баг, и именно с динамикой, потому что после обновления страницы всё становится на место. Возможно, дело в многократной вложенности флексбоксов разного направления, вынуждающей браузер слишком много всего пересчитывать при изменении размеров внутренней области. Нужно сделать минимальный пример, чтоб с ним можно было пойти жаловаться в багтрекеры браузеров (попытаюсь сам на досуге, но если сделаете раньше — весь веб скажет спасибо:).

                2. зашел под вашим w@w.w посмотрел, всё таки нет всё статично а не динамично, то просто оно так центрирует, что кажется норм, а на самом деле в верху должна быть надпись sing_out, а её нет, вы до неё доберётесь только если поудаляете листы, которые её туда подпирают, так что после перезагрузки страницы всё так же… может это нормальное поведение flex, просто у меня тогда вопрос, как всё таки отцентровать контент по вертикали именно всей страницы, потому как

                  !Если самому наружному блоку я не даю высоту 100%, то он по умолчанию тонкий и внутренние блоки не становятся по центру экрана, а если я наружному дам всё-таки высоту 100%, естественно внутренние центруются относительно него, но происходит эта чихарда со скроллом и скрытым контентов в результате этого центрирования. Получается, что центровать по вертикали вроде можно, но основной блок — по центру экрана нельзя, иначе при увеличении контента — сами видели что будет :-(

  3. Добрый день! Будет ли дополняться статья описаниями новых багов? Столкнулся с багами которые описаны у Филиппа, но нет у Вас

    з.ы. Хотел написать в форму обратной связи, но она не работает

Оставить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

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