Как сверстать карточки тарифов
Эта статья основана на одном из практических заданий verstaem.online.
Вы можете читать материал как обычное руководство или сначала попробовать выполнить задание самостоятельно, а затем сравнить свое решение с подробным разбором.
Перейти к заданиюВ этой статье мы создадим блок с тарифными планами, состоящий из нескольких карточек с названием, ценой, описанием, списком возможностей и кнопкой действия. На его примере разберем, как создавать карточки одинаковой высоты, использовать Flexbox для построения вертикального интерфейса, оформлять различные состояния компонентов и применять модификаторы БЭМ.
Создаем HTML-разметку
Сначала создадим базовую HTML-разметку с помощью Emmet. Для этого достаточно ввести ! и нажать Tab. Обратите внимание на атрибут lang. Поскольку основной контент страницы написан на русском языке, здесь используем значение ru.
<!doctype html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Карточки тарифов</title>
</head>
<body>
</body>
</html>
Идем далее. Поскольку перед нами сразу несколько однотипных карточек, логично использовать обычный список <ul>. Каждая карточка станет отдельным элементом <li>, а внутри него разместим самостоятельный компонент — <article>.
<ul class="tariffs">
<li class="tariffs__item">
<article class="tariffs-card">
</article>
</li>
</ul>
Теперь можно переходить к содержимому карточки. Сверху разместим название тарифа, затем цену, описание и список возможностей. Для списка преимуществ отлично подходит обычный <ul>, как перечисление преимуществ тарифа. Последним элементом станет кнопка действия. После этого останется лишь продублировать карточку несколько раз и заменить текст. И еще помимо этого нужно добавить дополнительный класс, чтобы затем отдельно выделить среднюю карточку.
<ul class="tariffs">
<li class="tariffs__item">
<article class="tariffs-card">
<h3 class="tariffs-card__title">Start</h3>
<div class="tariffs-card__price">
0 <span>₽ / месяц</span>
</div>
<p class="tariffs-card__descr">
Для знакомства с платформой и первых практических заданий.
</p>
<ul class="tariffs-card__list">
<li class="tariffs-card__item">
Базовые задания
</li>
<li class="tariffs-card__item">
Публичный профиль
</li>
</ul>
<button class="tariffs-card__btn">
Начать бесплатно
</button>
</article>
</li>
<li class="tariffs__item">
<article class="tariffs-card tariffs-card--best">
<h3 class="tariffs-card__title">Pro</h3>
<div class="tariffs-card__price">
990 <span>₽ / месяц</span>
</div>
<p class="tariffs-card__descr">
Для полноценной практики, подробных разборов и постоянного развития навыков вёрстки.
</p>
<ul class="tariffs-card__list">
<li class="tariffs-card__item">
Все задания платформы
</li>
<li class="tariffs-card__item">
Система достижений
</li>
<li class="tariffs-card__item">
Подробные разборы решений
</li>
<li class="tariffs-card__item">
Ранний доступ к новым заданиям
</li>
</ul>
<button class="tariffs-card__btn">
Выбрать тариф
</button>
</article>
</li>
<li class="tariffs__item">
<article class="tariffs-card">
<h3 class="tariffs-card__title">Team</h3>
<div class="tariffs-card__price">
2 490 <span>₽ / месяц</span>
</div>
<p class="tariffs-card__descr">
Для совместной работы, командных проектов и общего отслеживания прогресса.
</p>
<ul class="tariffs-card__list">
<li class="tariffs-card__item">
Командные проекты
</li>
<li class="tariffs-card__item">
Общий прогресс
</li>
<li class="tariffs-card__item">
Совместные материалы
</li>
</ul>
<button class="tariffs-card__btn">
Связаться с нами
</button>
</article>
</li>
</ul>
Добавляем стили
Подключим файл стилей через <link> и зададим несколько базовых правил. Для этого задания достаточно переопределить box-sizing, сбросить отступ у <body> и подключить шрифт Inter, который используется в макете.
* {
box-sizing: border-box;
}
@font-face {
font-family: "Inter";
src: url("../fonts/InterRegular.woff2");
font-display: swap;
font-weight: 400;
}
@font-face {
font-family: "Inter";
src: url("../fonts/InterBold.woff2");
font-display: swap;
font-weight: 700;
}
@font-face {
font-family: "Inter";
src: url("../fonts/InterExtraBold.woff2");
font-display: swap;
font-weight: 800;
}
body {
margin: 0;
background: #fff8f2;
font-family: "Inter", sans-serif;
}
Далее работаем над списком и его элементами. Списку достаточно задать display: flex, а также gap, а карточкам — flex: 1. Благодаря этому все карточки автоматически поделят между собой доступную ширину и будут выглядеть одинаково аккуратно независимо от размера окна браузера.
.tariffs {
display: flex;
list-style: none;
margin: 0 auto;
padding: 20px;
max-width: 1020px;
gap: 20px;
}
.tariffs__item {
flex: 1;
}
Теперь оформим саму карточку. Здесь снова нужен Flexbox, но направление вертикальное. Так все элементы будут располагаться сверху вниз, а мы сможем свободно управлять распределением пространства внутри карточки. Дополнительно добавим скругление, внутренние отступы и минимальную высоту. Именно min-height позволяет всем карточкам выглядеть одинаково даже несмотря на разное количество текста.
.tariffs-card {
display: flex;
flex-direction: column;
border: 1px solid #f1e3d6;
border-radius: 36px;
padding: 24px;
min-height: 550px;
background: #fff;
}
Далее делаем цену. У цены есть два элемента с разным шрифтом и цветом. Поэтому одна часть и обернута в <span>. Здесь мы будем использовать align-items: flex-end, чтобы выронять элементы.
.tariffs-card__title {
margin: 0;
margin-bottom: 20px;
font-weight: 800;
font-size: 24px;
color: #2a211c;
}
.tariffs-card__price {
display: flex;
align-items: flex-end;
margin-bottom: 20px;
font-weight: 800;
font-size: 56px;
line-height: 100%;
color: #2a211c;
gap: 8px;
}
.tariffs-card__price span {
padding-bottom: 8px;
font-weight: 400;
font-size: 16px;
line-height: 100%;
color: #7c6758;
}
Список внутри карточки делаем также через flexbox, чтобы было проще управлять отступами.
.tariffs-card__list {
list-style: disc;
margin: 0;
padding-left: 20px;
display: flex;
flex-direction: column;
font-weight: 400;
font-size: 16px;
line-height: 140%;
color: #2a211c;
gap: 12px;
}
И последнее — кнопка. Чтобы разместить ее внизу карточки, нужно добавить margin-top: auto, тогда отступ флекс-элемента займет все доступное пространство. Также делаем эффект наведения на кнопку. И не забудьте указать font-family: inherit, чтобы шрифт передался кнопке.
.tariffs-card__btn {
margin-top: auto;
display: flex;
align-items: center;
justify-content: center;
border: none;
border-radius: 16px;
padding: 16px 20px;
width: 100%;
font-family: inherit;
font-weight: 700;
font-size: 16px;
line-height: 120%;
color: #2a211c;
background: #fff1ea;
cursor: pointer;
transition: background 0.3s;
}
.tariffs-card__btn:hover {
background: #e3d8d2;
}
Далее нам нужно сделать среднюю карточку в другом стиле, выделить ее. Используем класс-модификатор, и через него меняем цвета элементов.
.tariffs-card--best {
border: 1px solid #2a211c;
background: #2a211c;
}
.tariffs-card--best .tariffs-card__title {
color: #fff;
}
.tariffs-card--best .tariffs-card__price {
color: #fff;
}
.tariffs-card--best .tariffs-card__price span {
color: rgba(255, 255, 255, 0.64);
}
.tariffs-card--best .tariffs-card__descr {
color: rgba(255, 255, 255, 0.74);
}
.tariffs-card--best .tariffs-card__list {
color: #fff;
}
.tariffs-card--best .tariffs-card__btn {
color: #fff;
background: #ef4444;
}
.tariffs-card--best .tariffs-card__btn:hover {
background: #c33737;
}
Теперь вы умеете создавать современные карточки тарифов с несколькими вариантами оформления, списком преимуществ и кнопкой действия. Заодно мы разобрали Flexbox, модификаторы БЭМ, одинаковую высоту карточек, margin-top: auto, выравнивание элементов по базовой линии и создание переиспользуемых интерфейсных компонентов.