Верстка / Многострочный flex

Сегодня будем учится верстать в столбик. В строчку вроде как уже умеем.

Вспоминания

В строчку обычно как? Например, вот так

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css" />
</head>
<body>
    
<div class="row">
    <div class="block">
        тут собачка живет 
        <i class="fas fa-2x fa-dog"></i>
    </div>

    <div class="block">
        <i class="fas fa-2x fa-cat"></i>
    </div>

    <div class="block">
        <i class="fas fa-2x fa-kiwi-bird"></i>
    </div>
</div>

<style>
    .row {
        display: flex;
    }
	
    .block {
        border: 1px solid black;
        margin: 0.25em;
        padding: 0.5em;
    }
</style>

</body>
</html>

и по умолчанию все зверики занимают ровно столько сколько им надо

если я хочу, чтобы каждый занимал какое-то специфическое пространство я стало быть добавляю свойство flex-grow: 1

<div class="row">
    <div class="block" style="flex-grow: 1;">
        тут собачка живет 
        <i class="fas fa-2x fa-dog"></i>
    </div>

    <div class="block"  style="flex-grow: 1;">
        <i class="fas fa-2x fa-cat"></i>
    </div>

    <div class="block"  style="flex-grow: 1;">
        <i class="fas fa-2x fa-kiwi-bird"></i>
    </div>
</div>

в этом случае как ты помнишь идет равномерное распределение пустого пространства

то есть, если я хочу, чтобы равномерными были именно размеры, то я добавляю flex-basis: 0

<div class="row">
    <div class="block" style="flex-basis: 0; flex-grow: 1;">
        тут собачка живет 
        <i class="fas fa-2x fa-dog"></i>
    </div>

    <div class="block"  style="flex-basis: 0; flex-grow: 1;">
        <i class="fas fa-2x fa-cat"></i>
    </div>

    <div class="block"  style="flex-basis: 0; flex-grow: 1;">
        <i class="fas fa-2x fa-kiwi-bird"></i>
    </div>
</div>

и все ровно встает:

А теперь посмотрим, как все это работает, когда я делаю верстку в столбик.

Верстаем в столбик

Чтобы сделать верстку в столбик надо добавить свойство flex-direction: column, вот так

<style>
    .block {
        /* ... */
    }

    .column { /* переименовал в column, не забудь переименовать выше, где class="row" */
        display: flex;
        flex-direction: column; /* добавил */
    }
</style>

и тут же все превращается в колонку

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

<div class="column">
    <div class="block" style="flex-basis: 0; flex-grow: 1;">
        тут собачка живет 
        <i class="fas fa-2x fa-dog"></i>
    </div>

    <div class="block"  style="flex-basis: 0; flex-grow: 2;"> <!-- заменил тут на flex-grow: 2; -->
        <i class="fas fa-2x fa-cat"></i>
    </div>

    <div class="block"  style="flex-basis: 0; flex-grow: 1;">
        <i class="fas fa-2x fa-kiwi-bird"></i>
    </div>
</div>

проверяем:

Хм, шо за ерунда?

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

То есть 100% ширины — это всегда понятно сколько, от левого края до правого. А вот 100% высоты — это не понятно, как считать. Это от верха видимого куска страницы до низа видимого куска страницы, или до низа если проскроллить, или еще как? Неясно в общем.

Поэтому при вертикальной верстке всегда важно указывать высоту колонки. Например, я укажу что высота моей колонки 300px

<div class="column" style="height: 300px">  <!-- добавил height: 300px -->
    <div class="block" style="flex-basis: 0; flex-grow: 1;">
        тут собачка живет 
        <i class="fas fa-2x fa-dog"></i>
    </div>

    <div class="block"  style="flex-basis: 0; flex-grow: 2;">
        <i class="fas fa-2x fa-cat"></i>
    </div>

    <div class="block"  style="flex-basis: 0; flex-grow: 1;">
        <i class="fas fa-2x fa-kiwi-bird"></i>
    </div>
</div>

о, и сразу все заработало

flex-basis: 0; ведет себя точно так же как и в горизонтальной верстке, то есть без него будет попытка распределить пустое пространство:

тут не сильно разницу видно, но она есть.

Выравнивание блоков внутри колонки

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

Уберу-ка я у блоков flex-grow и flex-basis и добавлю цвет колонке

<div class="column" style="height:300px;  background-color: rgb(167, 242, 255);">
    <div class="block" style="">
        тут собачка живет 
        <i class="fas fa-2x fa-dog"></i>
    </div>

    <div class="block"  style="">
        <i class="fas fa-2x fa-cat"></i>
    </div>

    <div class="block"  style="">
        <i class="fas fa-2x fa-kiwi-bird"></i>
    </div>
</div>

получится так

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

По умолчанию оно имеет значение stretch (что переводится как растянуть)

.column {
    align-items: stretch; /* добавил, прописал значение по умолчанию*/
    display: flex;
    flex-direction: column;
}

и соответственно меняя его я могу менять то, как будут выравниваться блоки по горизонтали внутри:

Например align-items: flex-start;

или align-items: center;

или в конец если хочу загнать align-items: flex-end;

но самая радость появляется что мы можем управлять положением блоков не только по горизонтали, но и по вертикали. Для этого используется свойство justify-content. По умолчанию оно имеет значение flex-start, то есть выравнивать по верху блока

.column {
    justify-content: flex-start; /* добавил */
    align-items: flex-end; 
    display: flex;
    flex-direction: column;
}

но я могу так же попросить его выравнивать по центру

.column {
    justify-content: center; /* поменял на center */
    align-items: flex-end; 
    display: flex;
    flex-direction: column;
}

а если еще и align-items: center; сделать:

можно и вниз опустить

.column {
    justify-content: flex-end; /* поменял на flex-end */
    align-items: center; 
    /* ... */
}

еще есть интересный режим который равномерно распределяет расстояние между блоками, почти как flex-grow только блоки занимают ровно столько места сколько им надо:

.column {
    justify-content: space-between; /* поменял на space-between */
    align-items: center; 
    /* ... */
}

есть еще такой:

.column {
    justify-content: space-around; /* поменял на space-around */
    align-items: center; 
    /* ... */
}

и такой:

.column {
    justify-content: space-evenly; /* поменял на space-evenly */
    align-items: center; 
    /* ... */
}

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

Несколько колонок в строчку

Естественно одна колонка — это не очень интересно, и намного интереснее объединять колонки в строчки. Используя уже знакомый нам горизонтальный флекс.

Допустим хочу я три колонки в ряд, сначала я просто скопирую блок с колонкой три раза:

<div class="column" style="height:300px; background-color: rgb(167, 242, 255);">
    <!-- ... -->
</div>

<div class="column" style="height:300px; background-color: rgb(167, 242, 255);">
    <!-- ... -->
</div>

<div class="column" style="height:300px; background-color: rgb(167, 242, 255);">
   <!-- ... -->
</div>

он мне все три колонки положит в одну мега колонк (то есть каждая колонка окажется под следующей), потому что это стандартное поведение div блоков, и по сути я получу колонку в три раза выше.

Чтобы поставить колонки в строчку я оберну все в обыкновенный flex блок, вот так

<div style="display: flex;">
	<div class="column" style="height:300px; background-color: rgb(167, 242, 255);">
			<!-- ... -->
	</div>

	<div class="column" style="height:300px; background-color: rgb(167, 242, 255);">
			<!-- ... -->
	</div>

	<div class="column" style="height:300px; background-color: rgb(167, 242, 255);">
		 <!-- ... -->
	</div>
</div>

и ура, теперь три колонки в ряд:

каждой колонке я могу указать как размещать блоки в ней

<div style="display: flex;">
    <div class="column" style="justify-content: flex-start; height:300px; background-color: rgb(167, 242, 255);">
        <!-- ... -->
    </div>

    <div class="column" style="align-items: stretch; justify-content: space-evenly;  height:300px; background-color: rgb(167, 242, 255);">
        <!-- ... -->
    </div>

    <div class="column" style="align-items: flex-end; justify-content: flex-end; height:300px; background-color: rgb(167, 242, 255);">
        <!-- ... -->
    </div>
</div>

вот так получится

на большом экране они скорее всего займут не всю строчку

если ты хочешь, чтобы они растягивались на всю ширину, просто добавь свойство flex-grow: 1 каждой колонке. Я еще цвет каждой поменял тут чтобы лучше видно было

<div style="display: flex;">
    <div class="column" style="flex-grow:1; justify-content: flex-start; height:300px; background-color: rgb(167, 242, 255);">
        <!-- ... -->
    </div>

    <div class="column" style="flex-grow:1; align-items: stretch; justify-content: space-evenly;  height:300px; background-color: rgb(126, 171, 255);">
        <!-- ... -->
    </div>

    <div class="column" style="flex-grow:1; align-items: flex-end; justify-content: flex-end; height:300px; background-color: rgb(171, 147, 255);">
        <!-- ... -->
    </div>
</div>

колонки ведут себя так же как обыкновенные блоки. То есть я могу попросить вторую колонку стать в два раза толще других, если укажу ей flex-grow: 2

<div style="display: flex;">
    <div class="column" style="...">
        <!-- ... -->
    </div>

    <div class="column" style="flex-grow:2; align-items: stretch; justify-content: space-evenly;  height:300px; background-color: rgb(126, 171, 255);">
        <!-- ... -->
    </div>

    <div class="column" style="...">
        <!-- ... -->
    </div>
</div>

тут опять распределится именно пустое пространство, если хочешь чтобы было четко, то добавляешь flex-basis: 0

<div style="display: flex;">
    <div class="column" style="flex-basis: 0; ...">
        <!-- ... -->
    </div>

    <div class="column" style="flex-basis: 0; flex-grow:2; ...">
        <!-- ... -->
    </div>

    <div class="column" style="flex-basis: 0; ...">
        <!-- ... -->
    </div>
</div>

хошь конкретные размеры, прописываешь в пикселях в свойство flex-basis, попутно убирая flex-grow:

<div style="display: flex;">
    <div class="column" style="flex-basis: 100px; justify-content: flex-start; height:300px; background-color: rgb(167, 242, 255);">
        <!-- ... -->
    </div>

    <div class="column" style="...">
        <!-- ... -->
    </div>

    <div class="column" style="...">
        <!-- ... -->
    </div>
</div>

в общем все как обычно, прямо как в прошлой задачке. Ну все можно пилить задачку =)

6

Сверстать вот так

если вдруг, то тут три строчки и у каждой колонки в строчке фиксированная ширина и высота, то есть flex-grow колонкам не ставим.