Каждый раз, когда сажусь за лендинг или небольшой сервис на чистом фронтенде, ловлю одно и то же чувство: логика продумана за 20 минут, а вёрстка и DOM-манипуляции съедают два дня. Фреймворк тут не спасает — тащить React ради страницы с формой и аккордеоном абсурдно, а ванильный JavaScript без структуры превращается в кашу из querySelector и обработчиков.
За последние месяцы я перестал писать такие проекты руками. Не потому, что разучился, а потому, что ИИ делает черновую работу быстрее и аккуратнее — если дать ему правильный промт. Разница между «сгенерируй мне сайт» и структурированным запросом с ограничениями — это разница между мусором и рабочим кодом с первого раза.
Ниже — 12 промтов, которые я реально использую. Каждый проверен на проектах: от портфолио-одностраничника до калькулятора с сохранением состояния в localStorage. Все примеры кода рабочие, без фреймворков и сборщиков.
1. Каркас страницы с семантикой и мета-тегами
Первый промт задаёт скелет. Без него ИИ любит пихать всё в <div> и забывать про <main>, <nav> и <article> — а это бьёт по доступности и SEO.
Промт:
Ты — фронтенд-разработчик. Сгенерируй семантический HTML5-каркас для [тип страницы]. Требования: только семантические теги (header, nav, main, section, article, aside, footer), корректный порядок заголовков h1–h3, мета-теги viewport, description, Open Graph. Никаких inline-стилей. Разметку дай одним блоком с комментариями, где какой раздел.
Пример результата для страницы курса:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="Практический курс по ванильному JavaScript">
<title>Курс JS без фреймворков</title>
</head>
<body>
<header>
<nav aria-label="Основная навигация">...</nav>
</header>
<main>
<h1>JavaScript без фреймворков</h1>
<section aria-labelledby="program">
<h2 id="program">Программа</h2>
</section>
</main>
<footer>...</footer>
</body>
</html>
Экономия — не в символах, а в том, что потом не переписываешь структуру под скринридеры и не объясняешь поисковику, что тут вообще происходит.
2. Адаптивная сетка на CSS Grid без медиа-запросов
Классическая боль: три брейкпоинта, которые ломаются на планшетах. Промт заставляет ИИ использовать auto-fit и minmax() вместо хардкода.
Промт:
Свёрстай адаптивную сетку карточек на CSS Grid. Условия: без медиа-запросов, автоматическое перестроение от 1 до 4 колонок в зависимости от ширины контейнера, gap 1.5rem, карточки одинаковой высоты. Используй repeat(auto-fit, minmax(...)). Объясни, почему выбрал именно такие значения.
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 1.5rem;
}
.cards > article {
display: flex;
flex-direction: column;
}
minmax(260px, 1fr) — рабочая лошадка: контейнер сам решает, сколько колонок влезет. Я использую этот промт почти в каждом проекте, где есть списки.
3. Тёмная тема через CSS-переменные и prefers-color-scheme
Раньше я делал переключатель темы на JS с классами на <body>. Теперь прошу сразу правильный слой переменных.
Промт:
Сделай систему цветов на CSS custom properties с поддержкой тёмной темы через prefers-color-scheme и ручным переключателем. Переменные объяви в :root, тёмные значения — в @media (prefers-color-scheme: dark) и в атрибуте [data-theme="dark"]. Переключатель — кнопка, которая меняет data-theme на html и сохраняет выбор в localStorage. Дай HTML, CSS и JS.
:root { --bg: #ffffff; --text: #1a1a1a; }
@media (prefers-color-scheme: dark) {
:root { --bg: #121212; --text: #eaeaea; }
}
[data-theme="dark"] { --bg: #121212; --text: #eaeaea; }
body { background: var(--bg); color: var(--text); }
const btn = document.querySelector('[data-theme-toggle]');
btn.addEventListener('click', () => {
const next = document.documentElement.dataset.theme === 'dark' ? 'light' : 'dark';
document.documentElement.dataset.theme = next;
localStorage.setItem('theme', next);
});
Важно: промт отдельно требует и системную тему, и ручную — иначе ИИ сделает только одно.
4. Аккордеон на нативных <details> и `
Самый недооценённый промт. Вместо 40 строк JS с классами и aria-атрибутами — нативный элемент, который уже доступен с клавиатуры и скринридеров.
Промт:
Сделай FAQ-аккордеон на нативных details/summary без JavaScript. Стилизуй маркер через ::marker или скрытый summary::-webkit-details-marker, добавь плавное раскрытие через grid-template-rows или max-height. Никаких библиотек.
<details>
<summary>Нужен ли фреймворк?</summary>
<p>Нет, для большинства лендингов хватает ванильного JS.</p>
</details>
details[open] summary { color: #0b5fff; }
summary { cursor: pointer; padding: .75rem 0; }
Если ИИ предлагает «сделать красиво через JS» — это сигнал переписать промт и явно запретить скрипты.
5. Валидация формы на Constraint Validation API
Браузер умеет валидировать формы сам. Промт заставляет использовать встроенный API вместо самописных регулярок на каждый чих.
Промт:
Сгенерируй форму регистрации с валидацией на Constraint Validation API: required, type=email, minlength, pattern. Показывай кастомные сообщения об ошибках через setCustomValidity и событие invalid, не используй сторонние библиотеки. Добавь aria-describedby для подсказок. Дай HTML, CSS и JS.
const email = document.querySelector('#email');
email.addEventListener('invalid', () => {
email.setCustomValidity('Введите корректный email, например name@domain.ru');
});
email.addEventListener('input', () => email.setCustomValidity(''));
Работает во всех современных браузерах, спецификация — HTML Living Standard на html.spec.whatwg.org. Проверено: сообщения появляются без единой сторонней зависимости.
6. Делегирование событий вместо N обработчиков
Когда ИИ генерирует список с кнопками, он часто вешает addEventListener на каждую. Промт это лечит.
Промт:
Есть динамический список задач. Реализуй обработку кликов и удаления через делегирование событий на контейнере, без навешивания слушателей на каждый элемент. Объясни, почему это лучше при добавлении новых элементов. Дай рабочий пример с data-атрибутами.
list.addEventListener('click', (e) => {
const btn = e.target.closest('[data-action="delete"]');
if (!btn) return;
btn.closest('li').remove();
});
Это не микрооптимизация: на списке из сотни элементов разница в потреблении памяти заметна, а код становится короче.
7. Состояние приложения без фреймворка
Главный аргумент сторонников React — управление состоянием. Промт показывает, что для небольших проектов хватает паттерна «объект состояния + функция render».
Промт:
Сделай счётчик и список задач на ванильном JS по паттерну: единый объект state, функция render(), которая перерисовывает DOM из state, и функции-экшены, которые меняют state и вызывают render. Без классов, без Proxy, без библиотек. Покажи, как добавить новую фичу без переписывания.
const state = { tasks: [] };
function render() {
list.innerHTML = state.tasks
.map(t => `<li>${t}</li>`)
.join('');
}
function addTask(text) {
state.tasks.push(text);
render();
}
Для проектов до нескольких экранов этого хватает с головой. Когда перестаёт хватать — тогда и думаешь про фреймворк, а не наоборот.
8. Работа с fetch и обработка ошибок
Половина «сломанных» интеграций — это fetch без проверки response.ok. Промт фиксирует паттерн.
Промт:
Напиши функцию загрузки данных через fetch с таймаутом через AbortController, проверкой response.ok, обработкой сетевых ошибок и JSON-парсинга. Верни понятную ошибку с кодом статуса. Добавь пример использования с async/await и try/catch.
async function loadData(url, timeout = 5000) {
const ctrl = new AbortController();
const id = setTimeout(() => ctrl.abort(), timeout);
try {
const res = await fetch(url, { signal: ctrl.signal });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return await res.json();
} finally {
clearTimeout(id);
}
}
AbortController — стандартный API, описан в спецификации WHATWG DOM/ Fetch. Таймаут через него — единственный корректный способ отменить зависший запрос без сторонних обёрток.
9. Модальное окно на <dialog>
Ещё один нативный элемент, который ИИ по привычке заменяет дивами. Промт возвращает его на место.
Промт:
Сделай модальное окно на элементе dialog с showModal() и close(). Требования: закрытие по Esc и клику на backdrop, фокус-трап встроенный, возврат фокуса на кнопку-триггер, стилизация ::backdrop. Без сторонних библиотек.
const dlg = document.querySelector('dialog');
dlg.addEventListener('click', (e) => {
if (e.target === dlg) dlg.close();
});
showModal() сам блокирует фон и управляет фокусом — это поведение браузера, а не магия библиотеки.
10. Анимации на Web Animations API
CSS-переходы не умеют в цепочки и отмену. Промт переключает на WAAPI там, где это уместно.
Промт:
Сделай анимацию появления карточек при скролле на IntersectionObserver + Element.animate(). Требования: без библиотек, без тяжёлых скролл-листенеров, уважай prefers-reduced-motion. Дай рабочий пример с пояснениями.
const io = new IntersectionObserver((entries) => {
entries.forEach(en => {
if (!en.isIntersecting) return;
en.target.animate(
[{ opacity: 0, transform: 'translateY(20px)' }, { opacity: 1, transform: 'none' }],
{ duration: 400, easing: 'ease-out', fill: 'forwards' }
);
io.unobserve(en.target);
});
});
document.querySelectorAll('.card').forEach(el => io.observe(el));
IntersectionObserver и Web Animations API — стандарты W3C, поддержка в актуальных браузерах полная.
11. Оптимизация: lazy-loading и изображения
Промт про производительность, который экономит реальные секунды загрузки.
Промт:
Проверь разметку страницы и добавь: loading="lazy" для изображений ниже первого экрана, decoding="async", width/height для предотвращения layout shift, srcset для адаптивных картинок. Объясни, какие метрики Core Web Vitals это улучшает и почему.
<img src="photo-800.jpg"
srcset="photo-400.jpg 400w, photo-800.jpg 800w"
sizes="(max-width: 600px) 400px, 800px"
width="800" height="600"
loading="lazy" decoding="async" alt="Пример">
Атрибуты width/height напрямую влияют на CLS — Cumulative Layout Shift из набора Core Web Vitals, описанного в документации web.dev.
12. Ревью кода: промт-аудитор
Последний и, пожалуй, самый полезный. Не генерация, а проверка того, что уже написано.
Промт:
Проведи ревью этого ванильного JS/HTML/CSS. Найди: необработанные ошибки fetch, утечки слушателей, отсутствие доступности (alt, aria, фокус), потенциальные XSS через innerHTML, неиспользуемые стили. Для каждой проблемы дай строку, объяснение и исправленный фрагмент. Не переписывай весь файл.
Я прогоняю через него каждый сгенерированный кусок перед коммитом. Особенно ловит innerHTML с пользовательскими данными — классический вектор XSS, описанный в OWASP Top 10 (категория A03: Injection).
| Промт | Что закрывает | Экономия времени |
|---|---|---|
| Каркас с семантикой | Доступность, SEO | ~30 мин |
| Grid без медиа-запросов | Адаптив | ~1 час |
| Тёмная тема на переменных | Дизайн-система | ~40 мин |
| Нативные details/dialog | JS-код и a11y | ~1 час |
| Делегирование событий | Утечки памяти | ~30 мин |
| Ревью-аудитор | XSS, баги | зависит от проекта |
Суммарно на типичном лендинге это те самые два дня, которые превращаются в один вечер. Не потому, что ИИ умнее, а потому, что правильный промт убирает этап «переделай по-человечески».
Заведите себе файл с этими промтами и адаптируйте под свой стек — через месяц вы заметите, что перестали писать одно и то же руками. А если хотите глубже разобраться, как формулировать такие запросы под свои задачи, — начните с одного: возьмите любой свой старый проект и прогоните его через промт №12. Разница в количестве найденного удивит.
Комментарии