Создание динамической таблицы цен с помощью Javascript и CSS Grid
Введение: почему динамическая таблица цен имеет значение
Таблицы цен являются краеугольным камнем любого веб-сайта продукта или услуги. Статическая таблица с одним размером подходит для всех может представлять ваши ценовые точки, но динамическая таблица ценообразования — та, которая обновляется в режиме реального времени на основе взаимодействия с пользователем — может значительно повысить коэффициенты конверсии. Позволив посетителям переключаться между ежемесячными и годовыми выставлениями счетов, видеть общую стоимость с дополнениями или сравнивать функции интерактивно, вы создаете прозрачный и привлекательный опыт. В этом руководстве мы создадим готовую к производству динамическую таблицу цен с использованием простого JavaScript и CSS Grid. Никаких фреймворков, никаких библиотек — просто прочный, поддерживаемый код, который работает в современных браузерах.
Настройка структуры HTML для ценовой сетки
Основой любой таблицы динамического ценообразования является чистая, семантическая структура HTML. Мы начнем с контейнера, который станет нашей CSS Grid, а затем вложим в нее отдельные ценовые карты. Каждая карта должна содержать имя плана, цену, список функций и кнопку призыва к действию. Для включения динамических обновлений мы включим атрибут на каждой карте и структурируем ценовой контейнер с классом, на который мы можем ориентироваться с помощью JavaScript.
<div class="pricing-grid" role="group" aria-label="Pricing plans">
<div class="pricing-card" data-plan="basic">
<h3 class="plan-name">Basic</h3>
<p class="price">
<span class="amount">$10</span>
<span class="period">/mo</span>
</p>
<ul class="features">
<li>5 projects</li>
<li>10 GB storage</li>
<li>Basic support</li>
</ul>
<a href="#" class="btn">Get Started</a>
</div>
<div class="pricing-card featured" data-plan="pro">
<h3 class="plan-name">Pro</h3>
<p class="price">
<span class="amount">$25</span>
<span class="period">/mo</span>
</p>
<ul class="features">
<li>Unlimited projects</li>
<li>100 GB storage</li>
<li>Priority support</li>
</ul>
<a href="#" class="btn">Get Started</a>
</div>
<div class="pricing-card" data-plan="enterprise">
<h3 class="plan-name">Enterprise</h3>
<p class="price">
<span class="amount">$50</span>
<span class="period">/mo</span>
</p>
<ul class="features">
<li>Unlimited projects</li>
<li>1 TB storage</li>
<li>24/7 support</li>
</ul>
<a href="#" class="btn">Contact Sales</a>
</div>
</div>
Обратите внимание на и , чтобы улучшить доступность. Класс на карте Pro позволяет выделить наиболее популярный вариант без дополнительного JavaScript.
Создание CSS Grid Layout
CSS Grid позволяет легко создать отзывчивую сетку, которая регулирует количество столбцов на основе порта просмотра. Мы определяем контейнер как сетку, устанавливаем гибкое количество столбцов с и и добавляем интервал с . Внутри каждой карты мы используем CSS Grid внутренне, чтобы выровнять цену, функции и кнопку.
.pricing-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 1.5rem;
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
}
.pricing-card {
display: grid;
grid-template-rows: auto auto 1fr auto;
border: 1px solid #e0e0e0;
border-radius: 12px;
padding: 2rem;
text-align: center;
background: #fff;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.pricing-card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 24px rgba(0,0,0,0.12);
}
.pricing-card.featured {
border: 2px solid #007bff;
position: relative;
}
.pricing-card.featured::before {
content: "Most Popular";
position: absolute;
top: -12px;
left: 50%;
transform: translateX(-50%);
background: #007bff;
color: #fff;
padding: 4px 16px;
border-radius: 20px;
font-size: 0.8rem;
font-weight: 600;
}
.plan-name {
font-size: 1.5rem;
margin: 0 0 0.5rem;
}
.price {
margin: 0 0 1.5rem;
}
.amount {
font-size: 2.5rem;
font-weight: 700;
}
.period {
font-size: 1rem;
color: #666;
}
.features {
list-style: none;
padding: 0;
margin: 0 0 1.5rem;
}
.features li {
padding: 0.5rem 0;
border-bottom: 1px solid #eee;
}
.features li:last-child {
border-bottom: none;
}
.btn {
display: inline-block;
padding: 0.75rem 1.5rem;
background: #007bff;
color: #fff;
text-decoration: none;
border-radius: 8px;
transition: background 0.3s;
}
.btn:hover {
background: #0056b3;
}
гарантирует, что кнопка всегда остается внизу, даже если списки функций отличаются по длине. Знак «Самая популярная» карты создан с псевдоэлементом, чтобы избежать дополнительной разметки.
Добавление JavaScript Interactivity
Теперь наступает динамическая часть. Добавим переключатель переключения, который позволяет посетителям переключаться между ежемесячной и годовой ценой. Когда переключатель изменяется, JavaScript обновляет цены на все карты. Мы также включаем помощника по форматированию цен и плавный переход для числового изменения.
<div class="pricing-toggle">
<label class="toggle-label">
<span>Monthly</span>
<input type="checkbox" id="billing-toggle" role="switch" aria-checked="false">
<span class="toggle-slider"></span>
<span>Yearly (save up to 20%)</span>
</label>
</div>
CSS для переключателя:
.pricing-toggle {
text-align: center;
margin-bottom: 2rem;
}
.toggle-label {
display: inline-flex;
align-items: center;
gap: 0.75rem;
cursor: pointer;
user-select: none;
}
.toggle-label input[type="checkbox"] {
position: absolute;
opacity: 0;
width: 0;
height: 0;
}
.toggle-slider {
width: 50px;
height: 26px;
background: #ccc;
border-radius: 13px;
position: relative;
transition: background 0.3s;
}
.toggle-slider::after {
content: "";
position: absolute;
top: 3px;
left: 3px;
width: 20px;
height: 20px;
background: white;
border-radius: 50%;
transition: transform 0.3s;
}
input:checked + .toggle-slider {
background: #007bff;
}
input:checked + .toggle-slider::after {
transform: translateX(24px);
}
JavaScript, который поддерживает обновление:
document.addEventListener('DOMContentLoaded', () => {
const toggle = document.getElementById('billing-toggle');
const prices = {
basic: { monthly: 10, yearly: 8 }, // per month when billed yearly
pro: { monthly: 25, yearly: 20 },
enterprise: { monthly: 50, yearly: 40 }
};
function updatePrices(isYearly) {
document.querySelectorAll('.pricing-card').forEach(card => {
const plan = card.dataset.plan;
if (!plan || !prices[plan]) return;
const amountElement = card.querySelector('.amount');
const periodElement = card.querySelector('.period');
let amount, period;
if (isYearly) {
amount = prices[plan].yearly;
period = ' /mo (billed yearly)';
} else {
amount = prices[plan].monthly;
period = ' /mo';
}
amountElement.textContent = `$${amount}`;
periodElement.textContent = period;
});
}
toggle.addEventListener('change', () => {
const isYearly = toggle.checked;
updatePrices(isYearly);
toggle.setAttribute('aria-checked', isYearly);
});
// Initialize with monthly
updatePrices(false);
});
Объект хранит как месячные, так и годовые ставки. Годовые цены представляют собой ежемесячную стоимость при оплате ежегодно — общая картина. Функция повторяется по каждой карте, читает ее и обновляет отображаемую сумму и период. Мы также обновляем атрибут , чтобы сохранить переключатель доступным.
Усиление переходного периода
Чтобы изменение цены было плавным, мы можем добавить краткий переход CSS на элементы и . Однако, поскольку мгновенно меняется, мы можем симулировать эффект подсчета с небольшим интервалом или просто использовать эффект выцветания. Для производственной площадки быстрый переход непрозрачности на ценовом контейнере работает хорошо. Добавьте это к вашему CSS:
.price {
transition: opacity 0.2s ease;
}
.updating .price {
opacity: 0;
}
Затем в JavaScript кратко добавьте и удалите класс на каждой карте. Но для большинства случаев использования мгновенное обновление отлично.
Сделать стол доступным и отзывчивым
CSS Grid уже обрабатывает отзывчивость, но гарантирует, что на очень маленьких экранах карты стекаются в одну колонку. Значение делает это автоматически. Для доступности мы должны обеспечить работоспособность клавиатуры и объявить о ее состоянии. и мы уже добавили считыватели экрана. Также добавьте к родительской этикетке переключателя для ясности.
Кроме того, предоставьте видимый индикатор фокусировки для пользователей клавиатуры. Контур по умолчанию работает, но вы можете придать ему стиль, соответствующий вашему брендингу:
.toggle-label input:focus-visible + .toggle-slider {
outline: 2px solid #007bff;
outline-offset: 4px;
}
Проверить таблицу цен с помощью считывателя экрана, чтобы убедиться, что изменения цен объявлены. Для улучшения этого, после обновления цены, можно воспользоваться живым регионом:
<div aria-live="polite" aria-atomic="true" class="sr-only"></div>
Затем в JavaScript установите текст на что-то вроде «Цены, обновляемые до годового выставления счетов» после каждого переключения. Этот элемент только для чтения экрана объявит об изменении без визуального сбоя.
Добавление более динамичных функций
После того, как основной переключатель работает, вы можете расширить таблицу цен с дополнительной интерактивностью:
Особенности Toggles
Добавьте флажки для надстроек (например, дополнительное хранилище, члены команды), которые обновляют общую цену. Храните базовые цены и дополнительные затраты в объекте. Когда флажок изменяется, пересчитайте общую сумму для каждой карты соответственно.
Валютный селекционер
Если ваша аудитория глобальна, добавьте выпадающее значение для переключения между курсами конвертации в долларах США, евро, фунтах стерлингов и т. Д. Умножьте базовую цену. Обновите текст с соответствующим форматированием валюты с использованием .
Анимированный счетчик цен
Для полированного эффекта оживить число от старого значения до нового значения более чем за несколько сотен миллисекунд. Библиотеки, такие как animate.css, не нужны — работает простой цикл.
Сберегательный знак
Когда годовой счет переключается, покажите значок «Сохранить 20%» рядом с ценой. Рассчитайте экономию как и отображайте его динамически. Добавьте атрибут для каждой карты в HTML и позвольте JavaScript заполнять его или вычислять его на лету.
Соображения в отношении эффективности
Если у вас есть десятки планов (например, SaaS, который генерирует планы из базы данных), рассмотрите эти оптимизации:
- Используйте делегацию событий: Прикрепите слушателя мероприятия к родительскому контейнеру вместо каждой карты. Для переключателя это уже сделано. Для флажков внутри карт делегат.
- Кашечные DOM-ссылки: При инициализации сохраняйте ссылки на и элементы в массиве или Карте по ключу плана.
- Использовать для анимации: Расписание визуальных обновлений для следующего цикла краски, чтобы избежать трэширования макета.
- Минимизируйте переливки: Батч DOM меняется при обновлении нескольких карт. В нашей функции мы читаем и пишем DOM в один цикл — это нормально. Если вы добавляете классы или встроенные стили, сначала подумайте о чтении всех значений, а затем о написании всех изменений.
Реальные примеры и примеры использования
Динамические таблицы цен используются везде, от подписных сервисов, таких как Dropbox и Spotify до хостинг-провайдеров, таких как . Общая схема заключается в том, чтобы предлагать ежемесячный / годовой переключатель с меткой «Лучшая стоимость» на годовом опционе. Некоторые компании также показывают общую годовую плату рядом с ежемесячной экономией. Например, план 10 долларов США / му, с годовым выставлением счетов, может отображать «8 долларов США / мум — выставлено 96 долларов США в год». Наша структура уже поддерживает это с охватом .
Еще одна вариация - скользящие шкалы по количеству. Таблица цен для продукта SaaS может иметь ползунки для количества пользователей или хранилища. По мере перемещения пользователя ползунок, обновления цены в прямом эфире. CSS Grid обрабатывает макет, а JavaScript обновляет значения цен. Это может быть построено с теми же принципами: уровни цен магазина, прослушивание изменений ввода и обновление DOM.
Для более продвинутого подхода вы можете загружать данные о ценах из файла JSON или API, что делает таблицу действительно ориентированной на данные. Если ваш сайт построен с безголовой CMS, такой как Directus, данные о ценах будут поступать из коллекции, и ваш интерфейсный JavaScript будет получать его и динамически отображать сетку. Этот подход поддерживает ценообразование синхронизировано с вашим бэкэндом.
Тестирование и поддержка браузера
CSS Grid поддерживается во всех современных браузерах, включая Internet Explorer 11 с префиксом — хотя мы рекомендуем использовать Autoprefixer или игнорировать IE11 для новых проектов. JavaScript, используемый здесь (ES6 , , функции стрелок, , буквальные шаблоны) работает в Chrome, Firefox, Safari и Edge. Если вам нужно поддерживать старые браузеры, транспиляцию с Babel или использование и традиционные функции. хорошо поддерживается в современных экранных считывателях, но вы также можете использовать стандартный флажок со скрытой областью в качестве запасного варианта.
Альтернативный подход: CSS Grid с пользовательскими свойствами CSS
Интересный способ избежать JavaScript для переключения цен - использовать CSS Custom Properties и (когда поддержка браузера созревает). Вы бы установили цены как и т. Д. И изменили бы их, переключая класс на корпусе. Однако для истинной динамической логики (например, добавление двух надстроек) JavaScript по-прежнему необходим. Комбинация обоих - CSS для макета и переходов, JavaScript для динамических данных - является наиболее надежной.
Заключение
Создание динамической таблицы цен с JavaScript и CSS Grid достижимо и расширяется. Начиная с семантического HTML, структурирования сетки с CSS Grid и добавления простого JavaScript для интерактивности, вы создаете инструмент, который может адаптироваться к сложным моделям ценообразования без раздутых зависимостей. Те же принципы — обновления на основе данных, адаптивная компоновка, доступные элементы управления — масштабирование для приложений корпоративного уровня. В качестве следующего шага рассмотрите чтение документации MDN CSS Grid для большего количества методов или изучите Дизайн переключателей Сара Суэйдан — для обработки сложных данных без структуры, Vanilla JS Toolkit предлагает легкие помощники.
Теперь реализуйте эти шаблоны в своем собственном проекте. Ваши пользователи оценят ясность, и ваши коэффициенты конверсии могут вас поблагодарить.