Как flex-wrap работает с align-self, align-items и align-content?

align-self

В следующем коде align-self работает с flex-wrap: nowrap,

введите описание изображения здесь

flex-container {
  display: flex;
  flex-wrap: nowrap;
  align-content: flex-start;
  width: 250px;
  height: 250px;
  background-color: silver;
}
flex-item {
  flex: 0 0 50px;
  height: 50px;
  margin: 5px;
  background-color: lightgreen;
}
flex-item:last-child {
  align-self: flex-end;
  background-color: crimson;
}
<flex-container>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
</flex-container>

Но когда контейнер переключен на flex-wrap: wrap, align-self собственность терпит неудачу.

введите описание изображения здесь

flex-container {
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  width: 250px;
  height: 250px;
  background-color: silver;
}
flex-item {
  flex: 0 0 50px;
  height: 50px;
  margin: 5px;
  background-color: lightgreen;
}
flex-item:last-child {
  align-self: flex-end;
  background-color: crimson;
}
<flex-container>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
</flex-container>


align-items

Точно так же почему align-items работа здесь (обертывание отключено):

введите описание изображения здесь

flex-container {
  display: flex;
  flex-wrap: nowrap;
  align-items: flex-end;
  align-content: flex-start;
  width: 250px;
  height: 250px;
  background-color: silver;
}
flex-item {
  flex: 0 0 50px;
  height: 50px;
  margin: 5px;
  background-color: lightgreen;
}
<flex-container>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
</flex-container>

... но не здесь (перенос включен):

введите описание изображения здесь

flex-container {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  align-content: flex-start;
  width: 250px;
  height: 250px;
  background-color: silver;
}

flex-item {
  flex: 0 0 50px;
  height: 50px;
  margin: 5px;
  background-color: lightgreen;
}
<flex-container>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
</flex-container>


align-content

С flex-wrap: nowrap, align-content свойство не будет вертикально центрировать элементы Flex здесь:

введите описание изображения здесь

flex-container {
  display: flex;
  flex-wrap: nowrap;
  align-content: center;
  width: 250px;
  height: 250px;
  background-color: silver;
}

flex-item {
  flex: 0 0 50px;
  height: 50px;
  margin: 5px;
  background-color: lightgreen;
}
<flex-container>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
</flex-container>

Но тогда, как ни странно, если обтекание включено и align-content опущен, контейнер создает широкие промежутки между строками:

введите описание изображения здесь

flex-container {
  display: flex;
  flex-wrap: wrap;
  /* align-content: center; */
  width: 250px;
  height: 250px;
  background-color: silver;
}

flex-item {
  flex: 0 0 50px;
  height: 50px;
  margin: 5px;
  background-color: lightgreen;
}
<flex-container>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
</flex-container>

А также align-self снова работает

введите описание изображения здесь

flex-container {
  display: flex;
  flex-wrap: wrap;
  /* align-content: center; */
  width: 250px;
  height: 250px;
  background-color: silver;
}
flex-item {
  flex: 0 0 50px;
  height: 50px;
  margin: 5px;
  background-color: lightgreen;
}

flex-item:nth-child(even) {
  align-self: flex-end;
  background-color: crimson;
}
<flex-container>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
</flex-container>

Как flex-wrap работать с align-self , align-items а также align-content?

2 ответа

Решение

Короткий ответ

Хотя flex-wrap Свойство кажется довольно простым - оно контролирует возможность переноса элементов flex - оно на самом деле оказывает широкое влияние на весь макет flexbox.

flex-wrap Свойство определяет тип гибкого контейнера, который вы будете использовать.

  • flex-wrap: nowrap создает однострочный гибкий контейнер
  • flex-wrap: wrap а также wrap-reverse создать многострочный гибкий контейнер

align-items а также align-self свойства работают как в одно-, так и в многострочных контейнерах. Тем не менее, они могут иметь эффект только при наличии свободного места на поперечной оси гибкой линии.

align-content свойство работает только в многострочных контейнерах. Это игнорируется в однострочных контейнерах.


объяснение

Спецификация flexbox предоставляет четыре свойства ключевых слов для выравнивания элементов flex:

  • align-items
  • align-self
  • align-content
  • justify-content

Чтобы понять функции этих свойств, важно сначала понять структуру гибкого контейнера.


Часть 1: Понимание главной и поперечной осей гибкого контейнера

Оси X и Y

Гибкий контейнер работает в двух направлениях: ось x (горизонтальная) и ось y (вертикальная).

ось x и ось y

Источник: Википедия

Дочерние элементы гибкого контейнера, известные как "гибкие элементы", могут быть выровнены в любом направлении.

Это гибкое выравнивание на самом фундаментальном уровне.

Главная и поперечная оси

Наложение осей X и Y в гибком макете является главной и поперечной осями.

По умолчанию главная ось является горизонтальной (ось X), а поперечная ось является вертикальной (ось Y). Это начальная настройка, определенная спецификацией flexbox.

изгиб основной оси и поперечной оси

Источник: W3C

Однако, в отличие от осей x и y, которые являются фиксированными, главная и поперечная оси могут переключать направления.

flex-direction Имущество

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

Тем не менее, эти направления могут быть легко переключены с помощью flex-direction имущество. Это свойство контролирует направление главной оси; он определяет, выравниваются ли элементы Flex по вертикали или по горизонтали.

Из спецификации:

5.1. Направление гибкого потока: flex-direction имущество

flex-direction Свойство указывает, как флекс-элементы размещаются в флекс-контейнере, устанавливая направление главной оси флекс-контейнера. Это определяет направление, в котором располагаются гибкие элементы.

Есть четыре значения для flex-direction имущество:

/* main axis is horizontal, cross axis is vertical */
flex-direction: row; /* default */
flex-direction: row-reverse;

/* main axis is vertical, cross axis is horizontal */    
flex-direction: column;
flex-direction: column-reverse;

Поперечная ось всегда перпендикулярна главной оси.


Часть 2: Flex Lines

В контейнере гибкие элементы существуют в строке, известной как "гибкая линия".

Гибкая линия - это строка или столбец, в зависимости от flex-direction,

Контейнер может иметь одну или несколько строк, в зависимости от flex-wrap,

Однолинейный гибкий контейнер

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

однострочный гибкий контейнер (один столбец

Изображение выше имеет одну линию сгиба.

flex-container {
  display: flex;
  flex-direction: column;
  flex-wrap: nowrap; /* <-- allows single-line flex container */
  width: 250px;
  height: 250px;
  background-color: silver;
}
flex-item {
  flex: 0 0 50px;
  width: 50px;
  margin: 5px;
  background-color: lightgreen;
}
<flex-container>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
</flex-container>

Multi-Line Flex Container

flex-wrap: wrap или же wrap-reverse устанавливает многострочный flex-контейнер, в котором flex-элементы могут создавать новые строки.

многострочный гибкий контейнер (3 колонки

Изображение выше имеет три линии сгиба.

flex-container {
  display: flex;
  flex-direction: column;
  flex-wrap: wrap; /* <-- allows multi-line flex container */
  width: 250px;
  height: 250px;
  background-color: silver;
}
flex-item {
  flex: 0 0 50px;
  width: 50px;
  margin: 5px;
  background-color: lightgreen;
}
<flex-container>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
</flex-container>

многострочный гибкий контейнер (3 ряда

Изображение выше имеет три линии сгиба.

flex-container {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap; /* <-- allows multi-line flex container */
  width: 250px;
  height: 250px;
  background-color: silver;
}
flex-item {
  flex: 0 0 50px;
  height: 50px;
  margin: 5px;
  background-color: lightgreen;
}
<flex-container>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
</flex-container>


Часть 3: Свойства выравнивания ключевых слов

Свойства назначены главной и поперечной (не X и Y) осям

В то время как flex-direction Свойство контролирует направление, в котором размечаются гибкие элементы, есть четыре свойства, которые управляют выравниванием и позиционированием. Это:

  • align-items
  • align-self
  • align-content
  • justify-content

Каждое из этих свойств постоянно назначается оси.

justify-content свойство работает только по главной оси.

Три align-* свойства работают только в поперечной оси.

Распространенной ошибкой является предположение, что эти свойства зафиксированы на осях x и y. Например, justify-content всегда горизонтально, и align-items всегда вертикально

Однако когда flex-direction переключается на column, главная ось становится осью Y, и justify-content работает вертикально.

Тема этого поста - выравнивание по осям. Для объяснения выравнивания главной оси и justify-content собственности, см. этот пост:

Определения

Спецификация flexbox предоставляет три ключевых свойства для выравнивания по оси:

  • align-items
  • align-self
  • align-content

align-items / align-self

align-items свойство выравнивает элементы flex вдоль оси сгиба линии flex. Это относится к гибким контейнерам.

align-self свойство используется для переопределения align-items на отдельных флекс. Это относится к гибким предметам.

Вот определение из спецификации:

8.3. Выравнивание по оси align-items а также align-self свойства

Элементы Flex могут быть выровнены по поперечной оси текущей строки контейнера Flex, аналогично justify-content но в перпендикулярном направлении. align-items устанавливает выравнивание по умолчанию для всех элементов гибкого контейнера. align-self позволяет этому выравниванию по умолчанию быть переопределенным для отдельных элементов flex.

Есть шесть возможных значений align-items / align-self:

  • flex-start
  • flex-end
  • center
  • baseline
  • stretch
  • auto (align-self только)

(Для описания каждого значения нажмите на заголовок определения спецификации выше.)

Начальная стоимость align-items является stretch Это означает, что гибкие элементы будут расширять всю доступную длину поперечной оси контейнера.

Начальная стоимость align-self является auto это означает, что он наследует значение align-items,

Ниже приведена иллюстрация влияния каждого значения в контейнере направления строки.

значения align-items align-self

Источник: W3C

align-content

Это свойство немного сложнее, чем align-items а также align-self,

Вот определение из спецификации:

8.4. Упаковочные линии Flex: align-content имущество

align-content свойство выравнивает линии флекс-контейнера внутри флекс-контейнера, когда на поперечной оси есть дополнительное пространство, аналогично тому, как justify-content выравнивает отдельные элементы в пределах главной оси. Обратите внимание, что это свойство не влияет на однострочный гибкий контейнер.

В отличие от align-items а также align-self, которые перемещают гибкие элементы в пределах своей линии, align-content перемещает гибкие линии внутри контейнера.

Есть шесть возможных значений align-content:

  • flex-start
  • flex-end
  • center
  • space-between
  • space-around
  • stretch

(Для описания каждого значения нажмите на заголовок определения спецификации выше.)

Ниже приведена иллюстрация влияния каждого значения в контейнере направления строки.

Источник: W3C

Почему align-content работать только в многолинейных гибких контейнерах?

В гибком контейнере с одной линией поперечный размер линии равен поперечному размеру контейнера. Это означает, что между линией и контейнером нет свободного места. В следствии, align-content не может иметь никакого эффекта.

Вот соответствующий раздел из спецификации:

Только многолинейные гибкие контейнеры когда-либо имеют свободное пространство на поперечной оси для выравнивания линий, потому что в однострочном гибком контейнере подошва автоматически растягивается, чтобы заполнить пространство.


Часть 4. Объясненные примеры

В примере № 1 align-self работает с flex-wrap: nowrap потому что гибкие элементы существуют в однострочном контейнере. Следовательно, есть одна гибкая линия, и она соответствует высоте контейнера.

flex-container {
  display: flex;
  flex-wrap: nowrap;
  align-content: flex-start;
  width: 250px;
  height: 250px;
  background-color: silver;
}
flex-item {
  flex: 0 0 50px;
  height: 50px;
  margin: 5px;
  background-color: lightgreen;
}
flex-item:last-child {
  align-self: flex-end;
  background-color: crimson;
}
<flex-container>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
</flex-container>

В примере № 2 align-self происходит сбой, потому что он существует в многострочном контейнере (flex-wrap: wrap) и align-content установлен в flex-start, Это означает, что гибкие линии плотно упакованы в начале поперечной оси, не оставляя свободного места для align-self работать.

flex-container {
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  width: 250px;
  height: 250px;
  background-color: silver;
}
flex-item {
  flex: 0 0 50px;
  height: 50px;
  margin: 5px;
  background-color: lightgreen;
}
flex-item:last-child {
  align-self: flex-end;
  background-color: crimson;
}
<flex-container>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
</flex-container>

Объяснение для примера № 3 такое же, как для примера № 1.

flex-container {
  display: flex;
  flex-wrap: nowrap;
  align-items: flex-end;
  align-content: flex-start;
  width: 250px;
  height: 250px;
  background-color: silver;
}
flex-item {
  flex: 0 0 50px;
  height: 50px;
  margin: 5px;
  background-color: lightgreen;
}
<flex-container>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
</flex-container>

Объяснение для примера № 4 такое же, как для примера № 2.

flex-container {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  align-content: flex-start;
  width: 250px;
  height: 250px;
  background-color: silver;
}

flex-item {
  flex: 0 0 50px;
  height: 50px;
  margin: 5px;
  background-color: lightgreen;
}
<flex-container>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
</flex-container>

Пример № 5 - это однострочный контейнер. Таким образом, размер поперечной линии гибкой линии равен поперечному размеру контейнера, не оставляя дополнительного пространства между ними. Следовательно, align-content, который выравнивает линии сгиба, когда есть дополнительное пространство на поперечной оси, не имеет никакого эффекта.

flex-container {
  display: flex;
  flex-wrap: nowrap;
  align-content: center;
  width: 250px;
  height: 250px;
  background-color: silver;
}

flex-item {
  flex: 0 0 50px;
  height: 50px;
  margin: 5px;
  background-color: lightgreen;
}
<flex-container>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
</flex-container>

Начальная настройка для align-content является stretch, Это означает, что если не указано другое значение, контейнер будет равномерно распределять доступное пространство по гибким линиям. (Аналогичный эффект создается на главной оси, когда все гибкие элементы получают flex: 1.)

Такое распределение пространства между строками может вызвать большие промежутки между строками / столбцами. Меньше строк приводят к более широким промежуткам. Чем больше строк, тем меньше пропуски, так как каждая строка получает меньшую долю пространства.

Чтобы решить эту проблему, переключитесь с align-content: stretch в align-content: flex-start, Это объединяет строки (см. Примеры № 2 и № 4 выше). Конечно, это также устраняет любое свободное место в линии, и align-items а также align-self больше не может работать.

Вот похожий пост: Уберите пробелы (пробелы) между несколькими строками flex-элементов при их переносе

flex-container {
  display: flex;
  flex-wrap: wrap;
  /* align-content: center; */
  width: 250px;
  height: 250px;
  background-color: silver;
}

flex-item {
  flex: 0 0 50px;
  height: 50px;
  margin: 5px;
  background-color: lightgreen;
}
<flex-container>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
</flex-container>

Как объяснено в предыдущих примерах, с align-content: stretch, может быть дополнительное пространство в гибких линиях, что позволяет align-items а также align-self работать. Любое другое значение для align-content будет упаковывать линии, исключая дополнительное пространство и делая align-items а также align-self бесполезный.

flex-container {
  display: flex;
  flex-wrap: wrap;
  /* align-content: center; */
  width: 250px;
  height: 250px;
  background-color: silver;
}
flex-item {
  flex: 0 0 50px;
  height: 50px;
  margin: 5px;
  background-color: lightgreen;
}

flex-item:nth-child(even) {
  align-self: flex-end;
  background-color: crimson;
}
<flex-container>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
</flex-container>

Прежде всего, align-content бесполезен, если нет переноса:

W3C док

Свойство align-content выравнивает линии flex-контейнера внутри flex-контейнера, когда на поперечной оси имеется дополнительное пространство, аналогично тому, как justify-content выравнивает отдельные элементы на главной оси. Обратите внимание, что это свойство не влияет на однострочный гибкий контейнер.

Кроме того, в вашем втором случае, align-self не терпит неудачу. Это бесполезно, потому что внутренние линии были упакованы. Давайте создадим пространство, чтобы стиль мог работать:

flex-container {
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  width: 250px;
  height: 250px;
  background-color: silver;
}
flex-item {
  flex: 0 0 50px;
  height: 50px;
  margin: 5px;
  background-color: lightgreen;
}
flex-item:last-child {
  align-self: flex-end;
  background-color: crimson;
}
flex-item:nth-child(5) {
  height: 90px;  /* added */
}
<flex-container>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
</flex-container>

Аналогично, в вашем 4-м примере стиль работает, если вы задали условия, в которых его можно увидеть

flex-container {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  align-content: flex-start;
  width: 250px;
  height: 250px;
  background-color: silver;
}

flex-item {
  flex: 0 0 50px;
  height: 50px;
  margin: 5px;
  background-color: lightgreen;
}
flex-item:nth-child(2),flex-item:nth-child(5) {
  height: 90px;  /* added */
}
<flex-container>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
  <flex-item></flex-item>
</flex-container>

Наконец, когда вы комментируете align-content, он возвращается к растяжению, поэтому линии увеличивают размер, чтобы заполнить контейнер

растянуть линии растянуть, чтобы занять оставшееся пространство. Если оставшееся свободное пространство отрицательно, это значение идентично flex-start. В противном случае свободное пространство будет разделено поровну между всеми линиями, увеличивая их поперечный размер.

Другие вопросы по тегам