+7 905 265-40-75
Как работает CSS Flexbox: наглядное введение в систему компоновки элементов на веб-странице
Flexbox призван спасти нас от неприятных моментов чистого CSS (например, от вертикального выравнивания), и он отлично справляется со своей задачей. Но разобраться в принципах его работы порой бывает сложно, особенно, если вы новичок.
Основная задача Flexbox — сделать слои гибкими, а работу с ними — интуитивно понятными. Для достижения этой цели он позволяет контейнерам самим решать, как обращаться со своими дочерними элементами, в том числе изменять их размер и расстояние между ними.
Звучит неплохо, но давайте посмотрим, так ли оно гладко на практике. В этой статье мы изучим 5 самых популярных свойств Flexbox, разберемся, что они делают, и как они на самом деле работают.
Display: Flex
Вот пример страницы:
У нас есть 4 разноцветных div’а разных размеров, которые находятся внутри серого div’а. У каждого div’а есть свойство display: block
. Поэтому каждый квадрат занимает всю ширину строки.
Чтобы начать работать с Flexbox, нам нужно сделать наш контейнер flex-контейнером. Делается это так:
1 2 3 |
#container { display: flex; } |
Вроде бы ничего особо и не изменилось — div’ы всего лишь встали в ряд. Но вы сделали что-то действительно мощное. Вы дали вашим квадратам классное свойство, называемое «flex-контекст».
Flex Direction
У flex-контейнера есть две оси: главная ось и перпендикулярная ей.
По умолчанию все предметы располагаются вдоль главной оси: слева направо. Поэтому наши квадраты выровнялись в линию, когда мы применили display: flex
. Однако flex-direction
позволяет вращать главную ось.
1 2 3 4 |
#container { display: flex; flex-direction: column; } |
Важно заметить, что flex-direction: column
не выравнивает квадраты по оси, перпендикулярной главной. Главная ось сама меняет свое расположение и теперь направлена сверху вниз.
Есть еще парочка свойств для flex-direction: row-reverse
и column-reverse
.
Justify Content
Justify-content
отвечает за выравнивание элементов по главной оси.
Вернемся к flex-direction: row
.
1 2 3 4 5 |
#container { display: flex; flex-direction: row; justify-content: flex-start; } |
Justify-content
может принимать 5 значений:
flex-start
;flex-end
;center
;space-between
;space-around
.
Space-between
задает одинаковое расстояние между квадратами, но не между контейнером и квадратами. Space-around
также задает одинаковое расстояние между квадратами, но теперь расстояние между контейнером и квадратами равно половине расстояния между квадратами.
Align Items
Если justify-content
работает с главной осью, то align-items
работает с осью, перпендикулярной главной оси.
Вернемся обратно к flex-direction: row
и пройдемся по командам align-items
:
flex-start
;flex-end
;center
;stretch
;baseline
.
Стоит заметить, что для align-items: stretch
высота квадратов должна быть равна auto
. Для align-items: baseline
теги параграфа убирать не нужно, иначе получится вот так:
Чтобы получше разобраться в том, как работают оси, давайте объединим justify-content
с align-items
и посмотрим, как работает выравнивание по центру для двух свойств flex-direction
:
Align Self
Align-self
позволяет выравнивать элементы по отдельности.
1 2 3 4 5 6 7 |
#container { align-items: flex-start; } .square#one { align-self: center; } // Only this square will be centered. |
Давайте для двух квадратов применим align-self
, а для остальных применим align-items: center
и flex-direction: row
.
Flex-Basis
Flex-basis
отвечает за изначальный размер элементов до того, как они будут изменены другими свойствами Flexbox:
Flex-basis
влияет на размер элементов вдоль главной оси.
Давайте посмотрим, что случится, если мы изменим направление главной оси:
Заметьте, что нам пришлось изменить и высоту элементов. Flex-basis
может определять как высоту элементов, так и их ширину в зависимости от направления оси.
Flex Grow
Это свойство немного сложнее.
Для начала давайте зададим нашим квадратикам одинаковую ширину в 120px:
По умолчанию значение flex-grow
равно 0. Это значит, что квадратам запрещено расти (занимать оставшееся место в контейнере).
Попробуем задать flex-grow
равным 1 для каждого квадрата:
Квадраты заняли оставшееся место в контейнере. Значение flex-grow
аннулирует значение ширины.
Но здесь возникает один вопрос: что значит flex-grow: 1
?
Попробуем задать flex-grow
равным 999:
И… ничего не произошло. Так получилось из-за того, что flex-grow
принимает не абсолютные значения, а относительные.
Это значит, что не важно, какое значение у flex-grow
, важно, какое оно по отношению к другим квадратам:
Вначале flex-grow
каждого квадрата равен 1, в сумме получится 6. Значит, наш контейнер поделен на 6 частей. Каждый квадрат будет занимать 1/6 часть доступного пространства а контейнере.
Когда flex-grow
третьего квадрата становится равным 2, контейнер делится на 7 частей (1 + 1 + 2 + 1 + 1 + 1).
Теперь третий квадрат занимает 2/7 пространства, остальные — по 1/7.
И так далее.
Стоит помнить, что flex-grow
работает только для главной оси (пока мы не поменяем ее направление).
Flex Shrink
Flex-shrink
— прямая противоположность flex-grow
. Оно определяет, насколько квадрату можно уменьшиться в размере.
Flex-shrink
используется, когда элементы не вмещаются в контейнер.
Вы определяете, какие элементы должны уменьшиться в размерах, а какие — нет. По умолчанию значение flex-shrink
для каждого квадрата равно 1. Это значит, что квадраты будут сжиматься, когда контейнер будет уменьшаться.
Зададим flex-grow
и flex-shrink
равными 1:
Теперь давайте поменяем значение flex-shrink
для третьего квадрата на 0. Ему запретили сжиматься, поэтому его ширина останется равной 120px:
Стоит помнить что flex-shrink
основывается на пропорциях. То есть, если у квадрата flex-shrink
равен 6, а у остальных он равен 2, то, это значит, что наш квадрат будет сжиматься в три раза быстрее, чем остальные.
Flex
Flex
заменяет flex-grow
, flex-shrink
и flex-basis
.
Значения по умолчанию: 0 (grow) 1 (shrink) и auto (basis)
.
Создадим два квадрата:
1 2 3 4 5 6 |
.square#one { flex: 2 1 300px; } .square#two { flex: 1 2 300px; } |
У обоих квадратов одинаковый flex-basis
. Это значит, что они оба будут шириной в 300px (ширина контейнера: 600px плюс margin и padding).
Но когда контейнер начнет увеличиваться в размерах, первый квадрат (с большим flex-grow
) будет увеличиваться в два раза быстрее, а второй квадрат (с наибольшим flex-shrink
) будет сжиматься в два раза быстрее.
Как вещи растут и сжимаются
Когда увеличивается первый квадрат, он не становится в два раза больше второго квадрата, и когда уменьшается второй квадрат, он не становится в два раза меньше первого. Это происходит из-за того, что flex-grow
и flex-shrink
отвечают за темп роста и сокращения.
Немного математики
Начальный размер контейнера: 640px. Вычтем по 20px с каждой стороны для padding, и у нас останется 600px, как раз для двух квадратов.
Когда ширина контейнера становится равной 430px (потеря в 210px), первый квадрат (flex-shrink: 1
) теряет 70px. Второй квадрат (flex-shrink: 2
) теряет 140px.
Когда контейнер сжимается до 340px, мы теряем 300px. Первый квадрат теряет 100px, второй — 200px.
Тоже самое происходит и с flex-grow
.
Перевод статьи «How Flexbox works — explained with big, colorful, animated gifs»
Никита Мингалеев, юный падаван