Menu

flex-wrap и flex-direction в CSS: строки, колонки, перенос

flex-wrap решает, сжимаются ли flex-элементы в одну строку или переходят на следующую, а flex-direction решает, идут ли они строкой или колонкой. Разберем оба свойства на живых примерах, сокращение flex-flow, align-content и адаптивный ряд карточек без медиазапросов.

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

flex-wrap: одна строка или сколько нужно

По умолчанию flex-контейнер держит все элементы в одной строке (flex-wrap: nowrap) и сжимает их, чтобы они поместились. flex-wrap: wrap позволяет им сохранить размер и перейти на следующую строку:

Каждый элемент просит 100px, их пять в блоке шириной 340px. Пяти элементам и четырем промежуткам по 8px нужно 532px, поэтому без переноса каждый элемент сжимается примерно до 62px: flex-элементы по умолчанию сжимаются. С wrap они остаются по 100px: три помещаются в первой строке, а два других переходят во вторую.

Значения flex-wrap

ЗначениеЧто происходит
nowrap (по умолчанию)Одна строка. Элементы сжимаются, а когда сжиматься дальше не могут, вылезают за контейнер
wrapЭлементы, которые не помещаются, начинают новую строку ниже
wrap-reverseТо же, но новые строки складываются вверх: первая строка оказывается внизу

Посмотрите, как элементы переносятся

Двигайте ползунок, чтобы менять ширину контейнера. Счетчик показывает число строк и сколько элементов в каждой:

При 400px в строку помещаются четыре элемента по 90px и три промежутка по 8px (384px), и получается 4 + 2. Потяните к 620px, и все шесть поместятся в одну строку; потяните к 120px, и каждый элемент получит свою строку.

flex-direction: строка или колонка

flex-direction задает направление, в котором идут элементы, то есть главную ось:

ЗначениеЭлементы идутПервый элемент
row (по умолчанию)бок о бок, в направлении письмав начале строки
row-reverseбок о бок, в обратном порядкев конце строки
columnстопкой, сверху внизсверху
column-reverseстопкой, снизу вверхснизу

В двух блоках row элементы растягиваются на всю высоту блока, потому что align-items: stretch работает поперек строки. В блоках column они по той же причине растягиваются на всю ширину. Оси повернулись, и вместе с ними повернулось каждое свойство выравнивания (подробно это показано на странице про justify-content).

flex-flow: оба свойства в одной строке

flex-flow это сокращение для flex-direction, а затем flex-wrap:

.cards { flex-flow: row wrap; }      /* flex-direction: row; flex-wrap: wrap; */
.stack { flex-flow: column nowrap; } /* flex-direction: column; flex-wrap: nowrap; */

Адаптивные карточки через wrap без медиазапросов

Дайте каждому элементу начальный размер через flex: 1 1 180px и разрешите перенос. Каждый элемент растет, заполняя свою строку, а когда в строку не помещается еще один элемент на 180px, следующий переносится:

В превью шириной около 800px в первую строку помещаются три карточки (около 253px каждая), а последние две делят вторую строку, где каждая вырастает примерно до 386px. Так работает flexbox: каждая строка делит свое пространство сама, поэтому карточки в короткой последней строке оказываются шире верхних. Если последняя карточка должна быть той же ширины, что и остальные, используйте grid с repeat(auto-fill, minmax(180px, 1fr)) (смотрите страницу про CSS Grid).

align-content: промежутки между строками

Когда контейнер переносит элементы и выше своих строк, align-content решает, где будут строки. Он принимает те же значения, что justify-content, плюс stretch:

В первом блоке обе строки стоят сверху. Во втором первая строка сверху, вторая снизу, а вся свободная высота между ними.

Обратный порядок и доступность

row-reverse, column-reverse и wrap-reverse меняют только то, где элементы рисуются. Программы чтения с экрана и клавиша Tab по-прежнему следуют порядку HTML, поэтому пользователь клавиатуры проходит элементы в направлении, обратном тому, что видит. Разворачивайте только ради визуального эффекта; когда порядок что-то значит, меняйте его в HTML.

Частые ошибки

  • Элементы сжимаются, а не переносятся. Элементы с flex: 1 начинают с flex-basis 0 и втискиваются в одну строку. Дайте им настоящую основу, например flex: 1 1 200px.
  • flex-wrap у элементов. Ему место у flex-контейнера.
  • align-items для промежутков между перенесенными строками. Оно выравнивает элементы внутри каждой строки; сами строки двигает align-content.
  • Одинокий последний элемент растянут на всю строку. Это flex-grow в строке с одним элементом. Используйте grid, если все карточки должны быть одинаковой ширины.
  • Ожидание, что flex-direction: column заполнит высоту. Колонка высотой только с содержимое, если не задать ей height, поэтому justify-content негде работать.

Часто задаваемые вопросы

Что делает flex-wrap: wrap?

Позволяет flex-элементам переходить на новую строку, когда они не помещаются в одну. При nowrap по умолчанию элементы остаются в одной строке и сжимаются или вылезают за контейнер, если сжиматься дальше не могут.

Почему не работает flex-wrap?

Перенос происходит, только когда начальные размеры элементов в сумме больше контейнера. Элементы с flex: 1 начинают с flex-basis 0, поэтому никогда не переносятся; дайте им настоящий начальный размер (flex: 1 1 200px или width: 200px). Также проверьте, что flex-wrap задан flex-контейнеру, а не элементам.

Чем отличаются flex-direction row и column?

row (по умолчанию) ставит элементы бок о бок в направлении письма, а column складывает их сверху вниз. Вместе с ним поворачивается главная ось, поэтому в колонке justify-content работает по вертикали, а align-items по горизонтали.

Что такое flex-flow?

Сокращение для flex-direction и flex-wrap в одном объявлении: flex-flow: row wrap; то же самое, что flex-direction: row; flex-wrap: wrap;.

Чем align-items отличается от align-content?

align-items размещает элементы внутри их строки. align-content размещает сами строки внутри контейнера, поэтому он важен, только когда у контейнера flex-wrap: wrap и он выше своих строк.

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ