Как работает Flexbox
vladimir чт, 01/31/2013 - 20:24 CSS3
Что такое flexbox?
Flexbox представляет новый способ отображения блоков в макете с помощью css3 и предназначен для облегчения расположения элементов относительно друг друга. В этой статье мы рассмотрим самый новый синтаксис модели flexbox. В последнее время версии браузеров меняются достаточно быстро, так что вы будете в теме, когда модель flexbox будет поддерживаться широко в реальных проектах.
Для чего нужен Flexbox?
Разработчики на протяжении долгого времени использовали таблицы, float-элементы, inline-block и другие CSS свойства, чтобы придать блокам нужное расположение. Однако ни один из вышеперечисленных инструментов не был предназначен для создания сложных страниц и приложений, которые в настоящее время используются почти в каждом проекте. Простые вещи, как вертикальное центрирование, осуществлялись достаточно сложно. Создание же макета на основе жидких сеток вообще считается верхом профессионализма, вот почему широкое распространение получили CSS-фреймворки на основе сеток. Итак, если множество проектов часто используют жидкие сетки, блоки одинаковой высоты, вертикальное центрирование блоков и т.д., то возникает вопрос: "Почему до сих пор нет свойства, которе позволило бы осуществлять эти вещи быстро и просто?"
Целью Flexbox является решение всех этих проблем!
Статус спецификации и поддержка браузерами
Модель flexbox разрабатывается уже четвёртый год. Браузеры используют разные экспериментальные версии спецификации. В сентябре 2012 года 3-я проверка ситаксиса Flexbox группой разработчиков из W3C достигла статуса W3C Candidate. Это означает, что W3C утверждает текущий синтаксис и даёт добро на использование вендорных префиксов браузерами.
История изменений спецификации по Flexbox:
- Июль 2009 Working Draft (display: box;)
- Март 2011 Working Draft (display: flexbox;)
- Ноябрь 2011 Working Draft (display: flexbox;)
- Март 2012 Working Draft (display: flexbox;)
- Июнь 2012 Working Draft (display: flex;)
- Сентябрь 2012 Candidate Recommendation (display: flex;)
Браузеры получили быструю поддержку Flexbox. Chrome 22+, Opera 12.1+, IE10, Firefox >=16 уже поддерживают Flexbox. Я рекомендую использовать один из этих браузеров для просмотра примеров.
Концепция и терминология
Хотя flexbox и создан для облегчения расположения блоков в макете, что в прошлом часто вызывало трудности, а в некоторых ситуациях большие проблемы, потребуется еще определенное время для решения этих задач с помощью Flexbox в реальных проектах. Нюансы терминологии модели могут затруднить её использование. Давайте рассмотрим как работает Flexbox-модель.
Модель Flexbox включает в себя flex-контейнер (flex container) и flex-пункты (flex items). Flex container должен иметь свойство display со значением flex или inline-flex. Со значением flex контейнер представляет из себя блочный элемент, а с inline-flex - строчный (инлайновый).
Пример объявления flex container:
.flex-container { display: -webkit-flex; display: flex; }
Flex container является родителем по отношению к flex items. Flex-пунктов может быть сколько угодно. Всё что находится вне flex-контейнера и внутри flex-пунктов отображается как обычно. Таким образо, Flexbox определяет, как flex-пункты будут расположены внутри flex-контейнера.
Flex линия
Flex items расположены внутри flex container вдоль flex line (flex линии). По умолчанию во flex-контейнере присутствует только одна flex-линия. Вот пример с двумя пунктами, расположенными по умолчанию вдоль flex-линии слева направо:
Flex item 1Flex item 2
.flex-container{ display: -webkit-flex; display: flex; width: 700px; background-color: green; margin: 20px auto; } .flex-item{ background-color: red; width: 100px; height: 100px; margin: 5px; color: #fff; }
Writing modes (режимы отображения содержимого)
Важной частью настройки flexbox является изменение направления flex-линии. По умолчанию направление flex-линии совпадает с направлением текста: слева направо, сверху вниз.
В спецификации появился новый модуль writing modes. Он позволяет менять направление текста справа налево, или даже вертикально.
Данный модуль находтся в стадии разработки, но Chrome поддерживает CSS свойство direction. Если в предыдущем примере установить свойство direction: rtl (справа налево), то изменится не только направление отображения содержимого справа налево, но и direction flex-линии, что приведет к изменению макета.
flex item 1flex item 2
body { direction: rtl; } .flex-container { display: -webkit-flex; display: flex; width: 700px; height: 240px; background-color: green; margin: 10px auto; } .flex-item { background-color: red; width: 100px; height: 100px; margin: 5px; }
Из данного примера можно сделать вывод, почему терминология Flexbox на данный момент настолько абстрактна. Нельзя просто указать “вправо”, “влево”, “вниз”, “вверх” когда мы не имеем понятия на каком языке написана данная страница (возможно на арабском - стиль письма справа налево!).
Главная и поперечная оси
Чтобы не зависеть от режима отображения содержимого direction, Flexbox использует концепцию главной оси и поперечной оси (Main Axis и Cross Axis). Flex-линия следуют по главной оси. Поперечная ось перпендикулярна главной оси. Имена начальных и конечных точек, а также направления каждой оси:
- Main Start
- Main End
- Main Direction (иногда называется Flow Direction)
- Cross Start
- Cross End
- Cross Direction
Перед тем как продолжить, важно понять терминологию главной и поперечной оси. Всё в модели flexbox расположено относительно этих двух осей. Во всех наших примерах режим наложения writing mode был слева направо, сверху вниз. Но вы должны иметь ввиду, что это может быть не всегда так.
Свойства Flex контейнера:
Flex-direction
Свойство flex-direction позволяет менять оси flex-контейнера. По умолчанию свойство flex-direction имеет значение row. В этом случае flex-пункты располагаются в соответствии с режимом writing-mode. Еще раз напомним, что это означает направление слева направо, сверху вниз (по умолчанию).
Другие возможные значения:
- row-reverse: Main Start И Main End меняются местами. Если даже writing-mode указан ltr (слева налево), то flex-пункты все равно будут расположены справа налево.
- column: Главная ось и поперечная ось меняются местами. Если режим отображения содержимого горизонтальный, то flex-пункты все равно будут располагаться вертикально.
- column-reverse: аналогично column только обратный.
Изменим в предыдущем примере свойство flex-direction на column:
flex item 1flex item 2
.flex-container { display: -webkit-flex; display: flex; -webkit-flex-direction: column; flex-direction: column; width: 700px; height: 240px; background-color: green; margin: 10px auto; } .flex-item { background-color: red; width: 100px; height: 100px; margin: 5px; }
Теперь flex-пункты располагаются вертикально.
justify-content
justify-content регулирует расположение flex-пунктов по главной оси. Возможные значения:
- flex-start (по умолчанию)
- flex-end
- center
- space-between
- space-around
Рассмотрим пример с justify-content : center чтобы flex-пункты центрировались по главной оси:
flex item 1flex item 2
.flex-container { display: -webkit-flex; display: flex; -webkit-justify-content: center; justify-content: center; width: 700px; height: 240px; background-color: green; margin: 10px auto; } .flex-item { background-color: red; width: 100px; height: 100px; margin: 5px; }
flex-start, flex-end, и center работают, соединившись вместе по главной оси. А вот space-between и space-around распределяют свободное пространство между flex-пунктами определённым способом. Приведу диаграмму из спецификации, которая показывает распределение justify-content:
align-items
align-items является дополнительным свойством к justify-content. align-items регулирует отображение flex-пунктов относительно перпендикулярной оси. Возможные значения:
- flex-start (по умолчанию)
- flex-end
- center
- baseline
- stretch
Рассмотрим примение свойства align-items:center, которе позволяет flex-пункты вертикально центрировать относительно перпендикулярной оси:
flex item 1flex item 2
.flex-container { display: -webkit-flex; display: flex; -webkit-align-items: center; align-items: center; width: 700px; height: 240px; background-color: green; margin: 10px auto; } .flex-item { background-color: red; width: 100px; height: 100px; margin: 5px; }
Итак, flex-start, flex-end, и center всегда располагаются соединившись вместе. Значение stretch довольно простое: оно заставляет flex-пункты растягиваться от Cross Start до Cross End, то есть по вертикали относительно flex-контейнера. baseline заставляет flex-пункты располагаться по базовой линии. Базовая линия вычисляется исходя из инлайнового содержимого flex-пунктов. Вот лучшее объяснение работы данных значений:
Flex-wrap
Во всех рассмотренных примерах flex-контейнер имел одну flex-линию. Использование свойства flex-wrap позволит создать flex-контейнер с разным количеством flex-линий. Возможные значения:
- nowrap (по умолчанию)
- wrap
- wrap-reverse
Если во flex-wrap установлено значение wrap, то во flex-пункты включаются дополнительные flex-линии, но только в том случае, если flex-пунктам не хватает пространства для расположения на одной flex-линии. Дополнительные flex-линии добавляются в направлении перпендикулярной оси.
Пример использования flex-wrap:
flex item 1flex item 2flex item 3
.flex-container { display: -webkit-flex; display: flex; -webkit-flex-wrap: wrap; flex-wrap: wrap; width: 700px; height: 240px; background-color: green; margin: 10px auto; } .flex-item { background-color: red; width: 300px; height: 100px; margin: 5px; }
Значение wrap-reverse аналогично значению wrap за исключением того, что новые flex-линии добавляются в обратном направлении по перпендикулярной оси.
align-content
align-content изменяет поведение свойства flex-wrap. Это значение аналогично align-items только вместо выравнивания flex-пунктов, оно выравнивает flex-линии. Как и можно было ожидать, значения аналогичные:
- stretch (по умолчанию)
- flex-start
- flex-end
- center
- space-between
- space-around
Принцип работы этих значений аналогичный justify-content и align-items.
Пример align-content: center
flex item 1flex item 2flex item 3
.flex-container { display: -webkit-flex; display: flex; -webkit-flex-wrap: wrap; flex-wrap: wrap; -webkit-align-content: center; align-content: center; width: 700px; height: 240px; background-color: green; margin: 10px auto; } .flex-item { background-color: red; width: 300px; height: 100px; margin: 5px; } .first { -webkit-order: -1; order: -1; }
flex-flow
Данное свойство компонует в себя свойства flex-direction и flex-wrap.
flex-flow: [flex-direction] [flex-wrap]
Пример:
.flex-container { -webkit-flex-flow: column nowrap; flex-flow: column nowrap; }
Свойства flex-пунктов (flex items)
Flex-пункт является дочерним блоком по отношению к flex-контейнеру. Содержимое flex-контейнера относится к flex-пункту этого контейнера. Содержимое flex-пункта отображается как обычно. Например, пока действует свойство float, flex-пункты никак на это не реагируют. Плавающие также могут находиться внутри самого flex-пункта.
Как говорят, flex-пункты имеют Main Size и Cross Size. Main Size – это размер flex-пункта в направлении главной оси, а Cross Size - в направлении поперечной оси. Фактически, шириной или высотой flex-пункта могут быть Main Size и Cross Size в зависимости от оси flex-контейнера.
Рассмотрим свойства, которые регулируют поведение flex-пунктов.
Order
Order является простейшим свойством. Порядок расположения flex-пунктов обеспечивается расположением flex-пунктов в HTML. В этом примере мы изменим значение свойства order одного flex-пункта на -1 и посмотрим, как при этом поменяется порядок расположения других flex-пунктов.
flex item 1flex item 2flex item 3
.flex-container { display: -webkit-flex; display: flex; -webkit-flex-wrap: wrap; flex-wrap: wrap; -webkit-align-content: center; align-content: center; width: 700px; height: 240px; background-color: green; margin: 10px auto; } .flex-item { background-color: red; width: 300px; height: 100px; margin: 5px; } .first { -webkit-order: -1; order: -1; }
Это свойство может оказаться полезным для доступности, когда порядок следования flex-пунктов в HTML должен быть одним, а вывод flex-пунктов на дисплее другим.
Margin
Наверняка вам знаком эффект margin: auto. Flexbox выполняет нечто подобное, но с еще более широкими возможностями. “auto” поглащает лишнее пространство. Это свойство может использоваться для разнообразного позиционирования flex-пунктов.
Например, объявим margin-right: auto; для первого flex-пункта, при этом он предоставит всё возможное свободное пространство справа от себя:
flex item 1flex item 2flex item 3
.flex-container { display: -webkit-flex; display: flex; -webkit-align-content: center; align-content: center; width: 700px; height: 240px; background-color: green; margin: 10px auto; } .flex-item { background-color: red; width: 100px; height: 100px; margin: 5px; } .flex-item:first-child{ margin-right: auto; }
Теперь посмотрим на примере как работает margin: auto
flex item 1
.flex-container { display: -webkit-flex; display: flex; -webkit-align-content: center; align-content: center; width: 700px; height: 240px; background-color: green; margin: 10px auto; } .flex-item { background-color: red; width: 100px; height: 100px; margin: 5px; } .flex-item:first-child{ margin: auto; }
align-self
Свойство align-self пункта служит для перекрытия свойства align-items flex-контейнера. Возможные значения аналогичные align-items:
- stretch (по умолчанию)
- flex-start
- flex-end
- center
- baseline
В этом примере мы назначим пунктам различные значения свойства align-self:
flex-startflex-endcenterbaselinestretch
.flex-container { display: -webkit-flex; display: flex; -webkit-align-content: center; align-content: center; width: 700px; height: 240px; background-color: green; margin: 10px auto; } .flex-item { background-color: red; width: 100px; min-height:70px; margin: 5px; } .item1 { -webkit-align-self: flex-start; align-self: flex-start; } .item2 { -webkit-align-self: flex-end; align-self: flex-end; } .item3 { -webkit-align-self: center; align-self: center; } .item4 { -webkit-align-self: baseline; align-self: baseline; } .item5 { -webkit-align-self: baseline; align-self: baseline; padding: 2em 0; } .item6 { -webkit-align-self: stretch; align-self: stretch; }
flex
Наконец-то мы дошли до свойства flex во Flexbox. Flex определяет,как flex-пункты будут использовать свободное пространство по главной оси. Рассмотрим каждое из возможных значений.
Flex:[number]
Такой синтаксис указывает какую часть должен занимать flex-пункт от общей ширины flex-контейнера. В следующем примере первый flex-пункт будет занимать 2/4 свободного места, а остальные два flex-пункта по 1/4:
flex: 2flex: 1flex: 1
.flex-container { display: -webkit-flex; display: flex; -webkit-align-content: center; align-content: center; width: 700px; height: 240px; background-color: green; margin: 10px auto; } .flex-item { background-color: red; width: 100px; min-height:70px; margin: 5px; } .item1 { -webkit-flex: 2; flex: 2; } .item2 { -webkit-flex: 1; flex: 1; } .item3 { -webkit-flex: 1; flex: 1; }
Часто приходится равномерно распределять элементы по ширине. Для этого достаточно задать значение данного свойства 1 и все flex-пункты распределятся по ширине контейнера.
flex: 2flex: 1flex: 1
.flex-container { display: -webkit-flex; display: flex; -webkit-align-content: center; align-content: center; width: 700px; height: 240px; background-color: green; margin: 10px auto; } .flex-item { background-color: red; width: 100px; min-height:70px; margin: 5px; } .item1 { -webkit-flex: 1; flex: 1; } .item2 { -webkit-flex: 1; flex: 1; } .item3 { -webkit-flex: 1; flex: 1; }
flex: initial
Flex-пункты с данным значением будет иметь строго фиксированную ширину, но только при наличии свободного пространства (при необходимости уменьшиться в размере - становится резиновым).
flex: auto
Flex-пункты становятся полностью резиновыми вдоль главной оси. Не корректно работает в Chrome 23.0.1271.95, поэтому лучше использовать flex: 1.
flex: none
flex-пункты становятся фиксированной ширины при всех ситуациях
advanced flex
Свойство flex можно использовать в режиме сокращения для придания спецефичности выбора flex-grow, flex-shrink, и flex-basis в одном объявлении: flex: [flex-grow] [flex-shrink] [flex-basis]
В большинтсве случаев не требуется такой синтаксис. Более того, для применения данного сокращения необходимо глубокое понимание модели Flexbox. Вы можете сделать каждое из свойств flex-grow, flex-shrink, и flex-basis специфичным. Я настоятельно рекомендую не использовать данное сокращение: по умолчанию придаются более разумные значения.
visibility
Когда реализуется свойство visibility: collapse; оно будет отличаться от значений visibility: hidden; и display: none; для flex-пунктов. Со значением collapse элемент задействует Cross Size flex-контейнера, но затрагивать пространство главной оси не будет. Это может быть полезным для динамического добавления или удаления flex-пунктов без оказания влияния на Cross Size flex-контейнера.
В настоящее время visibility: collapse; не коррексно работает в браузерах. На данный момент visibility: collapse; выполняет тоже самое что и visibility: hidden; Я уверен, что в ближайшее время ситуация изменится.
Посмотреть, как должно работать значение collapse в спецификации (http://www.w3.org/TR/css3-flexbox/#visibility-collapse)
Заключение
Как вы понимаете, Flexbox представляет мощное средство конструирования макетов. Он требует совершенно нового подхода для отображения блоков. Надеюсь, эта статья стала полезной для вас и вы сможете уже сейчас начать экспериментировать с макетами с помощью Flexbox. Будущее этой модели действительно потрясающее.
- Войдите, чтобы оставлять комментарии
Комментарии
Информацию по последним изменениям и новым свойствам модуля Flexbox можно получить на сайте W3C
Спасибо за статью!
О такой концепции слышу впервые
Интересная штука, решает много проблем. Вопрос следующий: насколько реально использовать флексы под проект ориентированный на 10-го ослика и выше? Или лучше повременить(?)
Алексей, с вендорным префиксом -ms можете использовать под 10 осла уже сейчас. Я сам еще ни разу в реальных проектах не использовал, думаю есть смысл на всякий случай еще подождать немного, пока окончательно вся спецификация устаканится. С другой стороны caniuse.com показывает, что хром и лиса уже без префиксов понимают флекс, что тоже уже много что значит!
Огромное спасибо за поэтапный, разжеванный материал!
Пожалуйста:)