Создание сайта с калькулятором стоимости оборудования и публикация на хостинге

Курс о том, как спроектировать, разработать и развернуть сайт с интерактивным калькулятором стоимости оборудования. Разберём структуру данных, логику расчётов, интерфейс, тестирование и размещение на хостинге с доменом и SSL.

1. Постановка задачи: требования к калькулятору и структуре сайта

Постановка задачи: требования к калькулятору и структуре сайта

Зачем нужна постановка задачи

Прежде чем писать код и публиковать сайт на хостинге, нужно зафиксировать что именно мы делаем и каким должен быть результат. Это защищает от типичных проблем:

  • Калькулятор «почти работает», но непонятно, как должны считаться скидки и доставка.
  • Страницы сделаны, но посетителю сложно понять, где посмотреть цены и как оставить заявку.
  • Данные о ценах разбросаны по коду, и любое обновление превращается в риск ошибок.
  • В этой статье мы формализуем требования к калькулятору стоимости оборудования и определим структуру сайта, чтобы дальше уверенно перейти к реализации.

    Что мы создаём в рамках курса

    Итоговый проект курса — это сайт, который:

  • Показывает информацию об оборудовании и услугах.
  • Позволяет посетителю рассчитать ориентировочную стоимость комплекта через калькулятор.
  • Даёт понятный способ отправить заявку или связаться.
  • Размещён на хостинге и доступен по публичной ссылке.
  • Важно: на старте мы проектируем решение так, чтобы оно могло работать как статический сайт (без серверной части). Это упростит публикацию и сделает проект устойчивым.

    Пользователи и сценарии

    Кто будет пользоваться сайтом

  • Потенциальный клиент: хочет быстро понять порядок цен и подобрать конфигурацию.
  • Менеджер/владелец: хочет, чтобы данные о ценах можно было обновлять без переписывания логики калькулятора.
  • Ключевые пользовательские сценарии

  • Посетитель выбирает тип оборудования, комплектацию и количество, видит итоговую стоимость.
  • Посетитель видит расшифровку расчёта: из чего сложилась сумма.
  • Посетитель сохраняет результаты (как минимум копирует или видит итог на странице) и переходит к контакту/заявке.
  • !Схема основного пути пользователя от входа на сайт до заявки

    Требования к калькулятору

    Входные данные (что пользователь может указать)

    Набор входов зависит от тематики оборудования, но для учебного проекта зафиксируем универсальный минимум.

  • Тип оборудования (например, «Компрессор», «Насос», «ИБП»).
  • Модель или класс (например, «Базовая», «Стандарт», «Премиум»).
  • Количество (целое число, минимум 1).
  • Дополнительные опции (например, монтаж, расширенная гарантия, доставка).
  • Регион/город (опционально, если доставка зависит от региона).
  • Рекомендация: в первой версии не перегружайте калькулятор десятками полей — лучше меньше параметров, но понятнее результат.

    Выходные данные (что калькулятор показывает)

    Калькулятор должен отображать:

  • Итоговую стоимость.
  • Валюту (например, ₽).
  • Расшифровку расчёта (промежуточные суммы).
  • Сообщения об ошибках ввода (например, «Количество должно быть целым числом от 1»).
  • Правила расчёта (логика)

    Чтобы требования были однозначными, фиксируем правила расчёта текстом.

  • Базовая цена определяется по выбранным типу и модели.
  • Стоимость опций добавляется к базовой цене.
  • Итог умножается на количество.
  • При необходимости применяется скидка (например, от количества или суммы).
  • Отдельными строками могут добавляться доставка и монтаж.
  • Отдельно нужно заранее ответить на вопросы (в рамках проекта можно выбрать упрощённые варианты):

  • Скидка применяется к чему: к цене оборудования или ко всему заказу?
  • Доставка считается фиксированной суммой или процентом?
  • Нужно ли показывать НДС отдельной строкой или достаточно «итоговой цены»?
  • Если эти пункты не определить сейчас, позже вы будете вынуждены переделывать интерфейс и расчёт.

    Валидация и защита от некорректного ввода

    Калькулятор должен корректно обрабатывать ошибки и пограничные случаи.

  • Количество: только целое число, минимум 1.
  • Не выбран тип/модель: итог не показывается или показывается как 0 с подсказкой.
  • Опции: если опция недоступна для модели, она должна быть скрыта или отключена.
  • Цена не найдена в прайсе: показывается понятная ошибка («Не удалось найти цену для выбранной конфигурации»).
  • Требования к интерфейсу (UX)

    Минимальные требования к удобству:

  • Итог обновляется сразу после изменения параметров (без перезагрузки страницы).
  • Расшифровка расчёта читаемая: строки, подписи, промежуточные суммы.
  • Управление с клавиатуры работает (переход по полям, ввод количества).
  • На мобильных устройствах калькулятор не «ломается» и не требует горизонтальной прокрутки.
  • Требования к данным о ценах

    Чтобы калькулятор был поддерживаемым, цены нельзя «зашивать» в логику расчёта.

    Правильная цель: логика расчёта отдельно, данные о ценах отдельно.

    В рамках статического сайта удобный вариант — хранить прайс в JSON-файле и загружать его на странице.

    Пример того, какие сущности обычно нужны в прайсе:

  • Список типов оборудования.
  • Для каждого типа — список моделей.
  • Для каждой модели — базовая цена.
  • Для опций — цена и правила доступности.
  • Требования к структуре сайта

    Минимальный набор страниц

    Ниже — рекомендованный состав страниц для проекта курса. Его достаточно, чтобы сайт выглядел завершённым и решал задачу.

    | Страница | Цель | Что должно быть на странице | |---|---|---| | Главная | Быстро объяснить, что вы предлагаете | Короткий оффер, преимущества, кнопка к калькулятору | | Калькулятор/Расчёт | Дать пользователю расчёт стоимости | Форма параметров, итог, расшифровка, призыв к контакту | | Каталог/Оборудование | Показать, что именно продаётся | Список типов/моделей, краткие описания | | Доставка и монтаж | Убрать вопросы по условиям | География, сроки, что входит, ограничения | | Контакты | Превратить интерес в обращение | Телефон/почта/мессенджер, форма заявки (если делаем), адрес |

    В учебном варианте допустимо объединить «Каталог» и «Доставка и монтаж» в одну страницу, если контента мало.

    Навигация и повторяющиеся элементы

    У сайта должны быть единые элементы, чтобы пользователь не терялся:

  • Шапка с меню (Главная, Калькулятор, Контакты).
  • Подвал с контактами и краткой юридической информацией (по желанию).
  • Повторяющаяся кнопка действия рядом с результатом калькулятора: «Оставить заявку».
  • Связь структуры сайта с калькулятором

    Калькулятор — центральная часть проекта, поэтому он должен быть доступен:

  • как отдельная страница;
  • и как якорный блок на главной (по желанию), чтобы пользователь дошёл до расчёта за 1–2 клика.
  • !Карта сайта (sitemap) для понимания структуры страниц

    Нефункциональные требования (качество и ограничения)

    Эти требования не про «что делает сайт», а про «каким он должен быть».

  • Работает как статический сайт (подходит для простого хостинга).
  • Быстро загружается: минимум тяжёлых библиотек и изображений.
  • Адаптивность: корректный вид на телефоне и на десктопе.
  • Доступность: понятные подписи полей, читаемые контрасты.
  • Надёжность: при ошибке загрузки прайса пользователь видит сообщение, а не «пустой экран».
  • Если вы хотите свериться с базовыми принципами веб-разработки, используйте справочник:

  • MDN Web Docs — Основы HTML
  • MDN Web Docs — Основы CSS
  • MDN Web Docs — Основы JavaScript
  • Критерии готовности (что считаем «сделано»)

    Перед тем как переходить к реализации, зафиксируйте критерии приёмки — по ним удобно проверять готовность.

  • Есть страницы, указанные в минимальной структуре (или их объединённый эквивалент).
  • Калькулятор считает итог по зафиксированным правилам.
  • Есть расшифровка расчёта (хотя бы базовая: цена, опции, количество, доставка).
  • Обрабатываются ошибки ввода (минимум: количество и обязательные выборы).
  • Цены вынесены в отдельные данные (например, JSON), а не спрятаны внутри логики.
  • На мобильном устройстве калькулятором можно пользоваться без проблем.
  • Что дальше по курсу

    Следующий шаг — выбрать технологический подход и подготовить основу проекта: структуру файлов, заготовку страниц и подключение данных для калькулятора. После этого мы перейдём к реализации интерфейса и логики расчёта.

    2. Проектирование данных: параметры, прайс-листы, формулы и сценарии

    Проектирование данных: параметры, прайс-листы, формулы и сценарии

    Зачем проектировать данные до написания кода

    В предыдущей статье мы зафиксировали требования к калькулятору и структуре сайта: какие параметры вводит пользователь, что мы показываем в результате и какие ошибки должны обрабатываться.

    Теперь нужно сделать следующий шаг: спроектировать данные, на которых будет работать калькулятор.

    Если данные не продумать заранее, почти неизбежны проблемы:

  • Цены «разъезжаются» по коду, их сложно обновлять.
  • Непонятно, как добавить новую модель или опцию без переписывания логики.
  • Сложно объяснить пользователю расчёт, потому что нет структуры строк (базовая цена, опции, доставка, скидка).
  • Мы спроектируем:

  • параметры (что выбирает пользователь и какие есть ограничения),
  • прайс-лист (как хранить цены и доступность),
  • формулы (в каком порядке считается итог),
  • сценарии (типовые варианты использования и проверки).
  • В рамках курса мы ориентируемся на статический сайт: прайс удобно хранить в JSON и загружать на странице калькулятора.

    > О формате JSON можно почитать в справочнике MDN: JSON — MDN Web Docs и в спецификации: RFC 8259 (The JavaScript Object Notation (JSON) Data Interchange Format)

    Принципы хорошей модели данных для калькулятора

    Отделяем данные от логики

  • Данные отвечают на вопрос: «Сколько стоит и где доступно?»
  • Логика отвечает на вопрос: «Как посчитать итог из выбранных данных?»
  • Цель: чтобы обновление цен происходило в одном месте (в прайсе), а код расчёта не менялся.

    Делаем ключи стабильными

    В данных лучше хранить не «человеческие» названия как идентификаторы, а стабильные ключи.

  • Пользователь видит: Компрессор
  • В прайсе ключ: compressor
  • Это защищает от ошибок при переименовании текста на сайте.

    Заранее определяем ограничения

    Примеры ограничений, которые важно зафиксировать:

  • Количество: целое число, минимум 1.
  • Модель должна принадлежать выбранному типу оборудования.
  • Опция может быть доступна не для всех моделей.
  • Доставка может зависеть от региона.
  • Эти ограничения должны быть отражены и в интерфейсе, и в данных.

    Параметры калькулятора: что именно выбирает пользователь

    Ниже — базовый набор параметров, который соответствует требованиям из постановки задачи.

    | Параметр | Тип ввода | Пример | Зачем нужен | Валидация | |---|---|---|---|---| | Тип оборудования | список (select) | Компрессор | определяет набор моделей | обязательно выбрать | | Модель/класс | список (select) | Стандарт | определяет базовую цену | обязательно выбрать | | Количество | число (input) | 3 | умножает стоимость | целое | | Опции | чекбоксы | Монтаж | добавляет доп.стоимость | зависит от доступности | | Регион | список (select) | Москва | влияет на доставку | можно сделать обязательным, если доставка всегда есть |

    Важно: список опций должен формироваться из прайса, а не «зашиваться» в вёрстку.

    Проектируем прайс-лист: сущности и связи

    Какие сущности нам нужны

    Минимальный набор сущностей для учебного проекта:

  • Типы оборудования
  • Модели (внутри типа)
  • Опции (отдельным списком)
  • Регионы доставки (если доставка не фиксированная)
  • Правила скидок (если используем скидки)
  • !Общая схема: как пользовательский выбор сопоставляется с прайсом и превращается в результат расчёта

    Как представить прайс в JSON

    Ниже — пример структуры price.json. Это пример, который удобно расширять.

    Почему такая структура удобна

  • equipmentTypes хранит дерево «тип → модели». Так проще строить два связанных списка (выбрали тип → загрузили модели).
  • allowedOptions фиксирует доступность опций для модели. Это позволяет отключать/скрывать чекбоксы.
  • options отделены от моделей, чтобы менять цену опции централизованно.
  • pricing.type задаёт вид ценообразования опции:
  • fixed — фиксированная надбавка
  • percent — процент от базы (или другой базы, которую вы определите правилами)
  • byRegion — цена берётся из таблицы регионов
  • Формулы расчёта: фиксируем порядок и базу

    Чтобы калькулятор был предсказуемым, нужно заранее определить:

  • порядок применения скидок,
  • к чему применяется процентная опция,
  • как доставка влияет на скидку (обычно не влияет).
  • Рекомендуемый порядок (для учебного проекта)

  • Находим базовую цену модели.
  • Считаем стоимость опций (каждая по своему правилу).
  • Складываем цену оборудования и опции, которые относятся к единице товара.
  • Умножаем на количество.
  • Применяем скидку (если есть).
  • Добавляем доставку (если доставка считается на заказ, а не на единицу).
  • Такой порядок проще объяснить пользователю строками расчёта.

    Базовая формула итога

    Упрощённо итог можно описать так:

    Где:

  • — итоговая стоимость заказа.
  • — базовая цена выбранной модели за 1 штуку.
  • — сумма опций, которые считаются на единицу (например, гарантия как процент от базы).
  • — количество.
  • — скидка на заказ (по правилу количества или суммы).
  • — доставка (часто фиксированная на заказ или по региону).
  • Важно: если монтаж считается «на единицу», включайте его в . Если монтаж «на заказ», добавляйте его рядом с .

    Как считать процентную опцию

    Если опция задаётся процентом, важно зафиксировать базу процента.

    В учебной версии удобно считать так:

  • расширенная гарантия rate = 0.07 применяется к базовой цене модели
  • Тогда стоимость гарантии за единицу:

    Где:

  • — стоимость гарантии за 1 штуку.
  • — базовая цена модели.
  • — ставка (например, 0.07 = 7%).
  • Строки расчёта: как подготовить «расшифровку»

    Чтобы показать пользователю понятную расшифровку, полезно мыслить не только итогом, но и строками.

    Рекомендуемая структура строки расчёта (как идея для данных внутри кода):

  • название строки
  • количество (если применимо)
  • цена за единицу (если применимо)
  • сумма строки
  • тип строки: база, опция, скидка, доставка
  • Например, строки результата могут выглядеть так:

  • Оборудование: Компрессор «Стандарт» — 180 000 ₽ × 2 = 360 000 ₽
  • Опция: Монтаж — 25 000 ₽ × 2 = 50 000 ₽
  • Опция: Расширенная гарантия (7%) — 12 600 ₽ × 2 = 25 200 ₽
  • Скидка за количество (5%) — −21 760 ₽
  • Доставка (Москва) — 5 000 ₽
  • Итог — 418 440 ₽
  • Эта же структура помогает тестировать расчёт.

    Сценарии: проверяем, что модель данных покрывает реальные случаи

    Сценарии нужны, чтобы убедиться: ваш прайс и правила позволяют посчитать всё, что требуется, и обработать ошибки.

    Набор минимальных сценариев для проекта

  • Базовый расчёт без опций
  • 1. Выбрать тип и модель. 2. Количество = 1. 3. Опции выключены. 4. Ожидание: итог равен базовой цене.

  • Расчёт с фиксированной опцией
  • 1. Количество = 2. 2. Включить монтаж (fixed). 3. Ожидание: монтаж добавляется корректно (на единицу или на заказ — как вы зафиксировали).

  • Расчёт с процентной опцией
  • 1. Включить гарантию (percent). 2. Ожидание: процент применяется к правильной базе (например, к basePrice).

  • Доставка по региону
  • 1. Выбрать регион. 2. Включить доставку. 3. Ожидание: сумма доставки берётся из таблицы deliveryByRegion.

  • Скидка от количества
  • 1. Количество = 5. 2. Ожидание: скидка применена согласно discountRules.

  • Недоступная опция
  • 1. Выбрать модель, где нет installation в allowedOptions. 2. Ожидание: опция скрыта или отключена; расчёт не должен её учитывать.

  • Ошибки ввода
  • 1. Количество пустое, 0, отрицательное, дробное. 2. Ожидание: понятная ошибка и отсутствие некорректного итога.

    Типичные ошибки проектирования прайса

  • Цены спрятаны в коде: сначала кажется быстрее, потом любое обновление превращается в правку JavaScript.
  • Нет стабильных id: если использовать текстовые названия как ключи, легко «сломать» сопоставление.
  • Опции не завязаны на доступность: пользователь выбирает то, что не подходит модели.
  • Смешаны опции “на единицу” и “на заказ” без явного правила: появляются двойные трактовки.
  • Нет явного порядка расчёта: скидки и проценты начинают считаться по-разному в разных местах.
  • Итог

    На этом этапе у вас должно быть зафиксировано:

  • какие параметры вводит пользователь и какие у них ограничения,
  • как выглядит прайс в JSON (типы, модели, опции, доставка, скидки),
  • порядок расчёта и база для процентов,
  • набор сценариев, которыми вы проверяете корректность.
  • Дальше (в следующих шагах курса) вы сможете безопасно перейти к реализации: загрузить JSON, построить UI калькулятора и написать расчёт так, чтобы изменения прайса не ломали логику.

    3. Верстка сайта: адаптивный интерфейс и компоненты калькулятора

    Верстка сайта: адаптивный интерфейс и компоненты калькулятора

    Как эта статья связана с предыдущими

    В статье «Постановка задачи: требования к калькулятору и структуре сайта» мы определили, что должен уметь сайт и калькулятор: входные параметры, правила отображения результата, обработку ошибок и базовую структуру страниц.

    В статье «Проектирование данных: параметры, прайс-листы, формулы и сценарии» мы спроектировали, на каких данных работает калькулятор: price.json, сущности (типы, модели, опции, доставка, скидки) и сценарии проверки.

    Теперь переходим к тому, как это будет выглядеть на странице: делаем адаптивную вёрстку и продумываем компоненты интерфейса так, чтобы их было легко связать с данными из JSON и логикой расчёта.

    Цель этапа вёрстки

    На этом этапе мы:

  • собираем страницы сайта в едином стиле (шапка, контент, подвал);
  • делаем адаптивный макет (мобильный и десктоп);
  • проектируем компоненты калькулятора (форма, блок результата, расшифровка, ошибки, состояния загрузки);
  • закладываем контракты между вёрсткой и будущим JavaScript (понятные идентификаторы, классы, области обновления).
  • Важно: мы сознательно делаем интерфейс простым и надёжным. Красоту и анимации можно добавить позже, а вот понятная структура и адаптивность нужны сразу.

    Каркас сайта: единые блоки на всех страницах

    Чтобы сайт ощущался цельным, делаем повторяющиеся элементы:

  • Шапка: логотип/название, меню, кнопка перехода к расчёту.
  • Основной контент: уникальный для каждой страницы.
  • Подвал: контакты, режим работы (если нужно), короткая приписка.
  • Рекомендация по навигации из постановки задачи:

  • Главная
  • Калькулятор
  • Контакты
  • Если страниц больше, добавляйте пункт меню только если он реально нужен пользователю.

    !Каркас страницы для мобильной и десктопной версии

    Адаптивность: базовые правила, чтобы ничего не «ломалось»

    Подход mobile-first

    Практичный подход для учебного проекта — mobile-first:

  • базовые стили рассчитаны на узкий экран;
  • расширение интерфейса делается через медиазапросы с min-width.
  • Это снижает риск ситуации, когда мобильная версия получается «урезанной копией» десктопа и начинает расползаться.

    Полезные справочные материалы:

  • MDN: Responsive design
  • MDN: Using media queries
  • Контейнер и сетка

    Чтобы текст не растягивался на всю ширину большого монитора, используйте контейнер с максимальной шириной и внутренними отступами.

    Типовая идея:

  • контент по центру;
  • max-width (например, 1000–1200 пикселей);
  • боковые отступы на мобильных.
  • Для компоновки блоков подойдут:

  • Flexbox для выравнивания элементов в строку или колонку;
  • Grid для двухколоночных и более сложных раскладок.
  • Справочник:

  • MDN: Flexbox
  • MDN: Grids
  • Минимальный набор брейкпоинтов

    В учебном проекте достаточно 2–3 состояний:

  • мобильный: по умолчанию;
  • планшет: например, от 768;
  • десктоп: например, от 1024.
  • Главная цель брейкпоинтов — не «подогнать под устройства», а обеспечить:

  • читаемую ширину строк;
  • удобные элементы управления;
  • логичное размещение формы и результата.
  • Практичный пример CSS-основы

    Что здесь важно:

  • переменные помогают выдерживать единый стиль;
  • container и card пригодятся почти на каждой странице;
  • медиазапрос аккуратно усиливает интерфейс на больших экранах.
  • Компоненты калькулятора: что обязательно должно быть на странице

    Из требований первой статьи калькулятор должен:

  • принимать параметры (тип, модель, количество, опции, регион);
  • показывать итог и валюту;
  • показывать расшифровку;
  • показывать ошибки ввода и ошибки данных.
  • Чтобы это реализовать без хаоса, заранее делим страницу калькулятора на компоненты.

    !Компоновка калькулятора на десктопе и мобильном

    Компонент «Форма параметров»

    Состав:

  • выбор типа оборудования;
  • выбор модели (зависит от типа);
  • количество;
  • список опций чекбоксами;
  • регион (если доставка зависит от региона).
  • Правила вёрстки формы:

  • у каждого поля есть подпись (пользователь должен понимать, что именно он выбирает);
  • рядом с полем есть место под сообщение об ошибке;
  • элементы управления достаточно крупные для мобильного.
  • Совет по будущей привязке к данным:

  • список типов, моделей, опций не «забивайте руками» — оставьте контейнеры, которые JavaScript заполнит из price.json.
  • Справочник по формам:

  • MDN: Web forms
  • Компонент «Результат»

    Состав:

  • итоговая сумма крупно;
  • подпись валюты;
  • короткое пояснение (например, «Ориентировочная стоимость»);
  • кнопка действия (например, «Оставить заявку» или «Отправить расчёт»).
  • Практика:

  • итог всегда в одном и том же месте, чтобы пользователь не искал;
  • при ошибке или незаполненных обязательных полях не показывайте «мусорные» числа — показывайте понятное состояние.
  • Компонент «Расшифровка расчёта»

    Это список строк, который соответствует логике из проектирования данных:

  • строка базовой цены;
  • строки опций;
  • строка количества (или умножение внутри строк);
  • скидка отдельной строкой, если есть;
  • доставка отдельной строкой, если есть;
  • итог.
  • Требования к удобству:

  • строки легко сканируются глазами;
  • отрицательные значения (скидка) заметны;
  • если доставка зависит от региона, строка явно показывает выбранный регион.
  • Компоненты состояний: загрузка, пусто, ошибка

    Так как прайс мы планируем загружать из JSON, нужны состояния:

  • загрузка: пока данные не пришли, в форме нельзя выбрать модели и опции;
  • пусто: пока пользователь не выбрал тип и модель, результат показывает подсказку;
  • ошибка: если price.json не загрузился или структура неожиданная.
  • Вёрстка под это делается заранее: отдельные области, которые JavaScript сможет переключать.

    Контракты между вёрсткой и JavaScript

    Чтобы код расчёта и обновление интерфейса были простыми, в вёрстке должны быть стабильные точки привязки. Так вы избежите хрупкого кода, который зависит от того, «какой там сейчас третий элемент в списке».

    Рекомендации:

  • для каждого поля формы используйте уникальный идентификатор (например, для типа, модели, количества, региона);
  • для контейнера опций используйте отдельный класс, чтобы JavaScript мог отрисовать чекбоксы;
  • для области результата используйте отдельные контейнеры под:
  • - итоговую сумму, - валюту, - список строк расшифровки, - сообщения об ошибках.

    Практичная идея именования (примерно):

  • поля: calc-type, calc-model, calc-qty, calc-region
  • контейнеры: calc-options, calc-total, calc-breakdown, calc-alert
  • Важно: идентификаторы должны быть стабильными, даже если вы поменяете тексты на кнопках и заголовках.

    Доступность и качество интерфейса

    Даже учебный проект должен быть удобен:

  • подписи полей должны однозначно объяснять ввод;
  • ошибки должны быть текстом и находиться рядом с проблемным полем;
  • элементы управления должны быть доступны с клавиатуры;
  • контраст текста и фона должен быть достаточным.
  • Если используете дополнительные атрибуты доступности, ориентируйтесь на справочник:

  • MDN: ARIA
  • Пример компоновки страницы калькулятора через Grid

    Идея:

  • на мобильном блоки идут друг за другом;
  • на десктопе форма и результат стоят в две колонки.
  • Что это даёт:

  • структура страницы становится предсказуемой;
  • проще поддерживать мобильный вид;
  • блок результата всегда аккуратно отделён.
  • Как сверстать опции так, чтобы их можно было генерировать из прайса

    Так как опции у модели разные (allowedOptions), чекбоксы должны:

  • отрисовываться по списку опций из price.json;
  • включаться или отключаться при смене модели;
  • иметь место под пояснение (например, как считается цена: фиксированно или процентом).
  • Практическая рекомендация по вёрстке:

  • выделите контейнер, куда JavaScript добавит элементы опций;
  • у каждого элемента опции должны быть:
  • - название, - краткое пояснение, - визуальное состояние отключено.

    В CSS заранее предусмотрите классы для состояния:

    JavaScript в следующей части курса будет просто переключать класс is-disabled и исключать такую опцию из расчёта.

    Проверка адаптивности: быстрый чек-лист

    Перед тем как переходить к JavaScript-логике, проверьте в инструментах разработчика браузера:

  • всё читаемо на ширине 360–390;
  • поля не выходят за экран;
  • кнопки нажимаются пальцем (не слишком мелкие);
  • итог и расшифровка не «прыгают» при изменении значений;
  • длинные названия моделей и опций не ломают сетку;
  • состояния загрузки и ошибки выглядят аккуратно.
  • Полезно тестировать как минимум в двух браузерах.

    Итог и что дальше

    На этом этапе у вас должна получиться страница калькулятора и базовый каркас остальных страниц сайта:

  • единый контейнер и базовые стили;
  • адаптивная компоновка (мобильный и десктопный варианты);
  • компоненты калькулятора: форма, результат, расшифровка, состояния;
  • подготовленные точки привязки для JavaScript.
  • Следующий шаг курса — подключить price.json, динамически заполнить выпадающие списки и опции, а затем реализовать расчёт и обновление результата согласно сценариям из проектирования данных.

    4. Логика расчётов на JavaScript: валидация, форматирование, итоговая цена

    Логика расчётов на JavaScript: валидация, форматирование, итоговая цена

    Как эта статья связана с предыдущими

    В предыдущих статьях курса мы:

  • зафиксировали требования к калькулятору и структуре сайта
  • спроектировали данные прайса и правила расчёта
  • сверстали адаптивный интерфейс и подготовили точки привязки для JavaScript
  • Теперь мы реализуем логику калькулятора на JavaScript так, чтобы:

  • данные (price.json) загружались отдельно от кода
  • форма валидировалась и не давала получить некорректный результат
  • итог и расшифровка обновлялись сразу при изменениях
  • суммы были аккуратно отформатированы и выглядели как в реальном коммерческом расчёте
  • !Поток данных: UI → состояние → расчёт → отрисовка

    Что мы считаем логикой калькулятора

    Логика калькулятора обычно состоит из четырёх слоёв:

  • загрузка данных: забираем price.json через fetch
  • состояние: храним выбранные пользователем значения в одном месте
  • валидация: проверяем обязательные поля и корректность чисел
  • расчёт и отрисовка: получаем строки расшифровки и итог, форматируем и показываем
  • Ключевая идея из проектирования данных: цены и доступность живут в JSON, а формулы и правила расчёта живут в JavaScript.

    Подготовка: точки привязки в вёрстке

    Из статьи про вёрстку у нас должны быть стабильные идентификаторы (пример):

  • calc-type тип оборудования
  • calc-model модель
  • calc-qty количество
  • calc-region регион
  • calc-options контейнер для чекбоксов опций
  • calc-total итоговая сумма
  • calc-breakdown расшифровка
  • calc-alert область для ошибок и подсказок
  • В JavaScript мы не ищем элементы по тексту или позиции. Мы ищем их по стабильным id.

    Загрузка прайса: fetch, состояния загрузки и ошибки

    Мы работаем со статическим сайтом, поэтому самый простой путь:

  • кладём price.json рядом со страницей
  • загружаем его через fetch
  • при ошибке показываем понятное сообщение
  • Справочник по fetch:

  • MDN: Fetch API
  • Пример каркаса загрузки данных:

    Практические замечания:

  • cache: 'no-store' удобен во время разработки, чтобы браузер не держал старую версию прайса
  • если price.json не загрузился, калькулятор лучше отключить, чем показывать нули и вводить пользователя в заблуждение
  • Построение интерфейса из данных

    После загрузки прайса мы должны:

  • заполнить список типов оборудования
  • при выборе типа заполнить список моделей
  • отрисовать опции с учётом allowedOptions
  • заполнить регионы доставки (если они предусмотрены)
  • Поиск сущностей в прайсе

    Чтобы расчёт был простым, полезно сделать маленькие функции поиска:

    Эти функции помогают избегать копипаста и дают единый стиль обработки отсутствующих данных.

    Заполнение выпадающих списков

    Важное правило: при смене типа нужно сбрасывать модель и выбранные опции, иначе пользователь может оставить комбинацию, которая не существует.

    Примечание: здесь используется innerHTML = '' только чтобы очистить select. Для строк расчёта и пользовательского контента лучше использовать безопасную отрисовку через textContent.

    Валидация: что и когда проверяем

    Валидация нужна не для того, чтобы усложнить код, а чтобы:

  • не показывать бессмысленный итог
  • объяснить пользователю, что именно нужно заполнить
  • защититься от NaN и ошибок данных
  • Справочник по валидации форм:

  • MDN: Client-side form validation
  • Правила валидации для нашего калькулятора

    Минимальный набор:

  • тип обязателен
  • модель обязательна
  • количество целое число и не меньше 1
  • если выбрана опция доставки, регион должен быть выбран
  • Пример функции валидации, которая возвращает список ошибок:

    Практика:

  • Number.isInteger защищает от значений типа 2.5
  • проверка существования модели защищает от ситуации, когда прайс обновился, а пользователь держит старую страницу открытой
  • Расчёт: строки расшифровки и итог

    Мы будем считать так же, как договорились на этапе проектирования:

  • базовая цена модели за единицу
  • опции, которые относятся к единице товара, добавляем к цене за единицу
  • умножаем на количество
  • применяем скидку (если есть правило)
  • добавляем доставку (обычно на заказ)
  • Чтобы пользователю было понятно, из чего складывается сумма, мы считаем не только итог, но и строки расшифровки.

    Формат строки расчёта

    Удобный минимальный формат для строки:

  • label текст
  • amount сумма строки в деньгах (положительная или отрицательная)
  • Почему это удобно:

  • отрисовка превращается в простой цикл
  • легко тестировать расчёт, сравнивая ожидаемые строки
  • Подсчёт стоимости опций

    Мы поддерживаем три типа ценообразования из проектирования данных:

  • fixed фиксированная сумма
  • percent процент от базовой цены модели
  • byRegion значение из таблицы регионов
  • Пример функции расчёта одной опции:

    Замечание про округление:

  • проценты могут дать дробное значение
  • для учебного проекта достаточно округлять до целых рублей через Math.round
  • Скидка по правилу количества

    Если в прайсе есть правила скидок, мы применяем первое подходящее (или самое выгодное, если вы так решите). Для простоты возьмём правило вида минимальное количество.

    Важно заранее решить и держаться этого решения: применять первое подходящее или максимальную скидку. В коммерческом проекте обычно выбирают максимальную, но для учебного достаточно первого правила.

    Главная функция расчёта

    Замечание: в describeOptionPricing мы показываем число без форматирования валюты, потому что это справка, а не сумма конкретного расчёта. Если хотите, можете форматировать и здесь.

    Типичные ошибки и как их избежать

  • Смешивание строк и чисел
  • - qty из input приходит строкой - всегда приводите к Number перед расчётом

  • Появление NaN в итогах
  • - почти всегда связано с тем, что не выбрана модель или регион, но расчёт всё равно пошёл - решается связкой валидация → только потом расчёт

  • Небезопасная отрисовка через innerHTML
  • - для пользовательских строк используйте textContent - так вы защищаетесь от случайных вставок HTML и упрощаете поддержку

  • Опции считаются, хотя недоступны
  • - не только отключайте чекбокс, но и очищайте optionIds при смене модели

    Итог

    После этого шага у вас есть полноценная логика калькулятора:

  • прайс загружается из price.json
  • интерфейс (типы, модели, опции) строится из данных
  • ввод валидируется, ошибки показываются пользователю
  • итог и расшифровка считаются по зафиксированным правилам
  • суммы форматируются и выглядят аккуратно
  • Дальше по курсу логично переходить к финализации проекта: подготовке файлов для публикации, проверкам на реальном хостинге и настройке публичной ссылки.

    5. Интеграции: отправка заявки, сохранение расчёта и аналитика

    Интеграции: отправка заявки, сохранение расчёта и аналитика

    Как эта статья связана с предыдущими

    Ранее в курсе мы:

  • зафиксировали требования к калькулятору и структуре сайта
  • спроектировали прайс в JSON и правила расчёта
  • сделали адаптивную вёрстку с понятными точками привязки
  • реализовали расчёт на JavaScript: загрузку price.json, валидацию, расшифровку и итог
  • Теперь добавим то, что превращает калькулятор из демо в рабочий инструмент продаж:

  • отправку заявки с выбранной конфигурацией
  • сохранение расчёта, чтобы пользователь мог вернуться к нему
  • аналитику, чтобы понимать, как калькулятор используется и где теряются заявки
  • !Общая картина интеграций вокруг калькулятора

    Что мы хотим получить в итоге

    После внедрения интеграций ваш сайт должен уметь:

  • превращать расчёт в понятное сообщение для менеджера и клиента
  • сохранять выбор пользователя без серверной части
  • отправлять события в систему аналитики без «ломания» калькулятора, если аналитика не загрузилась
  • Важно: мы продолжаем ориентироваться на статический сайт. Это значит, что серверную часть мы либо не используем, либо заменяем внешними сервисами.

    Отправка заявки: варианты для статического сайта

    Отправка заявки решает одну задачу: передать менеджеру конфигурацию и итог, а пользователю дать понятный следующий шаг.

    Ниже три практичных варианта, которые работают со статическим хостингом.

    Вариант A: отправка в почту или мессенджер без формы

    Подходит, если:

  • у вас нет необходимости собирать заявки в таблицу
  • вы хотите максимально простую реализацию без внешних сервисов
  • Способы:

  • mailto: ссылка с темой и текстом письма
  • ссылка на Telegram с текстом сообщения
  • ссылка на WhatsApp с текстом сообщения
  • Техническая особенность: текст нужно кодировать через encodeURIComponent, иначе пробелы и спецсимволы сломают ссылку.

    Справочник:

  • MDN: encodeURIComponent
  • #### Пример: генерация текста расчёта

    Практическое замечание: в тексте лучше использовать понятные человеку названия (например, title), а не id. Для этого обычно делают маппинг id → title через поиск в прайсе.

    #### Пример: кнопка «Отправить в Telegram»

    Справочник:

  • Telegram: Share Button
  • Вариант B: форма, которая отправляет данные во внешний сервис

    Подходит, если:

  • вы хотите получать заявки централизованно
  • вы хотите видеть заявки в кабинете сервиса или получать их на почту
  • Популярные решения для статических сайтов:

  • Formspree
  • Netlify Forms
  • Что важно продумать заранее:

  • какие поля обязательны (например, имя и телефон)
  • куда положить текст расчёта (например, скрытое поле quoteText)
  • защита от спама (у сервиса обычно есть настройки, а на форме можно добавить простую honeypot-ловушку)
  • #### Как передать расчёт в форму

    Идея: перед отправкой формы вы кладёте результат расчёта в поле textarea или скрытое поле.

    Далее вы вызываете fillQuoteToForm() на событии submit и отменяете отправку, если есть ошибки.

    Справочник:

  • MDN: FormData
  • Вариант C: заявка как «копируемый расчёт» + контакты

    Подходит, если:

  • вы не хотите никаких внешних сервисов
  • вы готовы, что часть пользователей просто скопирует расчёт и отправит его в чат или на почту вручную
  • Что добавить в интерфейс:

  • кнопку «Скопировать расчёт»
  • рядом блок контактов: телефон, почта, мессенджеры
  • Справочник:

  • MDN: Clipboard API
  • Пример копирования:

    Сохранение расчёта: чтобы пользователь мог вернуться

    Сохранение решает сразу две проблемы:

  • пользователь может случайно закрыть вкладку и потерять конфигурацию
  • пользователь может вернуться к расчёту позже или отправить ссылку коллеге
  • Для статического сайта есть два основных подхода: ссылка с параметрами и localStorage. Их можно использовать вместе.

    Сохранение в ссылку через параметры URL

    Плюсы:

  • пользователь может поделиться ссылкой
  • ничего не хранится на устройстве «навсегда»
  • Минусы:

  • нельзя безопасно хранить персональные данные в URL
  • URL может стать длинным, если вы попытаетесь запихнуть туда всю расшифровку
  • Рекомендация: сохраняйте в URL только выбор (тип, модель, количество, опции, регион), а расчёт пересчитывайте при открытии.

    Справочники:

  • MDN: URLSearchParams
  • MDN: History.pushState
  • #### Пример: сериализация выбора в URL

    js function debounce(fn, ms) { let t = null return (...args) => { clearTimeout(t) t = setTimeout(() => fn(...args), ms) } }

    const trackChangeDebounced = debounce(() => { track('calc_change', { type: state.selection.typeId || 'none', model: state.selection.modelId || 'none' }) }, 600) ``

    Конфиденциальность и согласие

    Если вы используете аналитические cookies, во многих случаях нужен механизм согласия. В рамках учебного проекта достаточно:

  • разместить короткое уведомление о сборе статистики
  • добавить ссылку на политику конфиденциальности
  • не отправлять персональные данные в аналитику
  • Мини-чеклист тестирования интеграций

    Перед публикацией на хостинге проверьте:

  • при невыбранных обязательных полях кнопка отправки заявки не уводит пользователя в «пустое» сообщение
  • текст заявки читаемый и не содержит внутренних id, если это не задумано
  • ссылки на мессенджеры открываются корректно, текст не ломается из-за кодирования
  • после обновления страницы выбор восстанавливается из URL или localStorage
  • если отключить аналитический скрипт, калькулятор всё равно работает
  • события не отправляются слишком часто (особенно при вводе количества)
  • Итог

    На этом этапе вы добавили к калькулятору важные интеграции:

  • отправка заявки без сервера или через внешний сервис
  • сохранение выбора через URL и localStorage
  • аналитика через события, чтобы измерять реальное использование
  • Следующий логичный шаг курса после интеграций: подготовить проект к публикации на хостинге, проверить загрузку price.json` в боевой среде и убедиться, что ссылки, формы и аналитика работают на публичном домене.

    6. Тестирование и оптимизация: корректность расчётов, скорость, SEO

    Тестирование и оптимизация: корректность расчётов, скорость, SEO

    Как эта статья связана с предыдущими

    Ранее в курсе вы:

  • зафиксировали требования к калькулятору и структуре сайта
  • спроектировали данные в price.json и правила расчёта
  • сверстали адаптивный интерфейс и подготовили точки привязки
  • реализовали JavaScript-логику: загрузку прайса, валидацию, расчёт, расшифровку
  • добавили интеграции: отправку заявки, сохранение выбора и аналитику
  • Теперь важно убедиться, что проект:

  • считает корректно при любых реалистичных вводах
  • работает быстро и стабильно на мобильных
  • нормально индексируется поиском и имеет базовую SEO-гигиену
  • !Общая карта работ: что проверять перед публикацией и после обновлений

    Что именно будем проверять

    Качество проекта удобно разделить на три слоя.

  • Корректность
  • Скорость и устойчивость
  • SEO и индексируемость
  • Главный принцип: калькулятор должен оставаться корректным даже после обновления price.json.

    Корректность расчётов

    Базовый набор сценариев как «регрессионные тесты»

    В статье про проектирование данных вы уже формулировали сценарии. Теперь превратим их в короткий чек-лист, который вы прогоняете:

  • после правок формул
  • после правок UI
  • после обновления прайса
  • Минимальный набор:

  • расчёт без опций при количестве 1
  • расчёт с фиксированной опцией
  • расчёт с процентной опцией
  • доставка по региону
  • скидка по количеству
  • недоступная опция не участвует в расчёте
  • некорректные вводы не дают получить «мусорный итог»
  • Рекомендация: заведите отдельный файл TESTS.md и храните там эти сценарии в виде таблицы с ожидаемыми суммами.

    Пограничные случаи, которые чаще всего ломают калькуляторы

    Проверяйте их вручную или автоматизируйте.

  • Количество: 1, большое число, пусто, 0, отрицательное, дробное, текст.
  • Не выбран тип или модель: итог не должен считаться.
  • Включена доставка без региона: должна быть ошибка валидации.
  • Прайс обновился: выбранная модель исчезла.
  • Процентные опции: округление даёт неожиданные копейки, итог «прыгает».
  • Хорошая практика: договориться об округлении один раз и применять его в одном месте. В статье про логику мы округляли проценты через Math.round.

    Детерминированность расчёта

    Детерминированность означает: при одинаковом выборе пользователя результат всегда одинаковый.

    Чтобы это обеспечить:

  • не используйте текущую дату и случайные числа в вычислениях
  • не храните цены в нескольких местах
  • не смешивайте форматирование и математику
  • Правило: сначала считаем числа, потом форматируем их для отображения.

    Мини-набор автоматических тестов без библиотек

    Для учебного проекта можно сделать простейший тест-раннер прямо в браузере, чтобы быстро ловить ошибки после правок.

    Идея:

  • вы выносите computeQuote() и функции поиска в отдельный файл (например, calc-core.js)
  • подключаете его на тестовой странице или запускаете в консоли
  • сравниваете фактический итог с ожидаемым
  • Пример простых тестов (их можно запускать в DevTools Console):

    Что важно в таких тестах:

  • они проверяют не интерфейс, а математику
  • они помогают безопасно менять вёрстку, не боясь «сломать расчёт»
  • Проверка целостности price.json

    Когда прайс хранится отдельно, возникают ошибки данных. Поэтому полезно проверять структуру прайса.

    Минимальные проверки:

  • у каждого типа есть id и models
  • у каждой модели есть id и basePrice
  • allowedOptions содержит только те id, которые реально существуют в options
  • для доставки по регионам все regionId уникальны
  • Пример базовой проверки (упрощённо):

    Если вы регулярно обновляете прайс, такая проверка экономит много времени.

    Скорость и устойчивость

    Как измерять скорость

    Вам нужны два инструмента:

  • отчёт Lighthouse в Chrome DevTools
  • вкладка Network для проверки веса ресурсов и кэша
  • Ссылки:

  • Lighthouse (документация Chrome)
  • Основы производительности на web.dev
  • В Lighthouse ориентируйтесь не только на общий балл, но и на причины проблем.

    Типовые причины медленной загрузки у статического сайта

  • тяжёлые изображения на главной
  • шрифты и стили подключены без необходимости
  • большие JavaScript-файлы и лишние библиотеки
  • нет кэширования на хостинге
  • price.json слишком большой и грузится без нужды
  • Практичные оптимизации без усложнения проекта

    #### Изображения

  • уменьшайте исходный размер изображений под реальные нужды
  • используйте современные форматы, если ваш хостинг и аудитория это поддерживают
  • не размещайте на странице изображения «на 4000px шириной», если в макете нужно 1000px
  • Справочник:

  • Изображения и производительность на web.dev
  • #### JavaScript

  • держите расчёт и форматирование в небольших функциях
  • избегайте тяжёлых фреймворков, если проект простой
  • не пересчитывайте и не отправляйте аналитику на каждый ввод символа, используйте debounce
  • Справочник:

  • MDN: RequestAnimationFrame
  • Если вы заметили «дёрганье» интерфейса при частых изменениях, переносите тяжёлую отрисовку на следующий кадр через requestAnimationFrame.

    #### Сеть и кэш

    Проверки:

  • price.json должен отдаваться быстро и без ошибок
  • при повторном открытии сайт не должен заново скачивать тяжёлые ресурсы
  • Что можно сделать на практике в рамках статического хостинга:

  • не включать cache: 'no-store' в продакшене
  • версионировать файлы при релизах, если хостинг агрессивно кэширует
  • Простой подход к версионированию:

  • app.v1.js, styles.v1.css, price.v1.json
  • Тогда браузер не будет путаться со старой версией.

    Устойчивость: что должно происходить при ошибках

    Ошибки неизбежны: сеть может быть медленной, прайс может быть недоступен.

    Минимальные требования к устойчивости:

  • при недоступном price.json пользователь видит понятное сообщение
  • элементы ввода отключаются, чтобы не создавать ощущение «калькулятор считает нули»
  • ошибки валидации всегда показываются рядом с действием пользователя
  • Полезно протестировать намеренно:

  • переименовать price.json и убедиться, что UI показывает ошибку
  • открыть сайт в режиме Offline в DevTools и проверить поведение
  • SEO для сайта с калькулятором

    Что такое SEO в контексте проекта

    SEO здесь решает две задачи:

  • поисковик должен понять, о чём ваш сайт
  • страницы должны индексироваться и иметь корректный сниппет
  • Калькулятор сам по себе часто не даёт «текстового контента», поэтому важно помочь поисковику.

    Минимальный набор SEO-элементов

    Проверьте для каждой важной страницы:

  • есть уникальный заголовок страницы и понятное название
  • есть краткое описание страницы
  • один главный заголовок и логичная структура подзаголовков
  • текст, объясняющий, что именно считается в калькуляторе
  • контактные данные и региональность, если это важно
  • Справочник:

  • Основы SEO на web.dev
  • Семантика и доступность помогают SEO

    Поисковики лучше понимают страницу, когда она:

  • имеет понятные заголовки
  • использует подписи к полям
  • содержит читаемый текст, а не только интерфейс
  • Это пересекается с доступностью.

    Справочник:

  • MDN: Accessibility
  • Индексация: robots и sitemap

    Для небольшого сайта полезно:

  • добавить sitemap.xml со ссылками на основные страницы
  • добавить robots.txt, который не блокирует важные страницы
  • Если вы используете внешний домен и хотите быстрее увидеть индексацию, обычно подключают панели для вебмастеров.

    Каноничность и дубли

    Если вы сохраняете выбор пользователя в URL (параметры type, model, qty), появляется риск множества URL с почти одинаковым контентом.

    Практичные решения для учебного проекта:

  • сохранять параметры в URL, но не продвигать эти URL как отдельные страницы
  • оставить основной «чистый» адрес страницы калькулятора как главный
  • Если вы в будущем будете развивать проект, можно отдельно продумать канонические адреса.

    Микроулучшения для сниппета и доверия

  • добавьте текст рядом с итогом: что входит и что не входит в цену
  • укажите, что расчёт ориентировочный, если это так
  • добавьте блок FAQ на странице калькулятора: 5–7 вопросов, которые реально задают
  • FAQ улучшает полезность страницы и добавляет текст, который индексируется.

    Финальный чек-лист перед публикацией

    Проверьте по порядку:

  • Калькулятор считает по всем сценариям из TESTS.md.
  • Валидация не даёт получить некорректный итог.
  • Ошибка загрузки price.json обрабатывается понятным сообщением.
  • Выбор корректно сохраняется и восстанавливается из URL или localStorage.
  • Lighthouse не показывает критических проблем (особенно на мобильном профиле).
  • Страницы имеют понятные заголовки и текст, объясняющий предложение.
  • Есть robots.txt и sitemap.xml, если вы хотите ускорить индексацию.
  • Что дальше по курсу

    После тестирования и оптимизации логичный следующий шаг: публикация на хостинге и проверка уже на боевом домене.

    На хостинге важно повторить ключевые проверки:

  • загружается ли price.json без ошибок и с правильным MIME-типом
  • работают ли интеграции (форма, мессенджеры, аналитика)
  • не ломается ли сохранение в URL при реальном адресе сайта
  • 7. Публикация на хостинге: домен, SSL, деплой, обновления и бэкапы

    Публикация на хостинге: домен, SSL, деплой, обновления и бэкапы

    Как эта статья связана с предыдущими

    На прошлых этапах у вас уже есть готовый статический проект:

  • структура страниц и требования
  • прайс в price.json
  • адаптивная вёрстка
  • логика калькулятора на JavaScript
  • интеграции (заявка, сохранение, аналитика)
  • тестирование, базовая оптимизация и SEO-гигиена
  • Теперь задача практическая: сделать сайт доступным по публичной ссылке, подключить домен, включить HTTPS, настроить процесс обновлений и продумать бэкапы, чтобы не потерять проект и уметь быстро откатываться.

    !Общая схема пути от локальных файлов до публичного сайта

    Что такое хостинг для статического сайта

    Статический сайт состоит из файлов, которые хостинг просто раздаёт браузеру:

  • HTML
  • CSS
  • JavaScript
  • JSON (ваш price.json)
  • изображения
  • Плюс такого подхода:

  • не нужен серверный код
  • проще деплой
  • дешевле и надёжнее
  • Важная деталь курса: калькулятор должен корректно загружать price.json по сети, а значит хостинг обязан отдавать этот файл без ошибок и блокировок.

    Как выбрать платформу хостинга

    Ниже три популярных варианта для статических проектов. Любой подойдёт для курса.

    | Вариант | Когда выбирать | Плюсы | Минусы | |---|---|---|---| | GitHub Pages | учебный проект, портфолио | бесплатно, просто, удобно с Git | меньше возможностей по формам и настройкам | | Netlify | нужен удобный деплой, формы, редиректы | много функций, деплой из Git, Netlify Forms | часть функций требует настройки аккаунта | | Vercel | хотите быстрый деплой из Git и хорошую CDN-раздачу | простой деплой, хорошая скорость | больше ориентирован на проекты с сборкой, хотя статике тоже подходит |

    Документация:

  • GitHub Pages documentation
  • Netlify Docs
  • Vercel Documentation
  • Подготовка проекта к публикации

    Перед деплоем проверьте структуру и относительные пути.

    Рекомендуемая структура файлов

    Ключевой принцип: используйте относительные пути, чтобы сайт одинаково работал локально и на хостинге.

    Примеры корректных подключений:

    Если разместить проект в подпапке, абсолютные пути вида /assets/app.js часто ломаются. Это типичная причина, почему «локально всё работает, а на хостинге нет».

    Проверка перед публикацией

  • откройте сайт локально через простой сервер, а не двойным кликом по HTML
  • убедитесь, что fetch к price.json работает
  • Быстрый вариант через Node.js:

    Сайт откроется по локальному адресу, и вы увидите сетевые ошибки, если пути настроены неверно.

    Деплой на GitHub Pages

    GitHub Pages хорошо подходит для статического сайта без сборки.

    Публикация через ветку

  • Создайте репозиторий и загрузите туда файлы.
  • Откройте настройки репозитория.
  • Включите Pages и выберите источник публикации.
  • Официальное руководство:

  • Configuring a publishing source for your GitHub Pages site
  • Частая проблема: путь сайта с репозиторием

    Если сайт доступен как https://username.github.io/repo-name/, то:

  • все ссылки и ресурсы должны открываться с учётом подпапки
  • относительные пути обычно спасают
  • Если у вас много путей, проще использовать деплой на корневой домен или выбрать платформу, где сайт живёт в корне.

    Деплой на Netlify

    Netlify особенно удобен, когда вы хотите:

  • деплой из Git
  • кастомный домен
  • редиректы
  • формы
  • Официальный старт:

  • Get started with Netlify
  • Вариант деплоя без Git

  • Соберите папку проекта.
  • Перетащите папку в Netlify в раздел загрузки.
  • Это быстро, но хуже для обновлений, поэтому для курса лучше деплой из Git.

    Деплой из Git

  • Подключите репозиторий.
  • Выберите ветку.
  • Если сборки нет, оставьте build-настройки пустыми.
  • Netlify будет автоматически публиковать сайт после каждого push.

    Деплой на Vercel

    Vercel тоже умеет статические сайты из Git и часто даёт очень быстрый результат по скорости загрузки.

    Официальные инструкции:

  • Deploying a static site
  • Логика похожа:

  • импортируете репозиторий
  • выбираете настройки
  • получаете публичный URL
  • Домен: что купить и как подключить

    Что такое домен и из чего он состоит

    Домен это человекочитаемый адрес сайта, например example.ru.

    Обычно вам нужно:

  • купить домен у регистратора
  • привязать домен к хостингу через DNS
  • DNS простыми словами

    DNS это система, которая говорит браузеру: на какой сервер или платформу указывает домен.

    Чаще всего вы встретите записи:

  • A запись указывает домен на IP-адрес
  • CNAME указывает поддомен на другой домен (например, на домен платформы)
  • У хостинга всегда есть официальная инструкция, какие записи добавить.

    Подключение домена к хостингу

    Типовой сценарий:

  • В панели хостинга добавляете свой домен.
  • Платформа показывает, какие DNS-записи нужно создать.
  • В панели регистратора домена создаёте записи.
  • Ждёте обновления DNS.
  • У Netlify есть отдельный раздел:

  • Netlify DNS
  • У GitHub Pages:

  • Managing a custom domain for your GitHub Pages site
  • У Vercel:

  • Domains on Vercel
  • Рекомендация по домену с www и без

    Практичный вариант:

  • сделать основной домен без www или с www
  • второй вариант настроить как редирект на основной
  • Так вы избегаете дублей и путаницы в аналитике.

    SSL и HTTPS: зачем и как включить

    Что такое SSL и HTTPS

    HTTPS это защищённый протокол доступа к сайту. SSL-сертификат нужен, чтобы:

  • браузер не показывал предупреждение «небезопасно»
  • данные (например, формы) передавались безопасно
  • современные API браузера работали стабильнее
  • Сейчас почти все платформы включают HTTPS автоматически.

    Откуда берутся сертификаты

    Обычно сертификаты выдаёт Let’s Encrypt:

  • Let’s Encrypt
  • Вы вручную ничего не «покупаете» и не устанавливаете, если используете GitHub Pages, Netlify или Vercel.

    Обязательное правило

    Включите принудительный HTTPS, чтобы все заходы по http:// перекидывало на https://.

    На платформах это обычно переключатель в настройках домена.

    Проверки после деплоя

    После публикации пройдитесь по чек-листу.

    Проверка загрузки price.json

  • Откройте сайт.
  • Откройте DevTools.
  • Вкладка Network.
  • Найдите запрос price.json.
  • Должно быть:

  • статус 200
  • корректный размер
  • без ошибок CORS
  • Если видите 404, проблема почти всегда в пути fetch('./data/price.json') и в реальном расположении файла на хостинге.

    Проверка MIME-типа

    Иногда хостинг может отдавать JSON неправильно, но на популярных платформах это редкость. Если браузер ругается, убедитесь, что файл реально имеет расширение .json.

    Проверка ссылок и роутинга

    Если у вас несколько HTML-страниц, проверьте:

  • переходы из меню
  • открытие страниц по прямой ссылке
  • отсутствие «битых» путей к стилям и скриптам
  • Обновления: как выпускать изменения без хаоса

    Минимальная стратегия релизов

    Хорошая базовая стратегия для учебного и небольшого коммерческого проекта:

  • Все изменения делаете в Git.
  • Каждый логический набор изменений это отдельный коммит.
  • Деплой происходит автоматически после push в основную ветку.
  • Это даёт понятную историю изменений и простой откат.

    Как обновлять прайс безопасно

    price.json меняется чаще всего, поэтому важно:

  • хранить его в репозитории
  • перед публикацией прогонять проверки корректности
  • Из предыдущей статьи у вас уже есть идеи валидации прайса. Практика:

  • делайте отдельный коммит вида Update price.json: Feb 2026
  • после деплоя обязательно прогоняйте 3–5 ключевых сценариев расчёта
  • Версионирование файлов и кэш

    Если хостинг или браузер агрессивно кэширует, вы можете увидеть ситуацию:

  • HTML обновился
  • JS или price.json остались старые
  • Практичное решение:

  • добавлять версию в имя файла при крупных изменениях
  • Пример:

  • app.v2.js
  • styles.v2.css
  • price.v2.json
  • И обновлять ссылки в HTML. Это простой способ заставить браузер скачать новую версию.

    Бэкапы и откаты

    Что считать бэкапом для статического сайта

    Для статического проекта лучший бэкап это:

  • репозиторий Git с историей
  • копия доменных настроек (какие DNS-записи нужны)
  • копия важных настроек хостинга (редиректы, формы)
  • Практика отката

    Если после обновления что-то сломалось:

  • Откатите последний коммит.
  • Запушьте изменения.
  • Платформа задеплоит предыдущую версию.
  • На многих платформах есть и откат деплоя в интерфейсе.

    На Netlify это отдельная функция:

  • Deploys overview
  • Что бэкапить отдельно от кода

    Если вы используете внешние сервисы:

  • формы (например, Formspree)
  • аналитика
  • то сохраняйте хотя бы:

  • идентификаторы счётчиков
  • тексты уведомлений
  • список событий аналитики
  • Это помогает быстро восстановить проект на другой платформе.

    Минимальный план обслуживания после публикации

    Чтобы проект не превратился в «заброшенную страницу», заведите простой ритм.

  • раз в месяц проверять, что сайт открывается по HTTPS
  • после каждого обновления price.json прогонять сценарии расчёта
  • раз в квартал запускать Lighthouse и проверять, не появились ли критические проблемы
  • хранить контакты и доменные доступы в безопасном месте
  • Итог

    После этого шага у вас должен быть не просто работающий калькулятор, а опубликованный продукт:

  • сайт доступен по публичной ссылке
  • подключён домен
  • включён HTTPS с SSL
  • настроен деплой и понятный процесс обновлений
  • продуманы бэкапы и способ отката
  • Дальше проект уже можно развивать как коммерческий инструмент: расширять прайс, добавлять новые сценарии, улучшать форму заявки и настраивать маркетинг, не ломая основу.