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 приводит к переносу строки

Связанные темы

Ресурсы