Flexbox: карточная раскладка
Карточная раскладка на Flexbox — контейнер с
flex-wrap: wrap, где карточки равномерно заполняют строки и выравниваются по высоте.
Зачем нужно
Карточки — один из самых распространённых UI-паттернов: товары, статьи, пользователи, проекты. Flexbox позволяет сделать равновысокие карточки с кнопкой, прижатой к низу, с минимальным кодом. Для адаптивной сетки лучше Grid, но Flexbox подходит для простых случаев.
Где используется
- Каталог товаров
- Список статей / блог
- Список пользователей / команда
- Портфолио проектов
- Список функций продукта
Основной контент
Базовая карточная сетка
.cards {
display: flex;
flex-wrap: wrap;
gap: 24px;
}
.card {
flex: 1 1 280px; /* растёт, сжимается, базовая ширина 280px */
/* Или фиксированная ширина */
flex: 0 0 calc(33.33% - 16px); /* 3 в ряд */
}
Равновысокие карточки с прижатой кнопкой
.cards {
display: flex;
flex-wrap: wrap;
gap: 24px;
}
.card {
flex: 1 1 280px;
display: flex;
flex-direction: column; /* Внутренний flex по вертикали */
border: 1px solid #e0e0e0;
border-radius: 8px;
overflow: hidden;
}
.card__image {
aspect-ratio: 16/9;
object-fit: cover;
width: 100%;
}
.card__body {
padding: 16px;
flex: 1; /* Растягивается — прижимает footer к низу */
}
.card__footer {
padding: 16px;
margin-top: auto; /* Прижат к низу */
border-top: 1px solid #e0e0e0;
}
<div class="cards">
<article class="card">
<img class="card__image" src="..." alt="...">
<div class="card__body">
<h2>Заголовок</h2>
<p>Описание карточки разной длины...</p>
</div>
<div class="card__footer">
<button>Подробнее</button>
</div>
</article>
<!-- ещё карточки -->
</div>
Ограничение по количеству в ряд
/* Ровно 3 в ряд */
.cards {
display: flex;
flex-wrap: wrap;
gap: 24px;
}
.card {
flex: 0 0 calc((100% - 48px) / 3);
/* 48px = 2 * gap */
}
/* Адаптивно */
@media (max-width: 768px) {
.card { flex: 0 0 calc(50% - 12px); }
}
@media (max-width: 480px) {
.card { flex: 0 0 100%; }
}
Частые ошибки
- Последняя неполная строка растягивается — при
justify-content: space-betweenпоследняя карточка одна растягивается на всю ширину; решение:justify-content: flex-startили Grid - Нет
min-widthна карточке — приflex: 1карточки могут сжаться до нуля; добавьтеmin-width: 200px - Не учтён
gapв расчёте —calc(33.33%)без вычетаgapприводит к переносу строки