[Перевод] Что происходит при создании контейнера Flexbox?

Это перевод статьи Rachel Andrew, являющейся одним из разработчиков спецификаций CSS.

В короткой серии статей я собираюсь потратить некоторое время на детальную распаковку Flexbox — точно так же, как я делала в прошлом с grid. Мы рассмотрим, для чего был разработан Flexbox, что он действительно делает хорошо, а когда мы не можем выбрать его в качестве способа компоновки.

В этой статье мы подробно рассмотрим, что на самом деле происходит при добавлении display: flex в вашу таблицу стилей.


Flex контейнер, пожалуйста!

Чтобы использовать Flexbox, вам нужен элемент, который будет flex контейнером. В вашем CSS вы используете display: flex:

Давайте немного поразмышляем о том, что на самом деле означает display: flex. В спецификации Display Module Level 3 каждое значение просмотра описывается как комбинация двух элементов: внутренней и внешней модели отображения.

Когда мы добавляем display: flex, мы в действительности определяем display: block flex. Внешний тип отображения нашего flex-контейнера блок; он действует как элемент уровня блока в стандартном потоке. Внутренний тип отображения flex, поэтому элементы непосредственно внутри нашего контейнера будут участвовать во flex-компоновке.

Это то, о чем вы, возможно, никогда не задумывались, но, вероятно, все равно понимаете. Контейнер flex действует как любой другой блок на вашей странице. Если у вас есть абзац, за которым следует контейнер flex, то оба элемента ведут себя так, как мы и хотим от блочных элементов.

Мы также можем назначить нашему контейнеру значение inline-flex, использовав display: inline flex, т.е. flex-контейнер действует как элемент уровня строки с дочерними элементами, которые участвуют во Flex компоновке. Дочерние элементы нашего строчного flex-контейнера ведут себя так же, как и дочерние элементы нашего блочного flex-контейнера; разница заключается в том, как сам контейнер ведет себя в общем макете.

Эта концепция поведения элементов, имеющих внешний тип отображения, определенный как блок на странице (плюс внутренний тип отображения) диктует, как ведут себя их дети, весьма полезна. Вы можете применить эти рассуждения к любому блоку в CSS. Как действует этот элемент? Как действуют дети этого элемента? Ответы относятся к их внешним и внутренним моделям отображения.


Строки Или Столбцы?

Как только мы определили наш flex-контейнер, вступают в игру некоторые начальные значения. Без добавления дополнительных свойств flex-элементы отображаются в виде строки. Это происходит потому, что начальным значением свойства flex-direction является row. Если вы не измените его, то получите ряд.

Свойство flex-direction определяет направление главной оси. Оно может принимать и другие значения:


  • column;
  • row-reverse;
  • column-reverse.

Наши элементы в один ряд будут размещены, начиная со стартового ребра, в направлении строки и отображаться в порядке, в котором они появляются в источнике. В спецификации это ребро называется как main-start:

Рис_1
Рис_1. main-start — начало строчного направления

Если мы используем значение column, элементы начнут располагаться от стартового ребра в блочном направлении и, следовательно, образуют столбец.

Рис_2
Рис_2. main-start — начало блочного направления

Если мы используем row-reverse, расположение main-start и main-end поменяются местами; поэтому элементы будут выкладываются один за другим в обратном порядке.

Рис_3
Рис_3. main-start — от конца строчного направления

Значение column-reverse делает то же самое.

Важно помнить, что эти значения не «переключают порядок элементов», хотя это то, что мы видим, они просто меняют место, где начинается поток элементов, переключая расположение main-start. Таким образом, наши элементы отображаются в обратном порядке, но это потому, что они начинают выкладывать от другого конца контейнера.

Также важно помнить, что, когда это происходит, это чисто визуальный эффект. Мы просим элементы отображать себя, начиная с конечного ребра; они все еще текут в том же порядке, и это тот порядок, который использует ваш экранный ридер, а также порядок, в котором они могут быть протабулированы. Вы никогда не должны использовать row-reverse, если вы действительно хотите изменить порядок элементов. Для этого внесите изменения в исходный документ.


Две оси flexbox

Мы уже раскрыли важную особенность flexbox: возможность переключения главной оси со строки на столбец. Это переключение оси, поэтому я думаю, что часто легче понять такие вещи, как выравнивание в макете сетки. С помощью сетки, работающей в двух направлениях, вы можете выравнивать по обеим осям практически одинаково. Flexbox немного сложнее, потому что некоторые события происходят в зависимости от того, работаете ли вы с главной или поперечной осью.

Мы уже сталкивались с главной осью, т. е. осью, которую вы определяете как значение flex-direction. Поперечная ось это другое направление. Если вы установили flex-direction: row, ваша главная ось находится вдоль строки, а поперечная — вниз по столбцу. С помощью flex-direction: column главная ось расположится вниз по столбцу, а поперечная — вдоль строки. Именно здесь нам нужно рассмотреть еще одну важную особенность Flexbox, и это тот факт, что он не привязан к физическим направлениям экрана. Мы не говорим о строке, идущей слева направо, или столбце сверху вниз, потому что это не всегда так.


РЕЖИМЫ ЗАПИСИ

Когда я выше описывала строку и столбец, я упомянула блочное и строчное направления. Эта статья написана на английском языке, который имеет горизонтальный режим записи. Это означает, что когда вы попросите Flexbox предоставить вам строку, вы получите горизонтальное отображение ваших flex элементов. В этом случае main-start находится слева — на месте, с которого начинаются предложения на английском языке.

Если бы я работала на языке справа налево, таком как арабский, то стартовое ребро было бы справа:

Начальные значения flexbox означают, что если все, что я делаю, это создаю контейнер flex, то мои элементы будут начинаться справа и отображаться, перемещаясь в левую сторону. Стартовое ребро в строчном направлении — это место, где предложения начинаются в используемом режиме записи.

Если вы окажетесь в вертикальном режиме записи и обратитесь к строке, ваша строка будет работать вертикально, потому что именно так строки текста выполняются на вертикальном языке. Это можно попробовать, добавив свойство режима записи в контейнер flex и установив для него значение vertical-lr. Теперь, когда вы устанавливаете flex-direction в row, вы получите вертикальный столбец элементов.

Таким образом, ряд может работать горизонтально, с main-start слева или справа, а также работать вертикально с main-start вверху. Это все еще flex-direction строка, даже если нашим умам, привычным к горизонтальному тексту, трудно думать о строке, работающей вертикально!

Чтобы элементы располагались в блочном направлении, мы задаем для свойства flex-direction значение column или column-reverse. На английском (или арабском) языке мы видим элементы, отображаемые один над другим вниз по странице, начиная с верха контейнера.

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

Однако независимо от того, в каком направлении отображаются блоки, если вы работаете со столбцом, вы работаете в блочном направлении.

Понимание того факта, что строка или столбец могут выполняться в разных физических направлениях, полезно для понимания некоторых терминов, используемых для Grid и Flexbox. Мы не ссылаемся на «лево и право» или «верх и низ» в Flexbox и Grid, потому что мы не делаем никаких предположений относительно режима записи нашего документа. Весь CSS становится более осведомленным о режиме записи.

Если вас интересуют некоторые другие свойства и значения, реализуемые, чтобы заставить остальную часть CSS вести себя таким же образом, прочитайте мою статью о логических свойствах и значениях.

В качестве резюме, запомните, что:


  • flex-direction: row
    • главная ось = рядное направление (inline dimension);
    • main-start будет там, где начинаются предложения в этом режиме записи;
    • поперечная ось = блочное направление (block dimension);
  • flex-direction: column
    • главная ось = блочное направление (block dimension);
    • main-start будет там, где блоки начинают выкладываться в этом режиме записи ;
    • поперечная ось = рядное направление (inline dimension).


Начальное выравнивание

Когда мы применяем display: flex, происходят также и некоторые другие события. Выполняется некоторое первоначальное выравнивание. В одной из следующих статей этой серии мы рассмотрим выравнивание. однако в нашем исследовании display: flex мы должны рассмотреть выполнение инициализации.


Примечание: стоит отметить, что, хотя эти свойства выравнивания начали жизнь в спецификации Flexbox, спецификация Box Alignment в конечном счете заменит их, как указано в спецификации Flexbox.


ВЫРАВНИВАНИЕ ГЛАВНОЙ ОСИ

Начальное значение свойства justify-content установлено в flex-start. Это как бы наш CSS был таким:

.container {
    display: flex;
    justify-content: flex-start;
}

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

Если вы видите свойство выравнивания, которое начинается с justify-, то оно применяется к главной оси Flexbox. Таким образом, justify-content выполняет выравнивание вдоль главной оси и располагает наши элементы в ее начале.

Другие возможные значения для justify-content:


  • flex-end;
  • center;
  • space-around;
  • space-between;
  • space-evenly (добавлено в Box Alignment).

Эти значения занимаются распределением свободного пространства flex-контейнера. Вот почему элементы располагаются рядом или отстоят друг от друга. Если вы добавите justify-content: space-between, то любое доступное пространство распределится между всеми элементами. Однако, это может произойти только если свободное пространство имеется. Если бы у вас был плотно упакованный flex-контейнер (без дополнительного пространства после того, как все элементы были выложены), то justify-content вообще ничего не сделало бы.

Вы можете увидеть это, если переключите flex-direction на столбец. Без высоты у flex-контейнера нет свободного места, поэтому установка параметра justify-content: space-between ничего не даст. Если добавить высоту и сделать так, чтобы контейнер был выше, чем требуется для отображения элементов, то свойство будет иметь эффект:


ВЫРАВНИВАНИЕ ВДОЛЬ ПОПЕРЕЧНОЙ ОСИ

Элементы также выравниваются в одну строку вдоль поперечной оси flex-контейнера. Выравнивание, которое мы выполняем, заключается в выравнивании блоков друг относительно друга в ряд. В следующем примере один из наших блоков имеет больше содержимого, чем все остальные. Что-то подсказывает другим блокам растянуться до той же высоты. Это свойство align-items, которое имеет начальное значение stretch:

Когда вы видите свойство выравнивания, которое начинается с align- и вы находитесь во flexbox, то вы имеете дело с выравниванием вдоль поперечной оси, и align-items выравнивает элементы вдоль flex строки. Другие возможные значения:


  • flex-start;
  • flex-end;
  • center;
  • baseline.

Если вы не хотите, чтобы все блоки растягивались на высоту самых высоких, то установка align-items: flex-start приведет к выравниванию их всех по начальному краю поперечной оси.


Начальные значения для элементов Flex

Наконец, сами flex элементы также имеют начальные значения, они установлены в:


  • flex-grow: 0;
  • flex-shrink: 1;
  • flex-basis: auto.

Это означает, что наши элементы не будут расти по умолчанию, чтобы заполнить доступное пространство на главной оси. Если же для параметра flex-grow задать положительное значение, элементы будут расти и занимать любое доступное пространство.

Однако блоки могут сжиматься, так как flex-shrink имеет положительное значение 1. Это означает, что если у нас есть очень узкий flex-контейнер, то элементы будут настолько малы, насколько это возможно, до того, как произойдет переполнение. Это разумное поведение; в общем, мы хотим, чтобы они оставались внутри своих блоков и не переполнялись, если есть место для их отображения.

Чтобы получить наилучший макет, свойство flex-basis по умолчанию имеет значение auto. Мы поймем, что это означает, в следующей статье этой серии, однако, большую часть времени вы можете думать об auto как о «достаточно большом значении, чтобы вместить содержимое». Вы увидите, что, если у вас есть гибкие элементы, которые заполняют контейнер, и один из них имеет больший объем содержимого, чем другие, то ему будет предоставлено больше места.

Это гибкость Flexbox в действии. При flex-basis в auto и отсутствии указания размеров элементов, они имеют базовый размер max-content. Это был бы размер, когда бы они растянулись и не выполняли перенос строки. В этом случае свободное пространство делится между элементами в пропорции, описанной в следующем примечании спецификации flexbox.


»Примечание: при распределении недостающего пространства коэффициент сжатия flex умножается на базовый размер flex. Это распределяет недостающее пространство пропорционально тому, как элемент может сжаться, так что, например, небольшой элемент не будет сжиматься до нуля, пока более крупный не будет заметно уменьшен.»

У более крупного элемента меньше свободного места, и мы получаем окончательный макет. Вы можете сравнить два скриншота ниже, оба взятые из приведенного выше примера. Однако на первом снимке экрана третий блок имеет меньшее количество контента, поэтому наши столбцы имеют более равномерное распределение пространства.

Рис_4
Рис_4. Элементы переносятся для придания большему элементу больше места

Здесь Flexbox помогает нам в конечном итоге получить разумный конечный результат без вмешательства человека, написавшего CSS. Вместо того, чтобы равномерно уменьшать пространство и в итоге получить очень высокий элемент с несколькими словами в каждой строке, он выделяет этому элементу больше пространства для размещения самого себя. В рамках такого поведения и есть ключ к реальным вариантам использования Flexbox. Flexbox наилучшим образом подходит для размещения множества элементов — вдоль одной оси — гибким и содержательным способом.

Я затронула здесь лишь некоторые детали, но мы рассмотрим эти алгоритмы позже в этой серии.


Заключение

В этой статье я взяла начальные значения Flexbox, чтобы объяснить, что на самом деле происходит, когда вы указываете display: flex. Это удивительная сумма, как только вы начинаете ее распаковывать, и, содержащиеся в ней несколько свойств оказываются многими ключевыми характеристиками гибких макетов.

Flex макеты гибки: они стараются сделать по умолчанию правильный выбор о вашем содержимом — сжимаются и растягиваются, чтобы получить лучшую читаемость. Гибкие макеты поддерживают режим записи: направления строк и столбцов связаны с используемым режимом записи. Гибкие макеты позволяют выравнивать элементы как группу по главной оси, выбирая способ распределения пространства. Они позволяют выравнивать элементы вдоль своей гибкой линии, перемещать элементы вдоль поперечной оси друг относительно друга. Важно отметить, что гибкие макеты понимают объем вашего контента, и попытаются принять правильные основные решения, чтобы отобразить его.

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

© Habrahabr.ru