Click, Change, Load: что нужно знать дизайнеру о событиях на сайте
Я часто вижу, как дизайнеры создают красивые прототипы, но теряются, когда нужно объяснить логику интерактивности разработчикам. Если ты не разбираешься в верстке, но хочешь понимать, как сайт реагирует на действия пользователя — эта статья для тебя. Я расскажу про основные события вроде click
или change
, объясню, к каким элементам они привязаны и как это влияет на UX. Ты сможешь проектировать осознаннее и говорить с верстальщиками на одном языке — даже без знания JS.
1. События, которые ты точно встречал
Если ты проектируешь интерфейсы, ты де-факто уже работаешь с событиями — просто не называешь их так. Давай разберём 5 самых популярных событий, которые отвечают за базовую интерактивность.
1.1. click
— «Кликнули? Делаем что-то!»
Где встречается
Кнопки (<button>
), ссылки (<a>
), карточки товаров, иконки.
Как работает
Срабатывает, когда пользователь кликает кнопкой мыши (или тапает на тачпаде или Enter при фокусе) по элементу на странице.
Типичный пример
Кнопка «Добавить в корзину» — событие срабатывает при любом клике (мышь, тап, Enter при фокусе).
- После отпускания кнопки мыши/тача (не при нажатии!).
- При нажатии Enter/Space на элементе с фокусом (если это
<button>
или элемент с атрибутомrole="button"
).
- Клик на лейбл (
<label>
)— переводит фокус на связанное поле ввода (<input>
), ноclick
сработает и на самом лейбле. - Клик на SVG-иконке внутри кнопки — событие «всплывает» до родительской кнопки.
- Клик правой кнопкой мыши — тоже триггерит
click
(но обычно это перехватывают черезcontextmenu
).
Пример из жизни
Если в твоём макете есть карточка, которая должна вести на страницу товара, лучше обернуть её в <a>
, а не назначать click
на <div>
.
1.2. change
— «Значение изменилось? Обновляем!»
Где встречается
Поля ввода (<input>
), выпадающие списки (<select>
), чекбоксы, другие контролы форм.
Как работает Срабатывает, когда пользователь изменил значение.
Типичный пример
Выбор страны в <select>
— событие срабатывает только после завершения взаимодействия (например, закрытие выпадающего списка).
- Для
<input type="text">
— при потере фокуса (blur
), если значение изменилось. - Для
<input type="checkbox">
— мгновенно при переключении. - Для
<select>
— после выбора пункта (даже если тот же пункт выбран повторно).
<input type="file">
— при выборе файла (даже если отменили диалог и выбрали тот же файл).<input type="range">
— только после отпускания ползунка (в отличие отoinput
).<textarea>
— работает так же, как текстовыйinput
, но дизайнеры часто забывают.
- Идеален для фильтров, форм и любых динамических данных — например, обновление цены при выборе варианта товара.
- Не путай с
input
(реагирует на каждое нажатие клавиши).
Пример из жизни
В Figma ты проектируешь селект с выбором страны. change
сработает только после выбора, а не во время прокрутки списка.
1.3. focus
/ blur
— «Куда нажали? Куда ушли?»
Где встречается
Поля ввода (<input>
), текстовые области (<textarea>
).
focus
— когда пользователь тапнул/кликнул в поле,blur
— когда фокус потерялся (тапнул/кликнул в другое место).
Типичный пример
Поле ввода email — focus
при клике внутрь, blur
при клике вне поля.
<div contenteditable="true">
— элемент с режимом редактирования тоже получает фокус, как поле ввода.focus
на ссылке (<a>
) — срабатывает при переходе по Tab, но игнорируется в большинстве интерфейсов.blur
для<select>
— если раскрыли список, но передумали и кликнули вне его.
Пример из жизни
В макете формы входа ты добавляешь анимацию лейбла при фокусе — это как раз focus
.
1.4. load
— «Всё загрузилось? Показываем!»
Где встречается
Изображения (<img>
), вся страница (<body>
), iframe.
Как работает Срабатывает, когда контент полностью загрузился.
Типичный пример
Изображение в галерее — событие срабатывает, когда весь контент (включая внешние ресурсы) загружен.
- Для изображений
<img>
— после полной загрузки изображения (даже если оно в кеше браузера). - Для скриптов
<script>
— после выполнения скрипта. - Для
<iframe>
— когда загружена вся вложенная страница.
<link rel="stylesheet">
—load
сработает после загрузки CSS.- SVG, встроенный через
<object>
— событие для SVG-документа. - Видео (
<video>
) — но чаще используютcanplay
(когда можно начать воспроизведение).
- Критично для лоадеров и «ленивой» загрузки — например, чтобы анимировать появление изображений.
- Не перегружай страницу тяжёлыми скриптами в
load
— это замедлит отрисовку.
Пример из жизни: Ты делаешь лендинг с фоновым видео. load
поможет запустить его только после загрузки, чтобы не ломать верстку.
1.5. submit
— «Форма отправлена? Проверяем!»
Где встречается
Формы (<form>
)
Как работает
Срабатывает при нажатии на кнопку отправки формы (<button type="submit">
или <input type="submit">
) или Enter в поле.
Типичный пример
Форма входа — событие срабатывает перед отправкой данных на сервер.
- При клике на
<button type="submit">
или<input type="submit">
. - При нажатии Enter в любом поле формы (если нет кнопки
type="button"
). - До фактической отправки — можно отменить через
e.preventDefault()
.
- Форма без кнопки — сработает при Enter в любом
input
. - Динамическая форма, созданная через JS —
submit
работает так же, как для обычной. <form method="dialog">
— для модальных окон в HTML5.
- Обязателено для валидации перед отправкой данных — например, проверка email.
- Не забудь отменить стандартное поведение (
e.preventDefault()
), если страница не должна перезагружаться.
Пример из жизни
В твоём макете есть форма подписки. submit
— это момент, когда можно показать анимацию «Спасибо».
Как это пригодится тебе?
Теперь, когда ты знаешь эти события, ты можешь:
- Осознанно проектировать интерактивность — например, не требовать анимацию при
click
для<div>
. - Говорить с разработчиками на их языке — «Здесь нужен
change
, а неoinput
». - Избегать «невозможных» решений — если в твоём прототипе 10 событий
mousemove
, это может тормозить.
2. Что происходит с формами? События, которые управляют данными
Если ты проектируешь формы, тебе нужно понимать не только визуальные состояния (вроде «ошибка» или «успех»), но и какие события запускают эти изменения. Вот главные «триггеры», которые влияют на поведение полей ввода, чекбоксов и других элементов форм.
2.1. input
— реакция на каждое нажатие
Типичный пример
Поле поиска с подсказками, где результаты обновляются по мере ввода.
- При каждом изменении значения (ввод символа, удаление, вставка из буфера).
- Не ждёт потери фокуса — работает мгновенно.
change
= «значение изменилось и подтверждено» (например, уход из поля).input
= «значение меняется прямо сейчас».
- Счётчик символов под полем комментария (обновляется при каждом нажатии).
- Динамическая валидация пароля (показывает силу пароля в реальном времени).
- Кастомные числовые поля (например, расчёт суммы при вводе цифр).
Совет для дизайнера
Если делаешь поле с мгновенной проверкой (например, поиск по базе), указывай в ТЗ:
«Использоватьinput
, а неchange
— подсказки должны появляться сразу при вводе».
2.2. invalid
— когда форма не отправляется
Типичный пример
Поле email с валидацией, которое подсвечивает ошибку, если введён некорректный адрес.
- При попытке отправить форму (
submit
), если поле не проходит встроенную HTML-валидацию (например,required
илиtype="email"
). - Можно кастомизировать стандартное сообщение браузера.
Ограничение
Не работает, если валидация написана на JavaScript (только нативные проверки HTML5).
- Поле с ограничением по длине (
minlength
/maxlength
). - Числовое поле с
min="0"
(покажет ошибку при отрицательном значении). - Кастомные стили ошибок — браузер показывает сообщение, но дизайн можно переопределить CSS.
2.3. reset
— когда форма очищается
Типичный пример
Кнопка «Очистить форму» в фильтрах или настройках.
- Только при клике на
<button type="reset">
или вызовеform.reset()
. - Не срабатывает при ручной очистке поля (например, удалении текста).
- Многостраничная форма (например, анкета), где можно сбросить все введённые данные.
- Динамически создаваемые поля — если их добавили после загрузки страницы,
reset
тоже их очистит. - Сброс фильтров в интернет-магазине без перезагрузки страницы.
Совет для дизайнера
Если в твоём макете есть кнопка «Очистить», уточни в ТЗ:
«Использоватьreset
, если нужно сбросить всю форму, илиclick
с ручным очищением полей, если только часть».
Как это пригодится тебе?
- Для мгновенной реакции (поиск, подсчёт символов) →
input
. - Для валидации при отправке →
invalid
+submit
. - Для сброса формы →
reset
.
Что дальше?
В следующей части я расскажу про события для сложных интерфейсов:
- Как сделать анимацию при наведении (
mouseover
). - Как реагировать на прокрутку (
scroll
). - Почему
dblclick
— это почти всегда плохая идея.
3. События для сложных интерфейсов: hover, скролл и опасные кейсы
Теперь разберём события, которые оживляют современные интерфейсы — от плавных hover-эффектов до анимаций при прокрутке. Я объясню, как они работают, когда их стоит использовать, а когда лучше избегать.
3.1. mouseover
/ mouseout
— «Навели курсор? Показываем подсказку!»
Типичный пример
Кнопка с выпадающей подсказкой при наведении.
mouseover
— когда курсор впервые попадает на элемент.mouseout
— когда курсор полностью покидает элемент (даже если перешёл на дочерний элемент!).
- На мобильных устройствах нет состояния наведения, поэтому такие эффекты должны дублироваться для тапов.
- Если внутри элемента есть другие вложенные элементы,
mouseout
сработает при переходе на них (это можно исправить черезmouseleave
).
- Интерактивная карта — подсветка регионов при наведении.
- Анимация иконки (например, вращение шестерёнки в настройках).
- Кастомные тултипы без использования CSS
:hover
.
Совет для дизайнера:
Если делаешь эффект наведения, продумай альтернативу для мобильных устройств:
«Использоватьmouseover
для десктопа, но добавитьclick
для мобильных».
3.2. scroll
— «Прокрутили страницу? Запускаем анимацию!»
Типичный пример
Появление блоков с текстом или изображениями по мере скролла (эффект «параллакс»).
- При любом перемещении скроллбара (включая инерцию на тач-устройствах).
- Можно отлавливать прокрутку конкретного элемента (например, боковой панели), а не всей страницы.
- Слишком частые вызовы
scroll
могут тормозить страницу (например, если внутри тяжёлые вычисления). - На iOS события скролла иногда срабатывают с задержкой.
- Бесконечная лента — подгрузка контента при достижении низа страницы.
- Фиксированное меню, которое меняет стиль после прокрутки на 100px.
- Кастомный скроллбар с анимацией.
Совет для дизайнера
Если хочешь анимацию при скролле, укажи в ТЗ:
«Оптимизироватьscroll
, чтобы не нагружать процессор (например, использоватьthrottling
)».
3.3. dblclick
— «Двойной клик? Почти никто не использует!»
Типичный пример
Редактор изображений, где двойной клик открывает полную версию.
- 95% пользователей не ожидают двойного клика в интерфейсах.
- На мобильных устройствах его почти невозможность.
- Конфликтует с
oclick
(оба события сработают).
- Переименование файла в файловом менеджере (как в Windows).
- Открытие превью в админ-панели.
- Выделение текста — но это нативное поведение браузера.
Совет для дизайнера
Замени dblclick
на:
- Однократный клик + иконку действия (например, карандаш для редактирования).
- Долгое нажатие (
touchstart
) для мобильных интерфейсов.
3.4. resize
— «Изменили размер окна? Адаптируем макет!»
Типичный пример
Адаптивное меню, которое меняет layout при сужении экрана.
- При изменении размеров окна браузера (ручное растягивание, поворот устройства).
- Не срабатывает при программном изменении размеров элемента (например, через JS).
- Событие вызывается многократно при резизовом окне (нужен
debounce
). - На мобильных устройствах срабатывает при повороте экрана, но не при появлении/скрытии клавиатуры.
- Динамические диаграммы, которые пересчитывают размеры.
- Кастомные сетки с изменяемым количеством колонок.
- Отключение анимаций на узких экранах.
Совет для дизайнера
Если твой дизайн чувствителен к размерам экрана, добавь в ТЗ:
«Использоватьresize
с задержкой (debounce
200ms), чтобы избежать лагов».
Итог для дизайнера
- Hover-эффекты →
mouseover
/mouseout
(но продумай мобильную версию). - Анимации при скролле →
scroll
(с оптимизацией!). - Двойной клик → лучше не использовать (
dblclick
). - Адаптация под размер экрана →
resize
(сdebounce
).
Ошибка, которую можно избежать
Не назначать scroll
на тяжёлые операции (например, пересчёт позиций десятков элементов) — это приведёт к тормозам.
4. События для мобильных устройств: тапы, свайпы и особенности touch-интерфейсов
Если ты проектируешь мобильные приложения или адаптивные сайты, стандартные события вроде click
и mouseover
работают иначе — или не работают вообще. В этой главе я объясню, какие события заменяют привычные клики и ховеры на сенсорных экранах, и как это влияет на UX.
4.1. touchstart
/ touchend
— аналог click
, но для пальцев
Типичный пример
Кнопка, которая должна реагировать на касание, а не на клик.
touchstart
— в момент первого касания экрана (аналогmousedown
).touchend
— когда палец отпускает экран (аналогmouseup
).
click
на мобильных имеет задержку ~300 мс (браузер ждёт, не будет ли двойного тапа).touchstart
срабатывает мгновенно, но не поддерживает hover-эффекты.
- Игры (например, прыжок персонажа при касании).
- Интерактивные карты — выделение зоны при касании.
- Кастомные свайпы (но для них лучше использовать
touchmove
).
Совет для дизайнера:
Если нужна мгновенная реакция на тап, укажи в ТЗ:
«Использоватьtouchstart
+touchend
вместоclick
для мобильных».
4.2. touchmove
— отслеживание движения пальца
Типичный пример
Галерея с горизонтальным свайпом.
- При движении пальца по экрану после
touchstart
. - Можно получить координаты касания (
event.touches[0].clientX
).
- Событие срабатывает очень часто (нужна оптимизация, чтобы избежать лагов).
- Не работает при попытке свайпать скролл страницы.
- Рисование пальцем (как в графических редакторах).
- Перетаскивание элементов (drag-and-drop).
- Управление громкостью (вертикальный свайп).
Совет для дизайнера:
Если делаешь интерфейс со свайпами, продумай:
«Добавить визуальную подсказку (например, точки для свайпа в галерее), так как не все пользователи ожидают этого жеста».
4.3. gesturestart
/ gesturechange
— масштабирование и поворот
Типичный пример
Изображение, которое можно увеличить двумя пальцами (пинч-зум).
- При мультитач-жестах (двумя и более пальцами).
- Позволяет отслеживать масштаб (
event.scale
) и угол поворота (event.rotation
).
- Работает только на iOS и некоторых Android-устройствах.
- Требует отмены стандартного поведения (
event.preventDefault()
), иначе браузер будет масштабировать всю страницу.
Совет для дизайнера:
Если проектируешь пинч-зум, укажи:
«Заблокировать стандартное масштабирование страницы через <meta name="viewport" content="user-scalable=no">
».
4.4. orientationchange
— поворот экрана
Типичный пример
Видеоплеер, который переключается между портретным и ландшафтным режимом.
- Только при изменении ориентации устройства (не при программном повороте элемента).
- Можно проверить новое положение через
window.orientation
.
- Не срабатывает на ПК (только мобильные устройства).
- На iOS иногда игнорируется, если страница загружена в iframe.
- Карусели, которые меняют количество слайдов при повороте.
- Адаптивные таблицы, преобразующиеся в карточки.
- Игры с разным управлением в портрете/ландшафте.
Совет для дизайнера
Всегда тестируй интерфейс в обоих ориентациях:
«При повороте экрана (orientationchange
) перестраивать сетку галереи с 2 на 4 колонки».
Итог для дизайнера
- Быстрые тапы →
touchstart
/touchend
. - Свайпы →
touchmove
(но избегай лагов). - Пинч-зум →
gesturechange
(только для iOS/Android). - Поворот экрана →
orientationchange
.
Ошибка, которую можно избежать
Не полагаться только на click
для мобильных — это вызовет задержку 300 мс.
5. Специальные события: жесты, анимации и неочевидные сценарии
Теперь разберём события, которые оживляют интерфейсы — от сложных жестов до анимаций и работы с мультимедиа. Эти знания помогут тебе проектировать по-настоящему динамичные интерфейсы, не нарушая UX.
5.1. animationstart
/ animationend
— контроль CSS-анимаций
Типичный пример
Кнопка, которая плавно исчезает после отправки формы.
animationstart
— в первый кадр анимации (даже если она на паузе).animationend
— когда анимация полностью завершена (или отменена).
- Не путай с
transitionend
(для CSS-переходов). - Если анимация прервана (например, удалён класс),
animationend
не сработает.
- Каскадные анимации — когда завершение одной запускает другую.
- Скрытие элемента только после окончания анимации.
- Счётчик повторов анимации через
animationiteration
.
Совет для дизайнера
Если анимация критична для UX, укажи:
«Элемент должен стать кликабельным только после animationend
».
5.2. fullscreenchange
— вход/выход в полноэкранный режим
Типичный пример
Видеоплеер с кнопкой полноэкранного режима.
- При любом изменении состояния: как при входе в fullscreen, так и при выходе.
- Работает для видео, карт, игр и даже отдельных div-блоков.
- Презентации с полноэкранными слайдами.
- Фотогалереи без интерфейса в fullscreen.
- Скрытие панели инструментов при максимальном размере.
Совет для дизайнера
Всегда предусматривай кнопку выхода:
«При fullscreenchange
показывать overlay с крестиком в углу».
5.3. beforeunload
— «Точно хотите уйти?»
Типичный пример
Предупреждение при попытке закрыть страницу с несохранёнными данными.
- При закрытии вкладки, переходе по ссылке или обновлении страницы.
- Можно кастомизировать стандартное браузерное сообщение.
- Современные браузеры показывают только дефолтный текст (нельзя вставить свою верстку).
- Не работает в мобильных браузерах.
Совет для дизайнера
Не злоупотребляй этим событием:
«Использовать beforeunload
только для критичных данных (например, незавершённый заказ)».
5.4. error
— когда что-то пошло не так
Типичный пример
Запасное изображение, если основное не загрузилось.
- Для
<img>
— при ошибке загрузки (неверный URL, 404). - Для
<script>
— если скрипт не удалось выполнить. - Для
window
— при необработанных ошибках JavaScript.
- Кастомные прелоадеры для видео (
<video onerror=...>
). - Аналитика ошибок через отправку данных на сервер.
- Резервный шрифт при проблемах с загрузкой основного.
Совет для дизайнера
Продумай fallback-состояния:
«Для всех изображений добавить error
с заменой на placeholder».
Итог для дизайнера
- Анимации →
animationstart
/animationend
. - Fullscreen →
fullscreenchange
(но тестируй на iOS). - Предупреждения при уходе →
beforeunload
(экономно!). - Обработка ошибок →
error
+ fallback-дизайн.
Ошибка, которую можно избежать:
Не назначать beforeunload
для тривиальных действий (например, «Точно хотите уйти?») — это раздражает пользователей.