Верстка по Flexbox (работа с элементами).
В этой cтатье мы с Вами продолжим изучать вопросы, касающиеся современной нативной верстки страниц сайта с помощью каскадных таблиц стилей с использованием модели Flexbox.
В предыдущей статье мы научились работать и производить всевозможные настройки флекс контейнеров с использованием современных CSS свойств, но этого недостаточно для того, чтобы решать многие задачи, связанные с версткой сайта.
Сейчас мы рассмотрим методы работы непосредственно с флекс элементами, научимся определять порядок их отображения в контейнере, научимся вертикально выравнивать конкретный флекс элемент, рассмотрим как указать относительную ширина флекс элемента, ширину флекс элемента по умолчанию и еще некоторые необходимые приемы работы с флекс элементами.
Порядок следования элементов
В этом разделе мы с Вами рассмотрим как с использованием Flexbox верстки задать порядок следования элементов внутри родительского элемента, что позволит простым способом решать сложные казалось бы задачи. CSS свойство order позволяет установлить порядок следования флекс элемента в контейнере относительно остальных.
Если элемент не является флекс элементом (не находится внутри родительского элемента, который является блочным, или строчным флекс контейнером), то свойство order, и любые свойства, предназначенные для работы с флекс элементами не окажут на такие элементы никакого эффекта.
Обращаю Ваше внимание, что если вы указываете значение свойства order для одного флекс элемента в контейнере, то это не будет являться его порядковым номером, а указывает только на "вес" его позиции по отношению к другим элементам. Допускается применение отрицательных значений (значение -1, например, смещает элемент к левому краю родительского контейнера). Значение по умолчанию 0.
Схематичное отображение работы свойства order отображено на следующем изображении:
В этом учебнике мы уже неоднократно сталкивались со свойством z-index, благодаря которому, вы можете управлять видимостью элементов по оси z, принцип указания значений свойства order аналогичен. Вы можете использовать в своей работе любые значения, которые будут вам интуитивно понятны, например, 100, 200, 300 и тому подобные.
Перейдем к рассмотрению примера:
<!DOCTYPE html> <html> <head> <title>Пример изменения следования элементов в колоннах</title> <style> .container, .container2, .container3 { display: flex; /* элемент отображается как блочный флекс контейнер */ } div > div { width: 50px; /* устанавливаем ширину блока */ height: 50px; /* устанавливаем высоту блока */ color: #fff; /* цвет текста */ margin: 1px; /* внешние отступы со всех сторон */ background: rgb(0,150,208); /* цвет заднего фона */ } .container div:nth-of-type(4) { /* выбираем четвертый <div> в первом контейнере */ order: -1; /* определяем порядок следования флекс элемента */ background: violet; /* цвет заднего фона */ } .container2 div:nth-of-type(4) { /* выбираем четвертый <div> во втором контейнере */ order: 1; /* определяем порядок следования флекс элемента */ background: violet; /* цвет заднего фона */ } .container3 div:nth-of-type(4) { /* выбираем четвертый <div> в третьем контейнере */ order: 2; /* определяем порядок следования флекс элемента */ background: violet; /* цвет заднего фона */ } </style> </head> <body> <p>order: -1;</p> <div class = "container"> <div>A</div> <div>B</div> <div>C</div> <div>D</div> <div>E</div> </div> <p>order: 1;</p> <div class = "container2"> <div>A</div> <div>B</div> <div>C</div> <div>D</div> <div>E</div> </div> <p>order: 2;</p> <div class = "container3"> <div>A</div> <div>B</div> <div>C</div> <div>D</div> <div>E</div> </div> </body> </html>
В этом примере мы разместили три блочных флекс контейнера, внутри них мы разместили по пять элементов <div>. С использованием псевдокласса :nth-of-type() указали для каждого четвертого элемента в определенном контейнере следующие значения свойства order:
- Для элемента в первом контейнере значение -1, что позволяет сместить элемент к левому краю родительского контейнера относительно остальных элементов, которые по умолчанию имеют значение 0 свойства order.
- Для элемента во втором контейнере значение 1, что позволяет сместить элемент к правому краю родительского контейнера относительно остальных элементов.
- Для элемента в третьем контейнере значение 2, что позволяет сместить элемент к правому краю родительского контейнера относительно остальных элементов. Еще раз обращаю Ваше внимание, что значение не является его порядковым номером, мы могли указать значение 100, 200, 500, элемент не изменит своей позиции так как другие элементы в контейнере имеют значение этого свойства равное 0.
Результат примера:
В следующем примере мы рассмотрим как происходит изменение следования элементов внутри колонн:
<!DOCTYPE html> <html> <head> <title>Пример изменения следования элементов в колоннах</title> <style> .container { display: flex; /* элемент отображается как блочный флекс контейнер */ flex-direction: column; /* флекс элементы отображаются вертикально как колонны (формируются сверху вниз) */ } .container:hover { flex-direction: column-reverse; /* флекс элементы отображаются вертикально как колонны (формируются снизу вверх) */ } div > div { height: 50px; /* устанавливаем высоту блока */ color: #fff; /* цвет текста */ margin: 1px; /* внешние отступы со всех сторон */ background: rgb(0,150,208); /* цвет заднего фона */ } .container div:nth-of-type(5) { /* выбираем пятый <div> в контейнере */ order: -100; /* определяем порядок следования флекс элемента */ background: violet; /* цвет заднего фона */ } .container div:nth-of-type(1) { /* выбираем первый <div> в контейнере */ order: 100; /* определяем порядок следования флекс элемента */ background: forestgreen; /* цвет заднего фона */ } </style> </head> <body> <div class = "container"> <div>A</div> <div>B</div> <div>C</div> <div>D</div> <div>E</div> </div> </body> </html>
В этом примере мы установили, что элементы внутри блочного флекс контейнера отображаются вертикально как колонны, формируясь сверху вниз (свойство flex-direction со значением column). В этом случае свойство order будет определять порядок следования элементов сверху вниз (элементы с меньшим номером будут отображаться выше, а с большим соответственно ниже).
Для первого элемента <div> с помощью псевдокласса :nth-of-type() мы установили значение свойства order равное 100, что позволило сместить его в конец всех элементов, а пятому элементу указали значение свойства order равное -100, что позволило сместить его влево перед всеми элементами.
Кроме того, мы указали, что при наведении на контейнер указателем мыши мы изменяем формирование колонны с сверху вниз на снизу вверх (свойство flex-direction со значением column-reverse). Обратите внимание, что в этом случае порядок следования элементов в колоннах изменяется на противоположный. Вы можете открыть пример в отдельном окне для демонстрации.
Результат примера:
Вертикальное выравнивание флекс элемента
В предыдущей cтатье "Верстка по Flexbox. Часть 1." мы с Вами рассмотрели как можно произвести выравнивание всех элементов внутри флекс контейнера. Но как быть, если какой то флекс элемент необходимо выровнять по особенному? На помощь нам приходит свойство align-self, которое задает выравнивание отдельных элементов строки внутри флекс контейнера. Кроме того, это свойство переопределяет значение выравнивания, заданного для контейнера свойством align-items конкретному элементу.
Обращаю Ваше внимание, что если для флекс элемента установлено свойство margin (внешние отступы) со значением auto, то свойство align-self будет игнорировано.
Схематичное отображение работы свойства align-self отображено на следующем изображении:
Перейдем к рассмотрению примера:
<!DOCTYPE html> <html> <head> <title>Использование свойства align-self</title> <style> .container { display: flex; /* элемент отображается как блочный флекс контейнер */ height: 250px; /* устанавливаем высоту контейнера */ background: rgba(0,150,208,.2); /* цвет заднего фона */ align-items: center; /* флекс элементы располагаются по центру контейнера (середина поперечной оси). */ } .container > div { /* устанавливаем стили для элементов <div>, вложенных в контейнер */ width: 20%; /* устанавливаем ширину блока */ color: #fff; /* цвет текста */ margin: 0 5px; /* внешние отступы */ background: rgb(0,150,208); /* цвет заднего фона */ text-align: center; /* горизонтальное выравнивание текста по центру */ } .container div:nth-of-type(1) { /* выбираем первый <div> в контейнере */ align-self: auto; /* флекс элемент наследует значение его родительского контейнера */ } .container div:nth-of-type(2) { /* выбираем второй <div> в контейнере */ align-self: stretch; /* флекс элемент растягивается по размеру строки флекс контейнера вдоль поперечной оси */ } .container div:nth-of-type(3) { /* выбираем третий <div> в контейнере */ align-self: flex-start; /* флекс элемент располагается в начале строки флекс контейнера (начало поперечной оси) */ } .container div:nth-of-type(4) { /* выбираем четвертый <div> в контейнере */ align-self: flex-end; /* флекс элемент располагается в конце строки флекс контейнера (конец поперечной оси) */ } .container div:nth-of-type(5) { /* выбираем пятый <div> в контейнере */ align-self: baseline; /* флекс элемент распологаются по его базовой линии строки флекс контейнера */ } </style> </head> <body> <div class = "container"> <div>auto (наследует center)</div> <div>stretch</div> <div>flex-start</div> <div>flex-end</div> <div>baseline</div> </div> </body> </html>
В этом примере мы создали блочный флекс контейнер, внутри которого мы разместили пять элементов <div> шириной 20% от родительского контейнера. С помощью свойства align-items указали, что все флекс элементы располагаются по центру контейнера (середина поперечной оси).
С использованием псевдокласса :nth-of-type() указали для каждого элемента свое значение свойства align-self.
Для первого элемента <div> мы установили значение auto (значение по умолчанию), что позволило унаследовать значение от родительского элемента, в данном случае это выполнено лишь для демонстрации, так как это не влияет на конечное отображение.
Для второго элемента <div> мы установили, что флекс элемент растягивается по размеру строки флекс контейнера вдоль поперечной оси. Если для контейнера не задано значение отличное от stretch, то именно это значение будет унаследовано.
Третий элемент располагается в начале строки флекс контейнера (начало поперечной оси), а четвертый располагается в конце строки флекс контейнера (конец поперечной оси).
Пятый флекс элемент располагается по его базовой линии строки флекс контейнера.
Результат примера:
Увеличение относительной ширины флекс элемента
Следующая полезная особенность Flexbox это возможность не производя каких-либо вычислений указывать относительную ширину для флекс элементов, а не абсолютную (в единицах измерения CSS), или в процентном соотношении. Например, если внутри флекс контейнера для одного элемента будет указано, что его ширина будет в два раза больше по отношению к остальным элементам, и если мы добавим в контейнер еще один блок, то при этом ширина контейнера не изменится, а элемент по прежнему останется в два раза больше остальных, при этом ширина всех блоков пропорционально уменьшится.
Определить на сколько элемент может увеличиться по отношению к остальным флекс элементам в одном контейнере доступно с помощью свойства flex-grow.
Обращаю Ваше внимание на то, что отрицательные значения свойства flex-grow не допускаются. Значение по умолчанию 0 - элементы не будут увеличиваться.
Перейдем к рассмотрению примера:
<!DOCTYPE html> <html> <head> <title>Использование свойства flex-grow</title> <style> .container, .container2, .container3 { display: flex; /* элементы отображаются как блочные флекс контейнеры */ height: 100px; /* устанавливаем высоту для контейнеров */ } div > div { color: #fff; /* цвет текста */ margin: 5px; /* внешние отступы со всех сторон */ background: rgb(0,150,208); /* цвет заднего фона */ font-size: 20px; /* размер шрифта */ text-align: center; /* горизонтальное выравнивание текста по центру */ } .container div:nth-of-type(1), .container div:nth-of-type(3), .container2 div:nth-of-type(1), .container2 div:nth-of-type(3), .container3 div:nth-of-type(1), .container3 div:nth-of-type(3) { flex-grow: 1; /* блок будет увеличен на 1 по отношению к остальным флекс элементам */ } .container div:nth-of-type(2) { flex-grow: 2; /* блок будет увеличен на 2 по отношению к остальным флекс элементам */ } .container2 div:nth-of-type(2) { flex-grow: 3; /* блок будет увеличен на 3 по отношению к остальным флекс элементам */ } .container3 div:nth-of-type(2) { flex-grow: 4; /* блок будет увеличен на 4 по отношению к остальным флекс элементам */ } </style> </head> <body> <div class = "container"> <div>1</div> <div>2</div> <div>1</div> </div> <div class = "container2"> <div>1</div> <div>3</div> <div>1</div> </div> <div class = "container3"> <div>1</div> <div>4</div> <div>1</div> </div> </body> </html>
В этом примере мы разместили три блочных флекс контейнера, внутри них мы разместили по три элемента <div>. С использованием псевдокласса :nth-of-type() указали для каждого первого и третьего элемента в каждом контейнере, что блок будет увеличен на 1 по отношению к остальным флекс элементам. Для каждого второго элемента в контейнерах указали различные значения свойства flex-grow.
В первом контейнере второй элемент будет увеличен на 2 по отношению к остальным флекс элементам, во втором контейнере на 3, а в третьем уже на четыре. Обратите внимание, как пропорцианально изменятся ширина элементов, не прибегая с нашей стороны к каким-либо расчетам, или использованию дополнительных функций.
Результат примера:
Размер флекс элемента по умолчанию
В предыдущем разделе мы с Вами рассмотрили как можно установить для флекс элементов относительную ширину по отношению к другим флекс элементам. В этом разделе мы рассмотрим еще одно свойство для работы с шириной флекс элемента. Свойство flex-basis позволит нам определить размер для флекс элемента, установленный по умолчанию перед тем как пространства внутри флекс контейнера будет распределено между другими элементами.
В отличии от свойства flex-grow используются как абсолютные значения (px, em, pt и так далее), так и значения в процентах, а не относительные значения, при этом отрицательные значения не допускаются. Значением по умолчанию является значение auto (размер равен размеру флекс элемента). Если элемент не имеет заданного размера, то размер будет высчитываться в зависимости от содержания флекс элемента.
Это свойство чем то похоже, на свойство определяющее минимальную ширину элемента (min-width), но в отличии от него свойство flex-grow не вызывает переполнение родительского элемента в том случае, если минимальный размер будет превышать размеры родительского элемента, а пропорционально уменьшает размер элемента. Другими словами это свойство определяет минимальный размер флекс элемента, который при необходимости может быть уменьшен, или увеличен.
Перейдем к рассмотрению примера:
<!DOCTYPE html> <html> <head> <title>Использование свойства flex-basis</title> <style> .container, .container2, .container3 { display: flex; /* элементы отображаются как блочные флекс контейнеры */ height: 95px; /* устанавливаем высоту для контейнеров */ background: rgba(0,150,208,.3); /* цвет заднего фона */ margin-bottom: 5px; /* внешние отступы снизу */ } div > div { color: #fff; /* цвет текста */ margin: 5px; /* внешние отступы со всех сторон */ background: rgb(0,150,208); /* цвет заднего фона */ font-size: 20px; /* размер шрифта */ text-align: center; /* горизонтальное выравнивание текста по центру */ } .container div:nth-of-type(1), .container div:nth-of-type(3), .container2 div:nth-of-type(1), .container2 div:nth-of-type(3), .container3 div:nth-of-type(1), .container3 div:nth-of-type(3) { flex-basis: auto; /* размер будет высчитываться в зависимости от содержания элемента */ } .container div:nth-of-type(2) { flex-basis: 100px; /* размер для флекс элемента по умолчанию составляет 100px */ } .container2 div:nth-of-type(2) { flex-basis: 200px; /* размер для флекс элемента по умолчанию составляет 200px */ } .container3 div:nth-of-type(2) { flex-basis: 10000px; /* размер для флекс элемента по умолчанию составляет 10000px */ } </style> </head> <body> <div class = "container"> <div>auto</div> <div>100px</div> <div>auto</div> </div> <div class = "container2"> <div>auto</div> <div>200px</div> <div>auto</div> </div> <div class = "container3"> <div>auto</div> <div>10 000px</div> <div>auto</div> </div> </body> </html>
В этом примере мы разместили три блочных флекс контейнера, внутри них мы разместили по три элемента <div>. С использованием псевдокласса :nth-of-type() указали для каждого первого и третьего элемента в каждом контейнере, что их размер будет высчитываться в зависимости от содержания элемента. Для каждого второго элемента в контейнерах указали различные значения свойства flex-basis.
В первом контейнере указали для второго флекс элемента размер по умолчанию 100px, во втором контейнере 100px, а в третьем уже 10000px. Обратите внимание, что в третьем контейнере элемент не смотря на его размеры не вызвал переполнение, а подстроился под оставшееся в родительском контейнере пространство.
Результат примера:
Уменьшение относительной ширины флекс элемента
Ранее мы с Вами рассмотрели как с помощью свойства flex-grow указать относительную ширину для флекс элементов и определить на сколько элемент может увеличиться по отношению к остальным флекс элементам. В CSS доступно и другое поведение для флекс элементов, при котором флекс элемент будет сжиматься относительно остальных флекс элементов в контейнере (при недостатке свободного пространства). За эту возможность отвечает свойтво flex-shrink.
Значение, определяющее на сколько будет уменьшен блок по отношению к остальным флекс элементам в контейнере (при недостатке свободного пространства) задается по аналогии со свойством flex-grow, но при этом значением по умолчанию будет 1, а не 0. Отрицательные значения так же не допускаются (не валидны).
Свойство flex-shrink со значением 0 определяет, что элемент не будет сжиматься, сохраняя при этом необходимую ширину элемента! Если вместе с этим значением указано минимальное значение ширины флекс элемента по умолчанию (свойство flex-basis), то элемент не сможет уменьшиться меньше этого значения. Используйте эту возможность осмысленно, так как существует вероятность переполнения содержимого флекс контейнера. Этот момент мы рассмотрим в конце статьи
Перейдем к рассмотрению примера:
<!DOCTYPE html> <html> <head> <title>Использование свойства flex-shrink</title> <style> .container, .container2, .container3 { display: flex; /* элементы отображаются как блочные флекс контейнеры */ width: 400px; /* устанавливаем ширину для контейнеров */ height: 95px; /* устанавливаем высоту для контейнеров */ background: rgba(0,150,208,.3); /* цвет заднего фона */ margin-bottom: 5px; /* внешние отступы снизу */ } div > div { color: #fff; /* цвет текста */ margin: 5px; /* внешние отступы со всех сторон */ background: rgb(0,150,208); /* цвет заднего фона */ font-size: 20px; /* размер шрифта */ text-align: center; /* горизонтальное выравнивание текста по центру */ flex-basis: 200px; /* размер для флекс элемента по умолчанию составляет 200px */ } .container div:nth-of-type(2) { flex-shrink: 2; /* блок будет уменьшен на 2 по отношению к остальным флекс элементам (при недостатке пространства) */ } .container2 div:nth-of-type(2) { flex-shrink: 3; /* блок будет уменьшен на 3 по отношению к остальным флекс элементам (при недостатке пространства) */ } .container3 div:nth-of-type(2) { flex-shrink: 4; /* блок будет уменьшен на 4 по отношению к остальным флекс элементам (при недостатке пространства) */ } </style> </head> <body> <div class = "container"> <div>1</div> <div>2</div> <div>1</div> </div> <div class = "container2"> <div>1</div> <div>3</div> <div>1</div> </div> <div class = "container3"> <div>1</div> <div>4</div> <div>1</div> </div> </body> </html>
В этом примере мы разместили три блочных флекс контейнера, внутри них мы разместили по три элемента <div>. Для контейнера мы задали ширину равную 400 пикселей, а для каждого вложенного флекс элемента с помощью свойства flex-basis указали размер по умолчанию равный 200px. Это было сделано для того, чтобы смоделировать ситуацию, при которой элемент у которого значение свойства flex-shrink больше остальных сжимался.
С использованием псевдокласса :nth-of-type() указали для каждого второго элемента в контейнерах различные значения свойства flex-shrink. В первом контейнере второй элемент при недостатке пространства будет уменьшен на 2 по отношению к остальным флекс элементам, во втором контейнере на 3, а в третьем уже на четыре и всё это проиходит автоматически, не прибегая с нашей стороны к каким-то усилиям.
Результат примера:
Универсальное свойство flex
CSS свойство flex является короткой записью для свойств, которые позволяют определить размер для флекс элемента, установленный по умолчанию, указать на сколько элемент может увеличиться и уменьшиться по отношению к остальным флекс элементам в одном контейнере, а именно:
- flex-grow (значение по умолчанию 0).
- flex-shrink (значение по умолчанию 1).
- flex-basis (значение по умолчанию auto).
Обратите внимание на некоторые нюансы использования свойства flex:
- Если указывается одно числовое значение, то оно устанавливается для свойства flex-grow, если указаны единицы измерения CSS, то соответственно для flex-basis.
- Если второе значение соответствует числовому значению, то оно устанавливается для flex-shrink, а если указаны единицы измерения CSS, то для flex-basis.
Перейдем к рассмотрению примера:
<!DOCTYPE html> <html> <head> <title>Использование свойства flex</title> <style> * { margin: 0; /* внешние отступы со всех сторон отсутствуют */ color: #fff; /* цвет текста */ } .content { display: flex; /* элемент отображается как блочный флекс контейнер */ height: calc(100vh - 200px); /* высчитываем высоту для элемента */ background: #999; /* цвет заднего фона */ } section { display: flex; /* элемент отображается как блочный флекс контейнер */ } header, footer { height: 100px; /* устанавливаем высоту для элементов */ background: #777; /* цвет заднего фона */ } aside { flex: 1; /* указываем на сколько элемент может увеличиться по отношению к остальным флекс элементам (flex-grow) */ } main { background: #aaa; /* цвет заднего фона */ flex: 5 0 450px; /* grow shrink basis */ } section > div { background: #333; /* цвет заднего фона */ margin: 5px; /* внешние отступы со всех сторон */ flex: 1 1 100px; /* grow shrink basis */ height: 100px; /* устанавливаем высоту для элементов */ } </style> </head> <body> <header>header</header> <div class = "content"> <aside>aside</aside> <main>main <section> <div>div</div> <div>div</div> <div>div</div> <div>div</div> </section> </main> <aside>aside</aside> </div> <footer>footer</footer> </body> </html>
В этом примере мы:
- Разместили элемент <header> вверху страницы и <footer> внизу страницы, указали для них высоту равную 100 пикселям и определенный цвет заднего фона.
- Элементу <div> с классом content указали, что он является блочным флекс контейнером и задали высоту, которая высчитывается с помощью функции calc() (100vh (viewport height) 100% от высоты области просмотра минус 200px, которые мы задали для элементов <header> и <footer>). Внутри контейнера мы разместили три флекс элемента: два элемента <aside> и один элемент <main>.
- Для флекс элементов <aside> мы указали, что они будут увеличены на 1 по отношению к остальным флекс элементам, а элементу <main> указали значение 5, то есть он будет занимать 5 из 7 частей внутри контейнера (свойство flex-grow). Кроме того, внутри универсального свойства flex мы указали элементу <main> значение 0 свойства flex-shrink, и указали ширину элемента по умолчанию равную 450px (flex-basis). При таком сочетании свойств это означает, что элемент не будет сжиматься и его ширина не сможет уменьшится меньше 450 пикселей, что приведет при недостатке пространства к переполнению флекс контейнера.
- Внутри флекс элемента <main> мы разместили элемент <section>, которому мы указали, что он является блочным флекс контейнером. Внутри него мы разместили четыре флекс элемента <div>. Для них мы указали, что они будут увеличены на 1 по отношению к остальным флекс элементам (свойство flex-grow), при недостатке пространства элементы будут уменьшены на 1 по отношению к остальным флекс элементам (значение по умолчанию свойства flex-shrink), и указали ширину элементов по умолчанию равную 100px (свойство flex-basis).
Результат примера: