Формы
Интерактивный калькулятор стоимости
Калькулятор для сайтов услуг, клиник, обучения и ремонта. Посетитель выбирает нужные опции и сразу видит примерную стоимость, а владелец сайта получает более тёплую заявку.
Калькулятор стоимости
Цена считается прямо во время выбора
Посетитель выбирает формат, услуги и срочность, а итоговая стоимость пересчитывается сразу. Такой блок помогает быстрее довести человека до заявки.
Формат работы
Дополнительные опции
Количество встреч
3 шт.Срочность
<section class="price-lab">
<div class="price-lab__head">
<span class="price-lab__badge">Калькулятор стоимости</span>
<h2>Цена считается прямо во время выбора</h2>
<p>
Посетитель выбирает формат, услуги и срочность, а итоговая стоимость
пересчитывается сразу. Такой блок помогает быстрее довести человека до заявки.
</p>
</div>
<div class="price-lab__grid">
<div class="price-lab__controls">
<div class="price-lab__group">
<h3>Формат работы</h3>
<div class="price-lab__cards">
<button class="price-lab__format active" type="button" data-price="2500" data-label="Базовый">
<strong>Базовый</strong>
<span>от 2 500 ₽</span>
</button>
<button class="price-lab__format" type="button" data-price="4500" data-label="Расширенный">
<strong>Расширенный</strong>
<span>от 4 500 ₽</span>
</button>
<button class="price-lab__format" type="button" data-price="7000" data-label="Премиум">
<strong>Премиум</strong>
<span>от 7 000 ₽</span>
</button>
</div>
</div>
<div class="price-lab__group">
<h3>Дополнительные опции</h3>
<label class="price-lab__option">
<input type="checkbox" data-price="1200" data-title="Подробная диагностика">
<span>Подробная диагностика</span>
<strong>+1 200 ₽</strong>
</label>
<label class="price-lab__option">
<input type="checkbox" data-price="900" data-title="Индивидуальные рекомендации">
<span>Индивидуальные рекомендации</span>
<strong>+900 ₽</strong>
</label>
<label class="price-lab__option">
<input type="checkbox" data-price="1500" data-title="Сопровождение после услуги">
<span>Сопровождение после услуги</span>
<strong>+1 500 ₽</strong>
</label>
</div>
<div class="price-lab__group">
<div class="price-lab__range-head">
<h3>Количество встреч</h3>
<strong><span class="price-lab__visits-value">3</span> шт.</strong>
</div>
<input class="price-lab__range" type="range" min="1" max="10" value="3">
</div>
<div class="price-lab__group">
<h3>Срочность</h3>
<select class="price-lab__urgency">
<option value="1">Обычный срок</option>
<option value="1.25">Быстрее обычного ×1.25</option>
<option value="1.5">Срочно ×1.5</option>
</select>
</div>
</div>
<aside class="price-lab__result">
<span class="price-lab__result-label">Предварительная стоимость</span>
<div class="price-lab__price">
<span class="price-lab__price-value">0</span> ₽
</div>
<div class="price-lab__summary">
<p>
Формат:
<strong class="price-lab__summary-format">Базовый</strong>
</p>
<p>
Встреч:
<strong class="price-lab__summary-visits">3</strong>
</p>
<p>
Опции:
<strong class="price-lab__summary-options">не выбраны</strong>
</p>
</div>
<div class="price-lab__bar">
<span></span>
</div>
<button class="price-lab__button" type="button">
Оставить заявку
</button>
<p class="price-lab__note">
Это пример расчёта. В реальном проекте можно отправлять выбранные параметры в заявку.
</p>
</aside>
</div>
</section>
.price-lab {
padding: 46px;
border-radius: 28px;
overflow: hidden;
background:
radial-gradient(circle at 12% 18%, rgba(59, 130, 246, 0.30), transparent 32%),
radial-gradient(circle at 88% 82%, rgba(34, 197, 94, 0.18), transparent 34%),
linear-gradient(135deg, #020617, #0f172a);
}
.price-lab__head {
max-width: 860px;
margin-bottom: 34px;
}
.price-lab__badge {
display: inline-flex;
margin-bottom: 16px;
padding: 8px 13px;
border-radius: 999px;
color: #bbf7d0;
background: rgba(34, 197, 94, 0.12);
border: 1px solid rgba(34, 197, 94, 0.35);
font-size: 13px;
}
.price-lab__head h2 {
margin: 0 0 16px;
color: #ffffff;
font-size: clamp(32px, 5vw, 56px);
line-height: 1.02;
letter-spacing: -0.05em;
}
.price-lab__head p {
color: #cbd5e1;
font-size: 17px;
line-height: 1.7;
}
.price-lab__grid {
display: grid;
grid-template-columns: 1.1fr 0.9fr;
gap: 26px;
align-items: start;
}
.price-lab__controls,
.price-lab__result {
border: 1px solid rgba(148, 163, 184, 0.28);
border-radius: 26px;
background: rgba(15, 23, 42, 0.78);
box-shadow: 0 28px 80px rgba(2, 6, 23, 0.5);
}
.price-lab__controls {
display: grid;
gap: 22px;
padding: 26px;
}
.price-lab__group h3 {
margin: 0 0 14px;
color: #ffffff;
font-size: 18px;
}
.price-lab__cards {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
}
.price-lab__format {
border: 1px solid #334155;
border-radius: 18px;
padding: 16px;
color: #cbd5e1;
text-align: left;
background: #020617;
cursor: pointer;
transition: 0.25s;
}
.price-lab__format strong,
.price-lab__format span {
display: block;
}
.price-lab__format strong {
color: #ffffff;
margin-bottom: 8px;
}
.price-lab__format span {
color: #94a3b8;
}
.price-lab__format.active,
.price-lab__format:hover {
border-color: #22c55e;
background: rgba(34, 197, 94, 0.12);
transform: translateY(-2px);
}
.price-lab__option {
display: grid;
grid-template-columns: auto 1fr auto;
gap: 12px;
align-items: center;
padding: 14px;
margin-bottom: 10px;
border: 1px solid #334155;
border-radius: 16px;
color: #dbeafe;
background: #020617;
cursor: pointer;
}
.price-lab__option input {
accent-color: #22c55e;
}
.price-lab__option strong {
color: #86efac;
}
.price-lab__range-head {
display: flex;
justify-content: space-between;
gap: 14px;
align-items: center;
}
.price-lab__range-head strong {
color: #86efac;
}
.price-lab__range {
width: 100%;
accent-color: #22c55e;
}
.price-lab__urgency {
width: 100%;
border: 1px solid #334155;
border-radius: 16px;
padding: 13px 14px;
color: #ffffff;
background: #020617;
outline: none;
}
.price-lab__result {
position: sticky;
top: 110px;
padding: 30px;
overflow: hidden;
}
.price-lab__result::before {
content: "";
position: absolute;
width: 260px;
height: 260px;
right: -110px;
top: -110px;
border-radius: 50%;
background: radial-gradient(circle, rgba(34, 197, 94, 0.25), transparent 70%);
}
.price-lab__result > * {
position: relative;
z-index: 2;
}
.price-lab__result-label {
color: #94a3b8;
}
.price-lab__price {
margin: 14px 0 22px;
color: #ffffff;
font-size: clamp(42px, 7vw, 72px);
font-weight: 800;
letter-spacing: -0.06em;
}
.price-lab__summary {
display: grid;
gap: 10px;
margin-bottom: 24px;
}
.price-lab__summary p {
display: flex;
justify-content: space-between;
gap: 16px;
margin: 0;
color: #94a3b8;
}
.price-lab__summary strong {
color: #dbeafe;
text-align: right;
}
.price-lab__bar {
height: 10px;
overflow: hidden;
border-radius: 999px;
background: #020617;
border: 1px solid #334155;
margin-bottom: 22px;
}
.price-lab__bar span {
display: block;
width: 0;
height: 100%;
border-radius: 999px;
background: linear-gradient(135deg, #22c55e, #3b82f6);
transition: 0.35s;
}
.price-lab__button {
width: 100%;
border: 0;
border-radius: 16px;
padding: 15px 18px;
color: #ffffff;
background: linear-gradient(135deg, #16a34a, #2563eb);
cursor: pointer;
transition: 0.25s;
}
.price-lab__button:hover {
transform: translateY(-2px);
}
.price-lab__note {
margin: 18px 0 0;
color: #94a3b8;
font-size: 14px;
}
.price-lab__price.is-updated {
animation: pricePulse 0.28s ease;
}
@keyframes pricePulse {
from {
transform: scale(0.96);
color: #86efac;
}
to {
transform: scale(1);
color: #ffffff;
}
}
@media (max-width: 900px) {
.price-lab {
padding: 26px 18px;
}
.price-lab__grid {
grid-template-columns: 1fr;
}
.price-lab__result {
position: static;
}
}
@media (max-width: 560px) {
.price-lab__cards {
grid-template-columns: 1fr;
}
.price-lab__summary p {
flex-direction: column;
gap: 4px;
}
.price-lab__summary strong {
text-align: left;
}
}
const priceFormats = document.querySelectorAll(".price-lab__format");
const priceOptions = document.querySelectorAll(".price-lab__option input");
const priceRange = document.querySelector(".price-lab__range");
const priceUrgency = document.querySelector(".price-lab__urgency");
const visitsValue = document.querySelector(".price-lab__visits-value");
const priceValue = document.querySelector(".price-lab__price-value");
const priceBox = document.querySelector(".price-lab__price");
const summaryFormat = document.querySelector(".price-lab__summary-format");
const summaryVisits = document.querySelector(".price-lab__summary-visits");
const summaryOptions = document.querySelector(".price-lab__summary-options");
const progressBar = document.querySelector(".price-lab__bar span");
let basePrice = 2500;
let formatLabel = "Базовый";
function formatMoney(value) {
return new Intl.NumberFormat("ru-RU").format(value);
}
function animatePrice() {
priceBox.classList.remove("is-updated");
void priceBox.offsetWidth;
priceBox.classList.add("is-updated");
}
function calculatePrice() {
const visits = Number(priceRange.value);
const urgency = Number(priceUrgency.value);
let optionsPrice = 0;
const selectedOptions = [];
priceOptions.forEach(function (option) {
if (option.checked) {
optionsPrice += Number(option.dataset.price);
selectedOptions.push(option.dataset.title);
}
});
const subtotal = (basePrice + optionsPrice) * visits;
const total = Math.round(subtotal * urgency);
visitsValue.textContent = visits;
summaryVisits.textContent = visits;
summaryFormat.textContent = formatLabel;
summaryOptions.textContent = selectedOptions.length ? selectedOptions.join(", ") : "не выбраны";
priceValue.textContent = formatMoney(total);
const progress = Math.min(100, (total / 120000) * 100);
progressBar.style.width = progress + "%";
animatePrice();
}
priceFormats.forEach(function (button) {
button.addEventListener("click", function () {
priceFormats.forEach(item => item.classList.remove("active"));
button.classList.add("active");
basePrice = Number(button.dataset.price);
formatLabel = button.dataset.label;
calculatePrice();
});
});
priceOptions.forEach(function (option) {
option.addEventListener("change", calculatePrice);
});
priceRange.addEventListener("input", calculatePrice);
priceUrgency.addEventListener("change", calculatePrice);
calculatePrice();