Flexbox в CSS
Сравнительно новая модель верстки известная как Flexbox, становится все популярнее. В первую очередь за счет удобного использования при создании каркасов и верстки отдельных элементов HTML страницы. Во вторую, за счет совершенно новых возможностей. В этой статье я попробую разобраться во всех тонкостях Flexbox и доступно поделиться знаниями с вами.
Если говорить коротко, то верстка с Flexbox дает нам простые решения некогда непростых задач. Например, когда нужно выровнять элемент по вертикали, или прижать подвал к низу экрана, или просто вставить несколько блоков в один ряд, так чтобы они занимали все свободно пространство. Подобные задачи решаются и без flex. Но как правило, эти решения больше похожи на «костыли» - приемы использовать css не по назначению. Тогда как с flexbox такие задачи решаются именно так, как задумывает flex-модель.
CSS Flexible Box Layout Module (CSS модуль для макетов с гибкими блоками), коротко flexbox (Флексбокс), создана, чтобы убрать недостатки при создании самых разных HTML конструкций, в том числе адаптированных под разную ширину и высоту, и сделать верстку логичной и простой. А логичный подход, как правило работает в неожиданных местах, там где результат не проверялся - логика наше все!
Flexbox позволяет элегантно контролировать самые разные параметры элементов внутри контейнера: направление, порядок, ширину, высоту, выравнивание вдоль и поперек, распределение свободного места, растяжение и сжатие элементов.
Читайте также: Grid в CSS
- Базовые знания
- CSS свойства Flexbox
- Для контейнера
- display:
- flex-direction:
- flex-wrap:
- flex-flow: direction wrap
- justify-content:
- align-content:
- align-items:
- Для элементов контейнера
- flex-grow:
- flex-shrink:
- flex-basis:
- flex: {grow shrink basis}
- align-self:
- order:
- Заметки
- Примеры Flex верстки
- Поддержка браузерами - 98.3%
- Видео
- Полезные ссылки по Flex
Базовые знания

FlexBox состоит из Контейнера и его Дочерних элементов (items) (гибких элементов).
-
Главная ось - главное направление движения элементов внутри контейнера. Направление главной оси можно изменить с помощью свойства flex-direction. Обратите внимание, что при смене осей, меняются только направления движения блоков внутри, а начало, конец и размер контейнера остаются прежними.
-
Начало и конец главной оси - элементы располагаются от начала и до конца контейнера.
-
Поперечная ось - направление движения элементов, когда они не умещаются в контейнер по направлению главной оси. Поперечная ось всегда перпендикулярна (⊥) главной.
-
Начало и конец поперечной оси - по поперечной оси заполняются ряды от начала и до конца контейнера. В каждом таком ряду располагаются элементы (читайте ниже).
- Размер (главный и поперечный) - базовая величина по которой высчитывается ширина или высота внутренних элементов, если размер указан не точно (указан в процентах или не указан вообще, а элемент должен растянуться или сжаться).
Для включения flexbox, любому HTML элементу достаточно присвоить css свойство display:flex; или display:inline-flex;.
<style> .flex{ display: flex; } </style> <div class="flex"> <div class="item">1</div> <div class="item">2</div> </div>
После включения flex свойства, внутри контейнера создаются две оси: главная и поперечная (перпендикулярная (⊥), кросс ось). Все вложенные элементы (первого уровня) выстраиваются по главной оси. По умолчанию главная ось горизонтальная и имеет направление слева направо (→), а кросс ось соответственно вертикальная и направлена сверху вниз (↓).
Главную и кросс оси можно поменять местами, тогда элементы будут располагаться сверху вниз (↓) и когда перестанут вмещаться в высоту то будут двигаться слева направо (→) - то есть оси просто поменялись местами. При этом начало и конец расположения элементов не меняется - меняются только направления (оси)! Именно поэтому нужно представлять себе оси внутри контейнера. Однако не нужно думать, что есть какие-то там «физические» оси и они на что-то влияют. Ось тут - это только лишь направление движения элементов внутри контейнера. Например, если мы указали выравнивание элементов по центру основной оси и потом изменили направление этой основной оси, то изменится и выравнивание: элементы были в середине по горизонтали, а стали в середине по вертикали... См. пример.
Еще одной важной особенностью Флекс-бокс является наличие рядов в поперечном направлении. Чтобы понять о чем речь, давайте представим что есть главная горизонтальная ось, много элементов и они не «лезут» в контейнер, поэтому переходят на другой ряд. Т.е. контейнер выглядит так: контейнер, внутри него два ряда, в каждом ряду по несколько элементов. Представили? А теперь запомните, что выравнивать по вертикали мы можем не только элементы, но и ряды! Как это работает хорошо видно в примере к свойству align-content. А вот так это выглядит схематически:

CSS свойства, которые могут влиять на модель построения макета: float, clear, vertical-align, columns не работают во flex конструкции. Тут используется другая модель построения макета и эти css свойства просто игнорируются.
CSS свойства Flexbox
Flexbox содержит разные css правила для управления всей flex конструкцией. Одни нужно применять к основному контейнеру, а другие к элементам этого контейнера.
Для контейнера
- display:
Включает flex свойство для элемента. Под это свойство попадает сам элемент и вложенные в него элементы: затрагиваются только потомки первого уровня - они станут элементами flex контейнера.
- flex - элемент растягивается на всю ширину и имеет свое полное пространство среди окружающих блоков. Происходит перенос строк в начале и в конце блока.
- inline-flex - элемент обтекается другими элементами. При этом его внутренняя часть форматируется как блочный элемент, а сам элемент — как встроенный.
flex и inline-flex отличаются тем что по-разному взаимодействуют с окружающими элементами, подобно display:block и display:inline-block.
меню
- flex-direction:
Изменяет направление главной оси контейнера. Поперечная ось меняется соответственно.
- row (default) - направление элементов слева направо (→)
- column - направление элементов сверху вниз (↓)
- row-reverse - направление элементов справа налево (←)
- column-reverse - направление элементов снизу вверх (↑)
Нужно понимать, что при переходе с row на column или с row-reverse на column-reverse меняется только направление осей и больше ничего. Начало и конец расположения блоков остается неизменным (см. картинку в начале). Т.е. если при row элементы начинали свой путь справа/сверху, то при column все останется также - изменится только направление... (см. пример свойства flex-wrap)
меню
- flex-wrap:
Управляет переносом непомещающихся в контейнер элементов.
- nowrap (default) - вложенные элементы располагаются в один ряд (при direction=row) или в одну колонку (при direction=column) независимо от того помещаются они в контейнер или нет.
- wrap - включает перенос элементов на следующий ряд, если они не помещаются в контейнер. Так включается движение элементов по поперечной оси.
- wrap-reverse - тоже что wrap только перенос будет не вниз, а вверх (в обратном направлении).
меню
- flex-flow: direction wrap
Объединяет оба свойства flex-direction и flex-wrap. Они часто используются вместе, поэтому чтобы писать меньше кода было создано свойство flex-flow.
flex-flow принимает значения двух этих свойств, разделенные пробелом. Или можно указать одно значение любого свойства.
/* только flex-direction */ flex-flow: row; flex-flow: row-reverse; flex-flow: column; flex-flow: column-reverse; /* только flex-wrap */ flex-flow: nowrap; flex-flow: wrap; flex-flow: wrap-reverse; /* сразу оба значения: flex-direction и flex-wrap */ flex-flow: row nowrap; flex-flow: column wrap; flex-flow: column-reverse wrap-reverse;
- justify-content:
Выравнивает элементы по основной оси: если direction=row, то по горизонтали, а если direction=column, то по вертикали.
- flex-start (default) - элементы будут идти с начала (в конце может остаться место).
- flex-end - элементы выравниваются по концу (место останется в начале)
- center - по центру (место останется слева и права)
- space-between - крайние элементы прижимаются к краям (место между элементами распределяется равномерно)
- space-around - свободное пространство равномерно распределяется между элементами (крайние элементы не прижимаются к краям). Пространство между краем контейнера и крайними элементами будет в два раза меньше чем пространство между элементами в середине ряда.
- space-evenly - тоже что space-around, только расстояние у крайних элементов до краев контейнера такое же как и между элементами.
меню
- align-content:
Выравнивает ряды, в которых находятся элементы по поперечной оси. То же что justify-content только для противоположной оси.
Заметка: Работает только когда высота контейнера фиксированная (выше чем ряды внутри него).
Т.е. если flex-direction: row, то это свойство будет выравнивать невидимые ряды по вертикали
¦
. Тут важно заметить, что высота блока должна быть задана жестко и должна быть больше высоты рядов иначе сами ряды будут растягивать контейнер и любое их выравнивание теряет смысл, потому что между ними нет свободного места... А вот когда flex-direction: column, то ряды движется по горизонтали→
и ширина контейнера почти всегда больше ширины рядов и выравнивание рядов сразу приобретает смысл...Это свойство мало где нужно и вместо него чаще используется align-items (см.ниже).
- stretch (default) - ряды растягиваются заполняя строку полностью
- flex-start - ряды группируются в верхней части контейнера (в конце может остаться место).
- flex-end - ряды группируются в нижней части контейнера (место останется в начале)
- center - ряды группируются по центру контейнера (место останется по краям)
- space-between - крайние ряды прижимаются к краям (место между рядами распределяется равномерно)
- space-around - свободное пространство равномерно распределяется между рядами (крайние элементы не прижимаются к краям). Пространство между краем контейнера и крайними элементами будет в два раза меньше чем пространство между элементами в середине ряда.
- space-evenly - тоже что space-around, только расстояние у крайних элементов до краев контейнера такое же как и между элементами.
меню
- align-items:
Выравнивает элементы по поперечной оси внутри ряда (невидимой строки). Т.е. сами ряды выравниваются через align-content, а элементы внутри этих рядов (строк) через align-items и все это по поперечной оси. По главной оси такого разделения нет, там нет понятия рядов и элементы выравниваются через justify-content.
- stretch (default) - элементы растягиваются заполняя строку полностью
- flex-start - элементы прижимаются к началу ряда
- flex-end - элементы прижимаются к концу ряда
- center - элементы выравниваются по центру ряда
- baseline - элементы выравниваются по базовой линии текста
Для элементов контейнера
- flex-grow:
Задает коэффициент увеличения элемента при наличии свободного места в контейнере. По умолчанию flex-grow: 0 т.е. никакой из элементов не должен увеличиваться и заполнять свободное место в контейнере.
По умолчанию flex-grow: 0
Примеры:
- Если всем элементам указать flex-grow:1, то все они растянуться одинаково и заполнять все свободное место в контейнере.
- Если одному из элементов указать flex-grow:1, то он заполнит все свободное место в контейнере и выравнивания через justify-content работать уже не будут: свободного места нет выравнивать нечего...
- При flex-grow:1. Если один из них имеет flex-grow:2, то он будет в 2 раза больше, чем все остальные
- Если все flex-блоки внутри flex-контейнера имеют flex-grow:3, то они будут одинакового размера
- При flex-grow:3. Если один из них имеет flex-grow:12, то он будет в 4 раза больше, чем все остальные
Как это работает? Допустим, что контейнер имеет ширину 500px и содержит два элемента, каждый из которых имеет базовую ширину 100px. Значит в контейнере остается 300 свободных пикселей. Теперь, если первому элементу укажем flex-grow:2;, а второму flex-grow: 1;, то блоки займут всю доступную ширину контейнера и ширина первого блока будет 300px, а второго 200px. Объясняется это тем, что доступные 300px свободного места в контейнере распределились между элементами в соотношении 2:1, +200px первому и +100px второму.
Заметка: в значении можно указывать дробные числа, например: 0.5 - flex-grow:0.5
меню
- flex-shrink:
Задает коэффициент уменьшения элемента. Свойство противоположное flex-grow и определяет как элемент должен сжиматься, если в контейнере не остается свободного места. Т.е. свойство начинает работать, когда сумма размеров всех элементов больше чем размер контейнера.
По умолчанию flex-shrink:1
Допустим, что контейнер имеет ширину 600px и содержит два элемента, каждый из которых имеет ширину 300px - flex-basis:300px;. Т.е. два элемента полностью заполняют контейнер. Первому элементу укажем flex-shrink: 2;, а второму flex-shrink: 1;. Теперь уменьшим ширину контейнера на 300px, т.е. элементы должны сжаться на 300px чтобы находится внутри контейнера. Сжиматься они будут в соотношении 2:1, т.е. первый блок сожмется на 200px, а второй на 100px и новые размеры элементов станут 100px и 200px.
Заметка: в значении можно указывать дробные числа, например: 0.5 - flex-shrink:0.5
меню
- flex-basis:
Устанавливает базовую ширину элемента - ширину до того как будут высчитаны остальные условия влияющие на ширину элемента. Значение можно указать в
px, em, rem, %, vw, vh
и т.д. Итоговая ширина будет зависеть от базовой ширины и значений flex-grow, flex-shrink и контента внутри блока. Приauto
элемент получает базовую ширину относительно контента внутри него.По умолчанию: auto
Иногда лучше установить ширину элемента жестко через привычное свойство width. Например, width: 50%; будет означать, что элемент внутри контейнера будет ровно 50%, однако при этом все также будут работать свойства flex-grow и flex-shrink. Такое может быть нужно, когда элемент растягивается контентом внутри него, больше указанного во flex-basis. Пример смотрите в заметках.
flex-basis будет «жестким», если обнулить растяжение и сжатие: flex-basis:200px; flex-grow:0; flex-shrink:0;. Все это можно записать так
flex:0 0 200px;
.
меню
- flex: {grow shrink basis}
Короткая запись трех свойств:
flex-grow flex-shrink flex-basis
.По умолчанию: flex: 0 1 auto
Однако можно указать и одно, и два значения:
flex: none; /* 0 0 auto */ /* число */ flex: 2; /* flex-grow (flex-basis переходит в 0) */ /* не число */ flex: 10em; /* flex-basis: 10em */ flex: 30px; /* flex-basis: 30px */ flex: auto; /* flex-basis: auto */ flex: content; /* flex-basis: content */ flex: 1 30px; /* flex-grow и flex-basis */ flex: 2 2; /* flex-grow и flex-shrink (flex-basis переходит в 0) */ flex: 2 2 10%; /* flex-grow и flex-shrink и flex-basis */
- align-self:
Позволяет изменить свойство align-items, только для отдельного элемента.
По умолчанию: от align-items контейнера
- stretch - элемент растягиваются заполняя строку полностью
- flex-start - элемент прижимаются к началу строки
- flex-end - элемент прижимаются к концу строки
- center - элемент выравниваются по центру строки
-
baseline - элемент выравниваются по базовой линии текста
меню
- order:
Позволяет менять порядок (позицию, положение) элемента в общем ряду.
По умолчанию: order: 0
По умолчанию элементы имеют order: 0 и ставятся в порядке их появления в HTML коде и направления ряда. Но если изменить значение свойства order, то элементы будут выстраиваться в порядке значений: -1 0 1 2 3 .... Например если одному из элементов указать order: 1, то сначала будут идти все нулевые, а потом элемент с 1.
Так можно, например, первый элемент перекинуть в конец, при этом не меняя направление движения остальных элементов или HTML код.
Заметки
Чем отличается flex-basis от width?
Ниже важные различия между flex-basis и width / height:
-
flex-basis работает только для главной оси. Это значит что при flex-direction:row flex-basis контролирует ширину (width), а при flex-direction:column контролирует высоту (height). Смотрите пример.
-
flex-basis применяется только к flex элементам. А значит если отключить flex у контейнера это свойство не будет иметь эффекта.
-
Абсолютные элементы контейнера не участвуют во flex конструкции... А значит, flex-basis не влияет на элементы flex контейнера, если они абсолютны position:absolute. Им нужно будет указать width / height.
- При использовании свойства flex 3 значения (flex-grow/flex-shrink/flex-basis) можно скомбинировать и записать коротко, а для width grow или shrink нужно писать отдельно. Например: flex:0 0 50% == width:50%; flex-shrink:0;. Иногда это просто неудобно.
По возможности все же отдавайте предпочтение flex-basis. Используйте width только когда не подходит flex-basis.
Отличие flex-basis от width - баг или фича?
Контент внутри flex элемента распирает его и не может выйти за его пределы. Однако если установить ширину через width или max-width, а не flex-basis, то элемент внутри flex контейнера сумеет выйти за пределы этого контейнера (иногда нужно именно такое поведение). Пример:
менюПримеры Flex верстки
В примерах нигде не используются префиксы для кроссбраузерности. Сделал я так для удобного чтения css. Поэтому примеры смотрите в последних версиях Chrome или Firefox.
#1 Простой пример с выравниванием по вертикали и горизонтали
Начнем с самого простого примера - выравнивание по вертикали и горизонтали одновременно и при любой высоте блока, даже резиновой.
<div class="parent"> <span class="child">Текст по середине</span> </div> <style> .parent { display: flex; } .child { margin: auto; } </style>
Или так, без блока внутри:
<div class="center-text"> Текст по середине </div> <style> .center-text { display: flex; justify-content: center; align-items: center; } </style>
#1.2 Разделение (разрыв) между элементами флекс блока
Чтобы расположить элементы контейнера по краям и произвольно выбрать элемент после которого будет разрыв, нужно использовать свойство margin-left:auto
или margin-right:auto
.
#2 Адаптивное меню на flex
Сделаем меню в самом верху страницы. На широком экране оно должно быть справа. На среднем выравниваться по середине. А на маленьком каждый элемент должен быть на новой строке.
<div class="nav"> <a href="#">Главная</a> <a href="#">О нас</a> <a href="#">Продукты</a> <a href="#">Контакты</a> </div> <style> .nav { display: flex; justify-content: flex-end; /* разместим справа */ background: #6e9cc3; } .nav a { color:#fff; padding:15px 10px; text-decoration:none; text-align:center; } .nav a:hover { background:#5c8db7; } /* меньше 800px */ @media all and (max-width: 800px) { .nav { justify-content: space-around; } .nav a{ flex-grow:1; /* растягиваться на всю ширину */ } } /* меньше 500px */ @media all and (max-width: 500px) { .nav { flex-direction: column; } } </style>
Перейдите в jsfiddle.net и изменяйте ширину секции «результат»
#3 Адаптивные 3 колонки
Этот пример показывает как быстро и удобно сделать 3 колонки, которые при сужении будут превращаться в 2 и затем в 1.
Обратите внимание, что сделать это можно без использования media правил, все на flex.
<div class="flex"> <div class="item">1</div> <div class="item">2</div> <div class="item">3</div> <div class="item">4</div> <div class="item">5</div> <div class="item">6</div> </div> <style> .flex{ display: flex; flex-wrap: wrap; max-width: 700px; /* макс ширина */ margin: 0 auto; /* выровняем по центру */ } .item{ flex:1 1 calc(33.33% - 30px); /* отнимем margin и скажем растягиваться */ margin:5px; box-sizing:border-box; /* чтобы внутренний отступ не влиял когда там будет текст... */ min-width:170px; /* мин. ширина блока, чтобы переносились на другой ряд */ padding:50px 20px; font-size:400%; text-align:center; background:#b5ced8; /* для красоты */ } </style>
Перейдите в jsfiddle.net и изменяйте ширину секции «результат»
#4 Адаптивные блоки на flex
Допустим нам нужно вывести 3 блока, один большой и два маленьких. При этом нужно чтобы блоки подстраивались под маленькие экраны. Делаем:
<div class="flex"> <div class="mainitem">1</div> <div class="sideitem"> <div class="item">2</div> <div class="item">3</div> </div> </div> <style> .flex{ display: flex; max-width: 700px; /* макс ширина блока */ margin: 0 auto; /* выравниваем блок по центру */ font-size:400%; } .mainitem, .item{ flex-grow:1; /* растягивание элементов */ background:#b5ced8; display: flex; justify-content: center; align-items: center; /* цифры по центру */ } .mainitem{ min-height:300px; /* высота основного блока */ } .sideitem{ /* flex:0 0 150px; */ flex-basis:150px; /* ширина 150 */ flex-shrink:0; /* Убираем уменьшение = 150 */ display: flex; flex-direction: column; } .item{ flex-basis:50%; min-height:150px; margin-left:10px; } .item:first-child{ margin-bottom:10px; } /* меньше 600px */ @media screen and (max-width: 600px) { .flex{ flex-wrap: wrap; } /* для переноса */ .sideitem{ flex-direction:row; flex-basis:100%; } .item{ margin-left:0; margin-top:10px; } .item:first-child{ margin-bottom:0; margin-right:10px; } } /* меньше 450px */ @media screen and (max-width: 450px) { .sideitem{ flex-wrap: wrap; } /* разрешаем перенос */ .item{ flex-basis:100%; } /* на всю ширину */ .item:first-child{ margin-right:0; } } </style>
Перейдите в jsfiddle.net и изменяйте ширину секции «результат»
#5 Галерея на flex и transition
Этот пример показывает как быстро можно сделать симпатичный аккордеон с картинками на flex. Обратите внимание на свойство transition для flex.
<div class="flex"> <div class="item img1"></div> <div class="item img2"></div> <div class="item img3"></div> <div class="item img4"></div> <div class="item img5"></div> </div> <style> .flex { display: flex; overflow:hidden; /*скроем тень*/ } .item { height:300px; flex:20%; /* = flex-basis:20%; */ transition: flex 300ms ease; box-shadow: 0 0 19px 3px #000; margin: 1px; /* красивости тени */ } .item:hover { flex: 0.1 0.1 400px; background-size: 100% 100% } .img1 { background: url('http://lorempixel.com/400/300/cats/1') 0 0 no-repeat; } .img2 { background: url('http://lorempixel.com/400/300/cats/2') 0 0 no-repeat; } .img3 { background: url('http://lorempixel.com/400/300/cats/3') 0 0 no-repeat; } .img4 { background: url('http://lorempixel.com/400/300/cats/4') 0 0 no-repeat; } .img5 { background: url('http://lorempixel.com/400/300/cats/5') 0 0 no-repeat; } </style>
#6 Флекс во флекс (просто пример)
Задача сделать гибкий блок. Так чтобы начало текста в каждом блоке находилось на одной линии по горизонтали. Т.е. при сужении ширины, блоки растут в высоту. Нужно, чтобы картинка была вверху, кнопка всегда внизу, а текст по середине начинался по одной горизонтальной линии...
Для решения этой задачи, сами блоки растягиваются флексом и им установлена максимально возможная ширина. Каждый внутренний блок также является флекс конструкцией, с повернутой осью flex-direction:column; и элемент в середине (где находится текст) растягивается flex-grow:1; чтобы заполнить всё свободное пространство, так достигается результат - текст начинался с одной линии...
Еще примеры
Смотрите здесь alexriz.github.io
менюПоддержка браузерами - 98.3%
Полной поддержки разумеется нет, однако все современные браузеры поддерживают flexbox конструкции. Для некоторых все еще нужно указывать префиксы. Для реальной картины заглянем в caniuse.com и видим, что без префиксов будут работать 96.3% используемых сегодня браузеров, с префиксами 98.3%. Это отличный показатель для того чтобы смело использовать flexbox.
Чтобы знать какие префиксы актуальны на сегодня (июнь. 2019), приведу пример всех flex правил с нужными префиксами:
Лучше если свойства с префиксами будут идти до оригинального свойства.
В этом списке нет ненужных на сегодня (по caniuse) префиксов, но вообще префиксов больше.
Chrome | Safari | Firefox | Opera | IE | Android | iOS |
---|---|---|---|---|---|---|
20- (old) | 3.1+ (old) | 2-21 (old) | 10 (tweener) | 2.1+ (old) | 3.2+ (old) | |
21+ (new) | 6.1+ (new) | 22+ (new) | 12.1+ (new) | 11+ (new) | 4.4+ (new) | 7.1+ (new) |
(new)
- новый синтаксис: display: flex;.(tweener)
- старый неофициальный синтаксис 2011 года: display: flexbox;.(old)
- старый синтаксис 2009 года: display: box;
Видео
Ну и не забывайте про видео, там порой тоже интересно и понятно. Вот парочка популярных:
Полезные ссылки по Flex
-
flexboxfroggy.com - игра обучающая flexbox.
-
Flexplorer - наглядный конструктор flex кода.
- Шпаргалка Flexbox
--
Использовал при написании:
- https://habrahabr.ru/post/242545/
- http://html5.by/blog/flexbox/
- https://css-tricks.com/snippets/css/a-guide-to-flexbox/
- https://www.w3.org/TR/css-flexbox-1/