CSS :: Модуль CSS Flexbox
- Введение в модуль CSS Flexbox
- Создание flex-контейнера
- css-свойство flex-direction
- css-свойство flex-wrap
- Сокращенное css-свойство flex-flow
- css-свойство order
- css-свойство flex-grow
- css-свойство flex-shrink
- css-свойство flex-basis
- Сокращенное css-свойство flex
- css-свойство justify-content
- css-свойства align-items и align-self
- css-свойство align-content
Введение в модуль CSS Flexbox
CSS Flexbox (от англ. CSS Flexible Box Layout - модуль макета гибкого контейнера) - представляет собой специальную блочную модель CSS, которая позволяет эффективно управлять элементами внутри родительского флекс-контейнера. В частности, модель дает возможность располагать дочерние элементы флекс-контейнера в строках или колонках, переопределять порядок их отображения, выравнивать различными способами, а также изменять размеры элементов для корректного заполнения свободного пространства флекс-контейнера.
Как следует из определения, CSS Flexbox представляет собой полноценный модуль и поэтому включает в себя целый набор различных свойств, одни из которых применяется к родительскому элементу (т.е. флекс-контейнеру), другие - к самим дочерним элементам (т.е. флекс-элементам). Однако прежде, чем приступить к описанию этих свойств и их возможностей, необходимо познакомиться с понятиями направлений и размеров, которые используются для описания флекс-контейнера (см. рисунок №1).
Рис. №1. Направления и размеры флекс-контейнера со строками
Схема флекс-контейнера взята из официальной документации W3C. Перечислим основные термины, использующиеся в ней:
- main axis – главная ось флекс-контейнера, вдоль которой располагаются его флекс-элементы (в нашем случае это горизонтальная ось, поэтому горизонтальное направление считается основным);
- main start и main end – начальная и конечная стороны флекс-контейнера, между которыми располагаются флекс-элементы вдоль главной оси в направлении от main start к main end;
- main size – размер флекс-контейнера или флекс-элемента, который принимается за основной; это может быть как ширина, так и высота, в зависимости от того, какая ось будет выбрана главной: горизонтальная или вертикальная (в нашем случае основным размером считается ширина, т.к. соответствующие стороны флекс-контейнера и его флекс-элементов параллельны главной оси);
- cross axis – поперечная ось флекс-контейнера (она всегда перпендикулярна главной оси);
- cross start и cross end – начальная и конечная стороны флекс-контейнера, между которыми располагаются флекс-элементы вдоль поперечной оси в направлении от cross start к cross end;
- cross size – размер флекс-контейнера или флекс-элемента, который принимается за поперечный (в нашем случае поперечным размером считается высота, т.к. вертикальные стороны флекс-контейнера и его флекс-элементов параллельны поперечной оси).
Создание flex-контейнера
Для того чтобы создать flex-контейнер и получить возможность управлять его flex-элементами, нужно использовать для элемента свойство display со значениями flex или inline-flex (см. пример №2). В первом случае флекс-контейнеры будут вести себя, как блочные элементы, располагаясь друг под другом по вертикали, а во втором - как строчные элементы, выстраиваясь друг за другом по горизонтали.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <base href="https://html.okpython.net/"> <title>Создание flex-контейнера</title> <style> /* Оформляем родительские div'ы flex-элементов */ div{ display: flex; width: 400px; height: 120px; margin: auto; margin-top: 20px; padding: 0px; background-color: #DFDFDF; border-radius: 5px; } /* Это общий стиль flex-элементов */ p, span{ background-color: #55aa55; border-radius: 5px; text-align: center; font-weight: bold; color: #F9F9F9; } /* Это класс для флекс-элем. 1-го div'а */ .div_flex_1 p, .div_flex_1 span{ width: 100px; } /* Это класс для флекс-элем. 2-го и 3-го div'ов */ .div_flex_2 p, .div_flex_2 span, .div_flex_3 p, .div_flex_3 span{ width: 40px; height: 60px; padding: 10px; margin: auto; } /* Это класс для флекс-элем. 4-го div'а */ .div_flex_4 p, .div_flex_4 span{ width: 40px; padding: 10px; margin: auto; margin-top: 10px; margin-left: 40px; } </style> </head> <body> <div class="div_flex_1"> <p>1</p><span>2</span><p>3</p><span>4</span> <p>5</p><span>6</span><p>7</p><span>8</span> </div> <div class="div_flex_2"> <p>1</p><span>2</span><p>3</p><span>4</span> <p>5</p><span>6</span><p>7</p><span>8</span> </div> <div class="div_flex_3"> Я простойййййй текст перед. <img src="html_files/images/cabinet.png"> <p>1</p><span>2</span><p>3</p><span>4</span> <p>5</p><span>6</span><p>7</p><span>8</span> <img src="html_files/images/cabinet.png"> Я простой текст после. </div> <div class="div_flex_4"> <p style="position: relative; top: 50px">1</p> <span>2</span><p>3</p><span>4</span> <p style="position: absolute; left: 300px;">5</p> <span>6</span> <p style="margin: 20%; padding: 10%">7</p> <span>8</span> </div> </body> </html>
Пример №2. Пример создания flex-контейнера
В примере мы создали четыре одинаковых блочных флекс-контейнера (display: flex), включающих по восемь пронумерованных дочерних элементов. В третий блок мы дополнительно добавили изображения и простой текст. Рассмотрим каждый из этих блоков подробнее.
В первом флекс-контейнере как строчные элементы «span», так и блочные элементы «p» стали флекс-элементами. Поэтому они перестали вести себя по-своему, а по умолчанию выстроились в одну строку вдоль главной оси флекс-контейнера, подстроив по-возможности свою ширину таким образом, чтобы не выйти за его пределы. При этом флекс-элементы заполнили и всю доступную высоту контейнера, т.к. их высоту мы не устанавливали. Однако заметим, что внешние отступы у бывших блочных и строчных элементов по умолчанию разные, в результате и растянулись они по-разному.
Во втором флекс-контейнере мы задали для флекс-элементов высоту, внутренние отступы и внешние отступы со значением margin: auto. Получился интересный результат: высота всех флекс-элементов выровнялась, а внешние отступы сработали в автоматическом режиме не только по горизонтали, но и по вертикали.
В третьем флекс-контейнере мы добавили изображения и простой текст. В такой ситуации изображения и текст без оберток становятся анонимными флекс-элементами, занимая свое место в ряду других флекс-элементов. При этом текст выравнивается по верхнему краю контейнера, а изображение деформируется и растягивается на всю высоту блока. Что касается ширины анонимных блоков, то она зависит от содержимого, т.е. текста или ширины изображения. Далее, учитывая то, что флекс-элементов в блоке стало очень много, а их ширина достигла своего минимального значения, которое у флекс-элементов по умолчанию устанавливается в min-width: auto, они вышли в основном направлении за пределы своего флекс-контейнера.
В четвертом флекс-контейнере мы переопределили значение автоматических внешних отступов, в результате элементам пришлось сжаться до минимума, но они все равно не вместились в свой контейнер. Однако мы убедились в том, что отступы на флекс-элементах срабатывают. Кроме того, для третьего элемента мы еще раз переопределили внешние и внутренние отступы, задав их в процентах, обнаружив еще одну особенность: для флекс-элементов проценты рассчитываются относительно ширины флекс-контейнера. Далее, для первого флекс-элемента мы применили относительное позиционирование, а для пятого - абсолютное. Как видим, позиционирование сработало, как и ожидалось: первый элемент остался в потоке, продолжая участвовать в компоновке гибкого макета, а вот пятый элемент стал свободным, выпав из общего потока данных флекс-элементов (это касается как абсолютно, так и фиксированно позиционированных элементов).
Обязательно скопируйте код себе в редактор и поэкспериментируйте с ним: поизменяйте ширину флекс-элементов, их внутренние и внешние отступы, задавая их также и в процентах, проверьте эффект от фиксированного позиционирования флекс-элементов. Все это поможет вам лучше понять рассматриваемый ниже набор свойств модели CSS Flexbox.
css-свойство flex-direction
Главная ось флекс-контейнера необязательно должна быть направлена горизонтально слева направо. Ее направление можно легко изменить при помощи ненаследуемого css-свойства flex-direction, которое задает направление главной оси флекс-контейнера, определяя порядок расположения флекс-элементов в нем (см. пример №3). В качестве значений свойство принимает следующие ключевые слова:
- row – главная ось направлена горизонтально в направлении записи текста (используется по умолчанию); напомним, что направление записи текста в элементе задается универсальным атрибутом dir и по умолчанию имеет значение ltr (т.е. слева направо), именно поэтому флекс-элементы по умолчанию также отображаются строкой слева направо в направлении от стороны main start к main end;
- row-reverse – главная ось также направлена горизонтально, но при этом стороны main start и main end флекс-контейнера располагаются в направлении противоположном направлению записи текста в контейнере, поэтому флекс-элементы отображаются в строку, но в обратном порядке;
- column – главная ось направлена вертикально сверху вниз, поэтому флекс-элементы отображаются колонкой сверху вниз в направлении от стороны main start к main end;
- column-reverse – главная ось направлена вертикально снизу вверх, поэтому флекс-элементы отображаются колонкой снизу вверх в направлении от стороны main start к main end.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <base href="https://html.okpython.net/"> <title>css-свойство flex-direction</title> <style> /* Оформляем родительские div'ы flex-элементов */ div{ display: flex; width: 250px; height: 150px; margin: auto; margin-top: 10px; background-color: #DFDFDF; border-radius: 5px; } /* Это общий стиль flex-элементов */ p, span{ width: 40px; padding: 10px; margin: auto; background-color: #55aa55; border-radius: 5px; text-align: center; font-weight: bold; color: #F9F9F9; } /* Это класс для 1-го div'а */ .div_flex_1{ flex-direction: row; } /* Это класс для 2-го div'а */ .div_flex_2{ flex-direction: row-reverse; } /* Это класс для 3-го div'а */ .div_flex_3{ flex-direction: column; } /* Это класс для 4-го div'а */ .div_flex_4{ flex-direction: column-reverse; } </style> </head> <body> <div class="div_flex_1"> <p>1</p><span>2</span><p>3</p> </div> <div class="div_flex_2"> <p>1</p><span>2</span><p>3</p> </div> <div class="div_flex_3"> <p>1</p><span>2</span><p>3</p> </div> <div class="div_flex_4"> <p>1</p><span>2</span><p>3</p> </div> </body> </html>
Пример №3. Пример использования свойства flex-direction
Важно понимать, что изменение направления отображения флекс-элементов в своем флекс-контейнере при помощи свойства flex-direction всего лишь визуальный эффект. На самом деле в потоке документа они занимают прежнее расположение и обрабатываются в той же последовательности. Поэтому для реального изменения порядка элементов нужно вносить изменения в исходный код документа.
css-свойство flex-wrap
По умолчанию все флекс-элементы выстраиваются в одну строку, стараясь вместиться в пределах своего флекс-контейнера. В результате, как мы видели в примере выше, могут возникать ситуации, когда флекс-элементы будут выходить за пределы своего контейнера. Для таких ситуаций в CSS предусмотрено ненаследуемое свойство flex-wrap, которое управляет порядком переноса и отображения флекс-элементов на новые строки (см. пример №4). В качестве значений свойство принимает следующие ключевые слова:
- nowrap – флекс-элементы отображаются в одной линии (значение используется по умолчанию);
- wrap – флекс-элементы выстраиваются в несколько строк, направление которых задаётся свойством flex-direction;
- wrap-reverse – флекс-элементы также выстраиваются в несколько строк, но в направлении, которое противоположно направлению заданному свойством flex-direction.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <base href="https://html.okpython.net/"> <title>css-свойство flex-wrap</title> <style> /* Оформляем родительские div'ы flex-элементов */ div{ display: flex; width: 250px; height: 150px; margin: auto; margin-top: 20px; background-color: #DFDFDF; border-radius: 5px; } /* Это общий стиль flex-элементов */ p, span{ width: 40px; padding: 10px; margin: auto; background-color: #55aa55; border-radius: 5px; text-align: center; font-weight: bold; color: #F9F9F9; } /* Это класс для 1-го div'а */ .div_flex_1{ flex-direction: row; flex-wrap: wrap; } /* Это класс для 2-го div'а */ .div_flex_2{ flex-direction: row; flex-wrap: wrap-reverse; } /* Это класс для 3-го div'а */ .div_flex_3{ flex-direction: column; flex-wrap: wrap; } /* Это класс для 4-го div'а */ .div_flex_4{ flex-direction: column; flex-wrap: wrap-reverse; } </style> </head> <body> <div class="div_flex_1"> <p>1</p><span>2</span><p>3</p><span>4</span> <p>5</p><span>6</span><p>7</p><span>8</span> </div> <div class="div_flex_2"> <p>1</p><span>2</span><p>3</p><span>4</span> <p>5</p><span>6</span><p>7</p><span>8</span> </div> <div class="div_flex_3"> <p>1</p><span>2</span><p>3</p><span>4</span> <p>5</p><span>6</span><p>7</p><span>8</span> </div> <div class="div_flex_4"> <p>1</p><span>2</span><p>3</p><span>4</span> <p>5</p><span>6</span><p>7</p><span>8</span> </div> </body> </html>
Пример №4. Пример использования свойства flex-wrap
Попробуйте в примере выше поизменять значение свойства flex-direction, обратив внимание на то, как будет изменяться порядок вывода флекс-элементов на новых строках.
Универсальное css-свойство flex-flow
Поскольку свойства flex-direction и flex-wrap используются в паре довольно часто, в CSS добавили ненаследуемое свойство flex-flow, которое может принимать через пробел сразу два значения: flex-flow: flex-direction || flex-wrap (см. пример №5). По умолчанию для первого значения используется row, а для второго - nowrap. Если указать только один параметр, второй примет значение по умолчанию.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <base href="https://html.okpython.net/"> <title>css-свойство flex-flow</title> <style> /* Оформляем родительские div'ы flex-элементов */ div{ display: flex; width: 250px; height: 150px; margin: auto; margin-top: 20px; background-color: #DFDFDF; border-radius: 5px; } /* Это общий стиль flex-элементов */ p, span{ width: 40px; padding: 10px; margin: auto; background-color: #55aa55; border-radius: 5px; text-align: center; font-weight: bold; color: #F9F9F9; } /* Это класс для 1-го div'а */ .div_flex_1{ flex-flow: row wrap; } /* Это класс для 2-го div'а */ .div_flex_2{ flex-flow: wrap-reverse; } /* Это класс для 3-го div'а */ .div_flex_3{ flex-flow: column wrap; } /* Это класс для 4-го div'а */ .div_flex_4{ flex-flow: column wrap-reverse; } </style> </head> <body> <div class="div_flex_1"> <p>1</p><span>2</span><p>3</p><span>4</span> <p>5</p><span>6</span><p>7</p><span>8</span> </div> <div class="div_flex_2"> <p>1</p><span>2</span><p>3</p><span>4</span> <p>5</p><span>6</span><p>7</p><span>8</span> </div> <div class="div_flex_3"> <p>1</p><span>2</span><p>3</p><span>4</span> <p>5</p><span>6</span><p>7</p><span>8</span> </div> <div class="div_flex_4"> <p>1</p><span>2</span><p>3</p><span>4</span> <p>5</p><span>6</span><p>7</p><span>8</span> </div> </body> </html>
Пример №5. Пример использования свойства flex-flow
Обратите внимание, что результат отображения данного примера идентичен результату примера №4, но при этом кода написано меньше.
css-свойство order
Иногда может потребоваться, чтобы некоторые флекс-элементы выстраивались вдоль заданного направления не по порядку. В таких случаях следует использовать ненаследуемое css-свойство order, которое применяется к флекс-элементам и переопределяет порядок их отображения. В качестве значений свойство принимает целые числа (как положительные, так и отрицательные). В результате флекс-элементы с меньшими значениями свойства order выводятся раньше, а элементы, имеющие большие значения выводятся позже (см. пример №6). Если флекс-элементы имеют одинаковые значения свойства order, они выводятся согласно их первоначальному порядку.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>css-свойство order</title> <style> /* Оформляем родительские div'ы flex-элементов */ div{ display: flex; width: 250px; height: 250px; margin: auto; margin-top: 10px; background-color: #DFDFDF; border-radius: 5px; } /* Это общий стиль flex-элементов */ p, span{ width: 40px; height: 40px; margin: auto; padding: 10px; background-color: #55aa55; border-radius: 5px; text-align: center; font-weight: bold; color: #F9F9F9; } /* Это класс для 1-го и 2-го div'ов */ .div_flex_1, .div_flex_2{ flex-flow: row wrap; } /* Это класс для 3-го и 4-го div'ов */ .div_flex_3, .div_flex_4{ flex-flow: column wrap; } </style> </head> <body> <div class="div_flex_1"> <p>1</p><span>2</span><p>3</p><span>4</span> <p>5</p><span>6</span><p>7</p><span>8</span> </div> <div class="div_flex_2"> <p>1</p><span>2</span> <p style="order: 1">3</p> <span>4</span><p>5</p> <span style="order: 8">6</span> <p>7</p><span>8</span> </div> <div class="div_flex_3"> <p>1</p><span>2</span><p>3</p><span>4</span> <p>5</p><span>6</span><p>7</p><span>8</span> </div> <div class="div_flex_4"> <p>1</p><span>2</span> <p style="order: 1">3</p> <span>4</span><p>5</p> <span style="order: 8">6</span> <p>7</p><span>8</span> </div> </body> </html>
Пример №6. Пример использования свойства order
В примере выше флекс-элементы первого и третьего блоков выводятся в заданном направлении согласно значениям их свойства flex-flow. А вот во втором и четвертом блоках этот порядок нарушается, т.к. к третьему и шестому элементам применяется свойство order, меняя порядок отображения этих элементов.
Поэкспериментируйте с кодом примера, применяя встроенный стиль с нашим свойством для разных флекс-элементов. Попробуйте не только положительные значения свойства, но и отрицательные.
css-свойство flex-grow
По умолчанию все флекс-элементы занимают свободное пространство своего флекс-контейнера на равных правах. Однако такое поведение можно именить при помощи ненаследуемого css-свойства flex-grow, которое применяется к флекс-элементам и определяет, какую долю свободного пространства будет занимать данный флекс-элемент по сравнению с другими флекс-элементами (см. пример №7). В качестве значений свойство принимает число, называемое коэффициентом роста флекс-элемента. Он может быть нулем (по умолчанию), а также положительным целым или дробным числом. При этом, чем больше коэффициент роста, тем большая доля свободного пространства достанется данному флекс-элементу по сравнению с другими элементами.
Чтобы рассчитать итоговый размер требуемого флекс-элемента можно использовать следующий алгоритм.
- Первый шаг. Рассчитываем свободное пространство флекс-контейнера (СПК). Для этого от ширины контейнера (ШК) (чистое пространство без паддингов) отнимаем сумму базовых размеров флекс-элементов (СБР), а также сумму их паддингов (СПЭ), соответствующих данному направлению: СПК = ШК - СБР - СПЭ.
-
Второй шаг. Рассчитываем размер доли свободного пространства (РДСП), которое займет данный флекс-элемент:
- если сумма всех коэффициентов роста флекс-элементов больше нуля, но меньше единицы (например, равна 0.8), то умножаем размер свободного пространства контейнера на коэффициент роста (КР) требуемого флекс-элемента: РДСП = СПК * КР;
- если сумма всех коэффициентов роста флекс-элементов больше единицы или равна ей, то размер свободного пространства умножаем на коэффициент роста данного элемента, а затем делим результат на сумму коэффициентов роста (СКР) всех элементов контейнера: РДСП = СПК * КР / СКР.
- Третий шаг. Рассчитываем итоговый размер флекс-элемента (ИР). Для этого прибавляем полученный размер доли свободного пространства контейнера занимаемого элементом к базовому размеру элемента: ИР = БР + РДСП.
Добавим, что в любом случае свободное пространство, которое распределяется между флекс-элементами с отличными от нуля коэффициентами роста, делится между ними пропорционально их коэффициентам роста и затем прибавляется к базовому размеру элемента.
Также отметим, что полученный алгоритм является результатом составления ряда пропорций и уравнений, которые могут быть решены в рамках школьной программы по математике. Но мы этим здесь заниматься не будем, а просто проверим алгоритм на практике.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <base href="https://html.okpython.net/"> <title>css-свойство flex-grow</title> <style> /* Оформляем родительские div'ы flex-элементов */ div{ display: flex; width: 500px; height: 120px; margin: auto; margin-top: 20px; background-color: #DFDFDF; border-radius: 5px; } /* Это общий стиль flex-элементов */ p, span{ width: 30px; padding: 10px; margin: auto; background-color: #55aa55; border-radius: 5px; text-align: center; font-weight: bold; color: #F9F9F9; } </style> </head> <body> <div> <p>1</p><span>2</span><p>3</p> </div> <div> <p>1</p><span>2</span> <p style="flex-grow: 0.5">3</p> </div> <div> <p>1</p> <span style="flex-grow: 0.3">2</span> <p style="flex-grow: 0.6">3</p> </div> <div> <p style="flex-grow: 0.5; width: 50px">1</p> <span style="flex-grow: 1; width: 70px">2</span> <p style="flex-grow: 1.5; width: 100px">3</p> </div> </body> </html>
Пример №7. Пример использования свойства flex-grow
Как видим, в первом блоке флекс-элементы не занимают свободное пространство флекс-контейнера, т.к. по умолчанию их коэффициенты роста равны нулю.
Во втором блоке мы применили встроенный стиль для третьего флекс-элемента, задав ему коэффициент роста 0.5. Т.к.
размер свободного пространства равен 500px-
В третьем блоке сумма коэффициентов роста равна 0.9 (т.е. меньше единицы), а размер свободного пространства равен
350px, т.к. 500px-
В четвертом блоке сумма коэффициентов роста равна 3 (т.е. больше единицы), поэтому элементы распределяют между собой
100% свободного пространства, что составляет величину в 220px, т.к.
500px-
Поэкспериментируйте с исходным кодом примера: поизменяйте коэффициенты роста элементов, количество самих элементов, у которых их значения будут отличны от нуля, попробуйте различные значения паддингов и ширины элементов, а в конце используйте свойство box-sizing: border-box и посмотрите, как изменится конечный результат при прочих равных условиях. Ну, и в конце хотелось бы напомнить, что результаты изменений вы можете отслеживать в инструментах для разработчиков в своем браузере.
css-свойство flex-shrink
Довольно часто может наблюдаться противоположная ситуация, когда свободное пространство в контейнере отсутствует, а флекс-элементам приходится сжиматься во избежание переполнения своего флекс-контейнера. По умолчанию в таких ситуациях все флекс-элементы отдают свое доступное пространство на общее благо на равных правах. Однако такое поведение можно именить при помощи ненаследуемого css-свойства flex-shrink, которое применяется к флекс-элементам и определяет, какую долю своего доступного пространства будет отдавать данный флекс-элемент по сравнению с другими флекс-элементами (см. пример №8). В качестве значений свойство принимает число, называемое коэффициентом сжатия флекс-элемента. Он может быть нулем (флекс-элемент не участвует в сжатии) или любым положительным целым или дробным числом (по умолчанию 1). При этом следует помнить, что при установке паддингов у флекс-элементов, они при сжатии не уменьшаются (уменьшаться может только сам базовый размер элемента). Кроме того, чем больше коэффициент сжатия, тем сильнее сжимается элемент по сравнению с другими элементами.
Чтобы рассчитать итоговый размер требуемого флекс-элемента можно использовать следующий алгоритм.
- Первый шаг. Рассчитываем размер свободного отрицательного пространства флекс-контейнера (РСОПК). Для этого от ширины контейнера (ШК) (чистое пространство без паддингов) отнимаем сумму базовых размеров флекс-элементов (СБР), а также сумму их паддингов (СПЭ), соответствующих данному направлению: РСОПК = ШК - СБР - СПЭ;
- Второй шаг. Находим сумму произведений (СПБР) базовых размеров (БР) флекс-элементов на их коэффициенты сжатия (КС): СПБР = БР1*КС1 + БР2*КС2 + ... + БРn*КСn, где n - общее число флекс-элементов контейнера.
- Третий шаг. Рассчитываем нормированный коэффициент сжатия (НКС) каждого флекс-элемента. Для этого находим произведение базового размера элемента на его коэффициент сжатия, а результат делим на сумму произведений всех базовых размеров флекс-элементов на их коэффициенты сжатия: НКС = БР*КС/СПБР.
- Четвертый шаг. Рассчитываем итоговый размер флекс-элемента (ИР). Для этого от базового размера флекс-элемента отнимаем произведение модуля размера свободного отрицательного пространства на нормированный коэффициент сжатия: ИР = БР - РСОПК*НКС.
Как видим, алгоритм расчета итогового размера флекс-элемента при сжатии сложнее аналогичного алгоритма при распределении свободного пространства между элементами. Это связано с тем, что при сжатии учитываются не только соотношения коэффициентов сжатия элементов, но и соотношения их размеров между собой. Однако вдаваться в подробности мы не будем, заметим только, что полученный алгоритм (опять же) является результатом составления ряда пропорций и уравнений, которые могут быть решены в рамках школьной программы по математике.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <base href="https://html.okpython.net/"> <title>css-свойство flex-shrink</title> <style> /* Оформляем родительские div'ы flex-элементов */ div{ display: flex; width: 300px; height: 120px; margin: auto; margin-top: 20px; background-color: #DFDFDF; border-radius: 5px; } /* Это общий стиль flex-элементов */ p, span{ width: 200px; min-width: 50px; padding: 10px; margin: auto; background-color: #55aa55; border-radius: 5px; text-align: center; font-weight: bold; color: #F9F9F9; } </style> </head> <body> <div> <p>1</p><span>2</span><p>3</p> </div> <div> <p style="flex-shrink: 3">1</p> <span style="flex-shrink: 3">2</span> <p style="flex-shrink: 3">3</p> </div> <div> <p>1</p><span>2</span> <p style="width: 250px;">3</p> </div> <div> <p>1</p><span>2</span> <p style="flex-shrink: 0">3</p> </div> <div> <p style="flex-shrink: 0.5">1</p> <span style="flex-shrink: 2; width: 300px;">2</span> <p style="flex-shrink: 6; width: 400px;">3</p> </div> </body> </html>
Пример №8. Пример использования свойства flex-shrink
В первом блоке флекс-элементы имеют одинаковый базовый размер (в нашем случае это ширина) в 200px и коэффициент сжатия равный 1 (установился по умолчанию). Рассчитываем размер свободного отрицательного пространства флекс-контейнера: 300px - 3*200px - 3*20px = -360px. Находим сумму произведений базовых размеров флекс-элементов на их коэффициенты сжатия: 200px*1 + 200px*1 + 200px*1 = 600px. Рассчитываем нормированный коэффициент сжатия каждого флекс-элемента (в нашем случае для всех элементов будет одинаковое значение): 200px*1/600px = 1/3. Получаем итоговые размеры наших флекс-элементов (тоже будут одинаковы): 200px - 360px*(1/3) = 80px ( и не забываем проверить результат в браузере в инструментах для разработчика).
Во втором блоке флекс-элементы также имеют одинаковый базовый размер (в нашем случае это ширина) в 200px и одинаковый коэффициент сжатия равный 3. Следовательно они также будут сжиматься полностью одинаково и будут иметь финальные размеры по 80px (схема та же, что и в первом блоке).
В третьем блоке все флекс-элементы имеют коэффициент сжатия равный 1 (установился по умолчанию), но для третьего флекс-элемента мы применили встроенный стиль, увеличив его ширину (базовый размер для нашего случая) до 250px. Рассчитываем размер свободного отрицательного пространства флекс-контейнера: 300px - 2*200px - 250px - 3*20px = -410px. Находим сумму произведений базовых размеров флекс-элементов на их коэффициенты сжатия: 200px*1 + 200px*1 + 250px*1 = 650px. Рассчитываем нормированный коэффициент сжатия каждого флекс-элемента: для первых двух элементов получаем 200px*1/650px = 4/13, а для третьего - 250px*1/650px = 5/13. Рассчитываем итоговые размеры наших флекс-элементов: для первого и второго элементов получаем величину 200px - 410px*(4/13) = 73.85px, а для третьего - 250px - 410px*(5/13) = 92.31px.
В четвертом блоке флекс-элементы имеют различные коэффициенты сжатия и размеры. Рассчитываем размер свободного отрицательного пространства флекс-контейнера: 300px - 200px - 300px - 400px - 3*20px = -660px. Находим сумму произведений базовых размеров флекс-элементов на их коэффициенты сжатия: 200px*0.5 + 300px*2 + 400px*6 = 3100px. Рассчитываем нормированный коэффициент сжатия каждого флекс-элемента: для первого элемента получаем 200px*0.5/3100px = 2/31, для второго - 300px*2/3100px = 6/31, а для третьего - 400px*6/3100px = 24/31. Рассчитываем итоговые размеры наших флекс-элементов: для первого элемента получаем величину 200px - 660px*(2/31) = 157.42px, для второго - 300px - 660px*(6/31) = 172.33px, а для третьего - 400px - 660px*(24/31) = -110.97px.
Т.к. итоговый размер третьего флекс-элемента стал меньше допустимого минимального размера элемента (в нашем случае это «min-width: 50px»), то ему присваиваем минимальный размер в 50px, а итоговые размеры первых двух элементов пересчитываем по алгоритму заново, но с учетом того, что третий элемент как бы имеет базовый размер в 50px и коэффициент сжатия 0. Итак, рассчитываем размер свободного отрицательного пространства флекс-контейнера: 300px - 200px - 300px - 50px - 3*20px = -310px. Находим сумму произведений базовых размеров флекс-элементов участвующих в сжатии на их коэффициенты сжатия: 200px*0.5 + 300px*2 = 700px. Рассчитываем нормированный коэффициент сжатия каждого флекс-элемента: для первого элемента получаем значение 200px*0.5/700px = 1/7, а для второго - 300px*2/700px = 6/7. Рассчитываем итоговые размеры наших флекс-элементов: для первого - 200px - 310px*(1/7) = 155.71px, а для второго - 300px - 310px*(6/7) = 34.29px.
Как видим, для второго элемента значение получилось меньше допустимого минимального, поэтому его ширину также устанавливаем в 50px, а коэффициент сжатия в 0. Повторяем алгоритм еще раз, но уже для одного оставшегося первого элемента. Рассчитываем размер свободного отрицательного пространства флекс-контейнера: 300px - 200px - 50px - 50px - 3*20px = -60px. Находим сумму произведений базовых размеров флекс-элементов участвующих в сжатии на их коэффициенты сжатия: 200px*0.5 = 100px. Рассчитываем нормированный коэффициент сжатия каждого флекс-элемента: 200px*0.5/100px = 1. Рассчитываем итоговый размер нашего флекс-элемента: 200px - 60px*1 = 140px.
Поэкспериментируйте с исходным кодом примера: поизменяйте коэффициенты сжатия элементов, попробуйте различные значения паддингов и ширины элементов, а в конце используйте свойство box-sizing: border-box и посмотрите, как изменится конечный результат при прочих равных условиях. Опять же, результаты изменений вы можете отслеживать в инструментах для разработчиков в своем браузере.
css-свойство flex-basis
Когда мы имеем дело с флекс-элементами, их базовый размер в зависимости от ситуации может быть как шириной элемента, так и его высотой. Однако в CSS присутствует ненаследуемое css-свойство flex-basis, позволяющее явно задать базовый размер флекс-элемента (см. пример №9). Соответственно, если свойство используется, его значение для определения базового размера будет иметь приоритет над значениями свойств width или height.
В качестве значений свойство flex-basis может принимать:
- auto – базовый размер флекс-элемента устанавливается автоматически в зависимости от размера его содержимого (используется по умолчанию);
- размер – разрешается использовать любые доступные в CSS единицы измерения длины, а также проценты, которые рассчитываются относительно размера флекс-контейнера.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <base href="https://html.okpython.net/"> <title>css-свойство flex-basis</title> <style> /* Оформляем родительские div'ы flex-элементов */ div{ display: flex; width: 500px; height: 100px; margin: auto; margin-top: 20px; background-color: #DFDFDF; border-radius: 5px; } /* Это общий стиль flex-элементов */ p, span{ flex-basis: 70px; width: 200px; min-width: 50px; height: 20px; padding: 10px; margin: auto; background-color: #55aa55; border-radius: 5px; text-align: center; font-weight: bold; color: #F9F9F9; } .flex_column{ flex-direction: column; height: 380px; } </style> </head> <body> <div> <p>1</p><span>2</span><p>3</p> </div> <div> <p style="flex-basis: 50px;">1</p> <span style="flex-basis: 100px;">2</span> <p style="flex-basis: 200px;">3</p> </div> <div class="flex_column"> <p>1</p><span>2</span> <p style="flex-basis: 40px;">3</p> </div> </body> </html>
Пример №9. Пример использования свойства flex-basis
В первом флекс-контейнере примера мы базовый размер для отдельных флекс-элементов не изменяли, поэтому все элементы визуально отображаются с шириной 70px (направление главной оси у нас горизонтальное, поэтому базовый размер переопределяет ширину). Высота же у всех элементов осталась такой, какой мы определили ее в таблицах стилей, т.е. 20px.
Во втором флекс-контейнере мы каждому флекс-элементу задали свой базовый размер. Высота при этом у всех также осталась равна 20px.
В третьем флекс-контейнере мы изменили направление главной оси на вертикальное и переопределили его высоту, установив новое значение в 380px (чтобы было хорошо видно колонку). Так как теперь направление главной оси вертикальное, базовый размер играет роль высоты. Поэтому мы и видим, что высота первых двух флекс-элементов увеличилась и стала равна базовому размеру, т.е. 70px. А вот ширина всех флекс-элементов стала равна 200px, как и было определено в таблице стилей (ведь в данном блоке базовый размер переопределяет уже высоту). Для третьего элемента мы для примера переопределили его базовый размер, поэтому его высота стала равна 40px, но ширина осталась равна 200px.
Сокращенное css-свойство flex
Для перечисленных выше трех свойств флекс-элементов в CSS предусмотрено сокращенное ненаследуемое css-свойство flex (см. пример №10), которое через пробел позволяет задавать коэффициент роста (по умолчанию используется 0), коэффициент сжатия (по умолчанию используется 1) и базовый размер флекс-элемента (по умолчанию используется auto). В случае необходимости разрешается также использовать и следующие служебные слова:
- none – соответствует комбинации flex: 0 0 auto;
- auto – соответствует комбинации flex: 1 1 auto.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <base href="https://html.okpython.net/"> <title>Универсальное css-свойство flex</title> <style> /* Оформляем родительские div'ы flex-элементов */ div{ display: flex; height: 150px; margin: auto; margin-top: 20px; background-color: #DFDFDF; border-radius: 5px; } /* Это общий стиль flex-элементов */ p, span{ flex: 1 1 150px; min-width: 50px; padding: 10px; margin: auto; background-color: #55aa55; border-radius: 5px; text-align: center; font-weight: bold; color: #F9F9F9; } .div_flex_1{width: 300px;} .div_flex_2{width: 600px;} </style> </head> <body> <div class="div_flex_1"> <p>1</p><span>2</span> <p style="flex-shrink: 2">3</p> </div> <div class="div_flex_2"> <p>1</p> <span>2</span> <p style="flex-grow: 10">3</p> </div> </body> </html>
Пример №10. Пример использования свойства flex
Для первого флекс-контейнера в примере мы установили заведомо малую ширину, чтобы флекс-элементам пришлось сжаться, при этом для третьего элемента мы переопределили коэффициент сжатия, заданный в таблице стилей сокращенным свойством flex.
Для второго флекс-контейнера мы наоборот установили заведомо большую ширину, чтобы флекс-элементам пришлось растянуться, при этом для третьего элемента мы переопределили коэффициент роста, заданный в таблице стилей сокращенным свойством flex.
css-свойство justify-content
Помимо управления направлением вывода флекс-элементов CSS предоставляет возможности и по выравниванию их вдоль требуемой оси. Начнем с главной оси. Для управления способом выравнивания флекс-элементов вдоль главной оси и распределения пространства между ними используется ненаследуемое css-свойство justify-content (см. пример №11), которое может принимать в качестве значений следующие ключевые слова:
- flex-start – флекс-элементы прижимаются к началу строки (используется по умолчанию);
- flex-end – флекс-элементы прижимаются к концу строки;
- center – флекс-элементы выравниваются по центру строки;
- space-between – флекс-элементы равномерно распределяются вдоль строки, но крайние из них прижимаются к соответствующим сторонам флекс-контейнера;
- space-around – флекс-элементы равномерно распределяются вдоль строки, но пустое пространство перед первым элементом и после последнего будет равно половине пространства между соседними флекс-элементами;
- space-evenly – флекс-элементы распределяются полностью равномерно, при этом пустое пространство перед первым элементом и после последнего будет такое же, как и между любыми соседними флекс-элементами.
Следует отметить, что если какие-либо флекс-элементы будут иметь ненулевые значения свойств margin или flex-grow, свойство justify-content будет игнорироваться.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <base href="https://html.okpython.net/"> <title>css-свойство justify-content</title> <style> /* Оформляем родительские div'ы flex-элементов */ div{ display: flex; width: 600px; height: 100px; margin: auto; margin-top: 10px; background-color: #DFDFDF; border-radius: 5px; } /* Это общий стиль flex-элементов */ p, span{ width: 40px; height: 40px; padding: 10px; background-color: #55aa55; border-radius: 5px; text-align: center; font-weight: bold; color: #F9F9F9; } /* Это класс для 1-го div'а */ .div_flex_1{ justify-content: flex-start; } /* Это класс для 2-го div'а */ .div_flex_2{ justify-content: flex-end; } /* Это класс для 3-го div'а */ .div_flex_3{ justify-content: center; } /* Это класс для 4-го div'а */ .div_flex_4{ justify-content: space-between; } /* Это класс для 5-го div'а */ .div_flex_5{ justify-content: space-around; } /* Это класс для 6-го и 7-го div'ов */ .div_flex_6, .div_flex_7{ justify-content: space-evenly; } /* Это класс для флексов 7-го div'а */ .div_flex_7>p, .div_flex_7>span{ margin: auto; } </style> </head> <body> <div class="div_flex_1"> <p>1</p><span>2</span><p>3</p> </div> <div class="div_flex_2"> <p>1</p><span>2</span><p>3</p> </div> <div class="div_flex_3"> <p>1</p><span>2</span><p>3</p> </div> <div class="div_flex_4"> <p>1</p><span>2</span><p>3</p> </div> <div class="div_flex_5"> <p>1</p><span>2</span><p>3</p> </div> <div class="div_flex_6"> <p>1</p><span>2</span><p>3</p> </div> <div class="div_flex_7"> <p>1</p><span>2</span><p>3</p> </div> </body> </html>
Пример №11. Пример использования свойства justify-content
Как видим, в последнем флекс-контейнере конструкция justify-content: space-evenly; не сработала, т.к. мы задали для флекс-элементов внешние отступы. Попробуйте сделать тоже самое в таблице стилей для всех флекс-элементов и посмотрите на результат.
css-свойства align-items и align-self
Для управления способом выравнивания флекс-элементов вдоль поперечной оси используются ненаследуемые css-свойства align-items и align-self (см. пример №12). Свойство align-items применяется к флекс-контейнеру и действует сразу на все его флекс-элементы, а свойство align-self применяется к флекс-элементам и позволяет управлять их выравниванием вдоль поперечной оси контейнера по-отдельности (переопределяя значение свойства align-items).
В качестве значений свойства могут принимать следующие ключевые слова:
- flex-start – флекс-элементы выравниваются в начале поперечной оси флекс-контейнера;
- flex-end – флекс-элементы выравниваются в конце поперечной оси флекс-контейнера;
- center – флекс-элементы выравниваются по линии поперечной оси флекс-контейнера;
- baseline – флекс-элементы выравниваются по их базовой линии;
- stretch – флекс-элементы растягиваются таким образом, чтобы занять всё доступное пространство контейнера.
Свойство align-self может принимать еще и значение auto. В этом случае будет использоваться значение свойства align-items для родительского флекс-контейнера или значение stretch, если родителя нет.
Что касается значений по умолчанию, то для align-items - это stretch, а для align-self - это auto.
Следует отметить, что если будут заданы значения внешних отступов margin в направлении поперечной оси, то свойства align-items и align-self будут игнорироваться.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <base href="https://html.okpython.net/"> <title>css-свойства align-items и align-self</title> <style> /* Оформляем родительские div'ы flex-элементов */ div{ display: flex; width: 600px; height: 100px; margin: auto; margin-top: 10px; background-color: #DFDFDF; border-radius: 5px; } /* Это общий стиль flex-элементов */ p, span{ width: 40px; height: 40px; padding: 10px; background-color: #55aa55; border-radius: 5px; text-align: center; font-weight: bold; color: #F9F9F9; } /* Это класс для 1-го div'а */ .div_flex_1{ align-items: flex-start; } /* Это класс для 2-го div'а */ .div_flex_2{ align-items: flex-end; } /* Это класс для 3-го div'а */ .div_flex_3{ align-items: center; } /* Это класс для флексов 3-го div'а */ .div_flex_3 p, .div_flex_3 span{ margin-left: 40px; } /* Это класс для 4-го div'а */ .div_flex_4{ align-items: baseline; } /* Это класс для 5-го div'а */ .div_flex_5{ align-items: stretch; } /* Это класс для 6-го и 7-го div'ов */ .div_flex_6, .div_flex_7{ align-items: center; height: 150px; } /* Это класс для флексов 7-го div'а */ .div_flex_7 p, .div_flex_7 span{ margin-top: 80px; } </style> </head> <body> <div class="div_flex_1"> <p>1</p><span>2</span><p>3</p> </div> <div class="div_flex_2"> <p>1</p><span>2</span><p>3</p> </div> <div class="div_flex_3"> <p>1</p><span>2</span><p>3</p> </div> <div class="div_flex_4"> <p>1</p><span>2</span><p>3</p> </div> <div class="div_flex_5"> <p>1</p><span>2</span><p>3</p> </div> <div class="div_flex_6"> <p style="align-self: flex-start">1</p> <span>2</span> <p style="align-self: flex-end">3</p> </div> <div class="div_flex_7"> <p>1</p><span>2</span><p>3</p> </div> </body> </html>
Пример №12. Пример использования свойств align-items и align-self
В третьем флекс-контейнере мы дополнительно задали внешние отступы вдоль главной оси (в нашем случае это горизонтальное направление). Как видим, выравнивание вдоль поперечной оси сохранилось.
В шестом флекс-контейнере мы переопределили значение свойства align-items для первого и последнего флекс-элементов при помощи свойства align-self, поэтому они и расположились лесенкой.
В последнем флекс-контейнере конструкция align-items: center; не сработала, т.к. мы дополнительно задали для флекс-элементов внешние отступы вдоль поперечной оси (в нашем случае она имеет вертикальное направление).
css-свойство align-content
Если флекс-элементов в контейнере достаточно много и у них есть возможность занимать несколько строк, возникает необходимость в выравнивании этих строк и распределении пространства между ними вдоль поперечной оси флекс-контейнера. Для этих целей в CSS предусмотрено ненаследуемое css-свойство align-content (см. пример №13), которое может принимать в качестве значений следующие ключевые слова:
- flex-start – строки располагаются в начале поперечной оси;
- flex-end – строки располагаются с конца поперечной оси;
- center – строки располагаются по центру флекс-контейнера;
- space-between – строки располагаются равномерно вдоль поперечной оси: расстояние между ними одинаково, но крайние строки прижимаются к соответствующим сторонам флекс-контейнера;
- space-around – строки располагаются равномерно вдоль поперечной оси: расстояние между ними одинаково, но расстояние между первой строкой и соответствующей стороной контейнера, а также расстояние между последней строкой и соответствующей стороной контейнера, равно половине расстояния между двумя соседними строками;
- space-evenly – строки располагаются полностью равномерно вдоль поперечной оси: расстояние между ними одинаково, при этом расстояние между первой строкой и соответствующей стороной контейнера, а также расстояние между последней строкой и соответствующей стороной контейнера, равно расстоянию между двумя соседними строками;
- stretch – строки равномерно растягиваются, заполняя свободное пространство (используется по умолчанию).
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <base href="https://html.okpython.net/"> <title>css-свойство align-content</title> <style> /* Оформляем родительские div'ы flex-элементов */ div{ display: flex; flex-wrap: wrap; align-items: center; width: 300px; height: 220px; margin: auto; margin-top: 10px; background-color: #DFDFDF; border-radius: 5px; } /* Это общий стиль flex-элементов */ p, span{ width: 60px; margin: auto; padding: 10px; background-color: #55aa55; border-radius: 5px; text-align: center; font-weight: bold; color: #F9F9F9; } /* Это класс для 1-го div'а */ .div_flex_1{ align-content: flex-start; } /* Это класс для 2-го div'а */ .div_flex_2{ align-content: flex-end; } /* Это класс для 3-го div'а */ .div_flex_3{ align-content: center; } /* Это класс для 4-го div'а */ .div_flex_4{ align-content: space-between; } /* Это класс для 5-го div'а */ .div_flex_5{ align-content: space-around; } /* Это класс для 6-го div'а */ .div_flex_6{ align-content: space-evenly; } </style> </head> <body> <div class="div_flex_1"> <p>1</p><span>2</span><p>3</p> <p>4</p><span>5</span><p>6</p> <p>7</p><span>8</span><p>9</p> </div> <div class="div_flex_2"> <p>1</p><span>2</span><p>3</p> <p>4</p><span>5</span><p>6</p> <p>7</p><span>8</span><p>9</p> </div> <div class="div_flex_3"> <p>1</p><span>2</span><p>3</p> <p>4</p><span>5</span><p>6</p> <p>7</p><span>8</span><p>9</p> </div> <div class="div_flex_4"> <p>1</p><span>2</span><p>3</p> <p>4</p><span>5</span><p>6</p> <p>7</p><span>8</span><p>9</p> </div> <div class="div_flex_5"> <p>1</p><span>2</span><p>3</p> <p>4</p><span>5</span><p>6</p> <p>7</p><span>8</span><p>9</p> </div> <div class="div_flex_6"> <p>1</p><span>2</span><p>3</p> <p>4</p><span>5</span><p>6</p> <p>7</p><span>8</span><p>9</p> </div> </body> </html>
Пример №13. Пример использования свойства align-content
Чтобы элементы имели одинаковые размеры и выравнивались равномерно в самих строках, мы для наглядности установили автоматические внешние отступы для всех флекс-элементов (margin: auto;).
Как видим, модуль CSS Flexbox предоставляет нам достаточно возможностей для создания гибких блоков, в которых мы можем практически любым способом выравнивать требуемый нам контент.
Быстрый переход к другим страницам
- Свойства связанные с курсором мыши
- Модуль CSS Flexbox
- @-правила
- Вернуться к оглавлению учебника