Содержание
CSS-анимации и hover-эффекты делают плакат живым, но их возможности ограничены: движение либо бесконечное, либо привязано к наведению курсора. JavaScript снимает эти ограничения. С ним плакат может реагировать на клик, отслеживать движение мыши, менять содержимое, запускать события по таймеру и хранить состояние между действиями зрителя. В этой статье разберём базовые инструменты, от которых отталкивается вся интерактивность в веб-плакате.
Найти и подключить
Вся работа с JavaScript в браузере строится на двух действиях: найти HTML-элемент и повесить на него обработчик события. Для этого существуют два метода, которые вы будете использовать в каждом проекте.
querySelector находит элемент на странице по CSS-селектору. Точно так же, как вы выбираете элемент в CSS через .class или #id, вы передаёте тот же селектор в querySelector, и JavaScript возвращает вам этот элемент.
addEventListener привязывает к элементу функцию, которая выполнится при наступлении события. Событие — это что-то, что происходит: клик, наведение, нажатие клавиши, скролл.
<button class="demo-btn">Нажми на меня</button>
.demo-btn {
padding: 16px 32px;
background: #fe3904;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
}
.demo-btn.clicked {
background: #9eff70;
color: black;
}
const btn = document.querySelector('.demo-btn')
btn.addEventListener('click', () > {
btn.classList.toggle('clicked')
})
/* querySelector — находит элемент по CSS-селектору.
addEventListener — вешает обработчик на событие.
Это два метода, которые вы будете
использовать в каждом проекте. */
Две строки: найти кнопку, повесить обработчик на клик. Внутри обработчика classList.toggle, который переключает CSS-класс. Визуальная работа остаётся на стороне CSS, JavaScript только управляет, когда класс включить и выключить.
Управление классами
Самый чистый способ менять внешний вид элемента из JavaScript — переключать CSS-классы. Вы описываете все визуальные состояния в CSS, а JavaScript решает, какой класс когда активен.
<div class="target"></div>
<button data-action="red">цвет</button>
<button data-action="round">форма</button>
<button data-action="big">размер</button>
<button data-action="reset">сброс</button>
.target { transition: all 0.3s ease; }
.target.red { background: #fe3904; }
.target.round { border-radius: 50%; }
.target.big { transform: scale(1.4); }
const target = document.querySelector('.target')
document.querySelectorAll('.ctrl-btn').forEach(btn > {
btn.addEventListener('click', () => {
const action = btn.dataset.action
if (action === 'reset') {
target.className = 'target'
} else {
target.classList.toggle(action)
}
})
})
/* classList.add('x') — добавить класс.
classList.remove('x') — убрать.
classList.toggle('x') — переключить.
className = 'target' — сбросить все
классы до одного базового. */
Три кнопки добавляют элементу разные классы: red, round, big. Каждый клик переключает свой класс через toggle. Кнопка «сброс» обнуляет все классы через className = 'target'. Классы комбинируются: можно одновременно включить цвет, форму и размер.
CSS — это предпочтительный подход для большинства задач. Вы держите визуальную логику в CSS (переходы, анимации, цвета), а JavaScript отвечает только за переключение состояний. Код остаётся чистым, а визуальные изменения легко корректировать без правки JS.
Прямая запись свойств
Иногда CSS-классов недостаточно, потому что значение нужно вычислить динамически — случайный цвет, угол поворота, координата клика. В таких случаях свойства записываются напрямую через element.style.
<div class="style-box"></div>
<div class="style-box"></div>
<div class="style-box"></div>
const colors = ['#fe3904','#9eff70','#82e1f1','#febbed','#3898e2']
document.querySelectorAll('.style-box').forEach(box > {
box.addEventListener('click', () > {
const randomColor = colors[Math.floor(Math.random() * colors.length)]
box.style.backgroundColor = randomColor
box.style.borderRadius = Math.random() >0.5 ? '50%' : '8px'
box.style.transform = `rotate(${Math.random() * 30 - 15}deg)`
})
})
/* element.style.property — запись
CSS-свойства напрямую из JS.
Используйте camelCase:
background-color → backgroundColor.
classList + CSS — чище.
style — гибче (динамические значения). */
Каждый клик задаёт квадрату случайный цвет, случайную форму (круг или прямоугольник) и случайный поворот. Эти значения невозможно заранее описать в CSS, потому что они генерируются на лету.
Обратите внимание на запись свойств: в CSS это background-color, а в JavaScript — backgroundColor (camelCase). Дефис в JavaScript — это оператор вычитания, поэтому все составные CSS-свойства записываются слитно с заглавной буквой.
Работа с группой элементов
querySelector находит один элемент — первый, который подходит под селектор. Если на странице пять карточек с классом .card, он вернёт только первую. Для работы с группой существует querySelectorAll, который возвращает все подходящие элементы. Дальше forEach обходит каждый и вешает обработчик.
<div class="card">♠</div>
<div class="card">♥</div>
<div class="card">♦</div>
<div class="card">♣</div>
<div class="card">★</div>
.card {
transition: all 0.3s ease;
cursor: pointer;
}
.card.flipped {
background: #fe3904;
color: white;
transform: rotateY(180deg);
}
const cards = document.querySelectorAll('.card')
cards.forEach(card > {
card.addEventListener('click', () > {
card.classList.toggle('flipped')
})
})
/* querySelectorAll возвращает список
всех элементов с этим селектором.
forEach обходит каждый и вешает
обработчик. Без forEach обработчик
получил бы только первый элемент. */
Пять карточек с символами. Клик на любую переворачивает именно её, не затрагивая остальные. Без forEach обработчик получил бы только первая карточка, остальные четыре остались бы мёртвыми.
Несколько событий на одном элементе
На один элемент можно повесить сколько угодно обработчиков разных событий. Это позволяет создавать многоуровневую реакцию: одно поведение при наведении, другое при нажатии, третье при отпускании.
<div class="event-box">наведи, кликни или зажми</div>
<div class="event-label"></div>
const box = document.querySelector('.event-box')
const label = document.querySelector('.event-label')
box.addEventListener('mouseenter', () > {
box.style.background = '#82e1f1'
label.textContent = 'mouseenter'
})
box.addEventListener('mouseleave', () > {
box.style.background = '#f0f0f0'
label.textContent = 'mouseleave'
})
box.addEventListener('mousedown', () > {
box.style.background = '#fe3904'
box.style.color = 'white'
box.style.transform = 'scale(0.92)'
label.textContent = 'mousedown'
})
box.addEventListener('mouseup', () > {
box.style.transform = 'scale(1)'
label.textContent = 'mouseup'
})
/* Одному элементу — несколько обработчиков.
mouseenter/mouseleave — наведение.
mousedown/mouseup — нажатие/отпускание.
click — полный клик (down + up).
Полный список: MDN → Event reference. */
Квадрат реагирует на четыре события: mouseenter (курсор вошёл), mouseleave (курсор ушёл), mousedown (кнопка мыши нажата), mouseup (кнопка отпущена). Каждое событие меняет и внешний вид элемента, и текст подписи внизу. Попробуйте навести, нажать и отпустить — вы увидите, в каком порядке срабатывают события.
click,dblclick,mouseentermouseup,mousemove,wheelkeydown,keyup,touchstart
touchend, scroll, resize. Запоминать все не нужно. Когда вам понадобится конкретное событие, ищите «MDN Event reference» — это полный справочник, который покрывает всё.
Изменение текста
JavaScript может менять текст внутри элемента через свойство textContent. Это полезно для счётчиков, статусов, подписей и любого содержимого, которое зависит от действий зрителя.
<div class="display">0</div>
<button class="minus">−</button>
<button class="plus">+</button>
const display = document.querySelector('.display')
let count = 0
document.querySelector('.plus').addEventListener('click', () > {
count++
display.textContent = count
})
document.querySelector('.minus').addEventListener('click', () > {
count--
display.textContent = count
})
/* textContent заменяет текст элемента.
Переменная count хранит число
между кликами — это состояние.
Каждый клик обновляет и число,
и то, что видит зритель. */
Счётчик: кнопка «+» увеличивает число, кнопка «−» уменьшает. Переменная count хранит текущее значение между кликами — это состояние. Каждый клик обновляет и переменную, и то, что видит зритель на экране.
Условия if / else
Когда нужно выполнить разное действие в зависимости от текущего состояния, используется if / else. Это способ сказать: «Если условие выполняется — сделай одно, иначе — другое».
<div class="light"></div>
<div class="light-label">выкл</div>
const light = document.querySelector('.light')
const label = document.querySelector('.light-label')
let isOn = false
light.addEventListener('click', () > {
isOn = !isOn
if (isOn) {
light.classList.add('on')
label.textContent = 'вкл'
} else {
light.classList.remove('on')
label.textContent = 'выкл'
}
})
/* if (условие) { ... } else { ... }
Проверяет и выполняет один из двух блоков.
!isOn инвертирует: true → false, false → true.
Каждый клик переключает лампочку. */
Лампочка. Клик переключает переменную isOn между true и false. Если isOn — добавляем класс on и показываем текст «вкл». Иначе — убираем класс и показываем «выкл». Запись isOn = !isOn инвертирует значение: true становится false и наоборот.
Таймеры
Не всё должно происходить мгновенно. Иногда нужно отложить действие или выполнять его с регулярным интервалом. Для этого существуют два метода.
setTimeout — выполняет функцию один раз через заданное время. Тысяча миллисекунд — одна секунда.
setInterval — выполняет функцию многократно с заданным интервалом, пока не остановлен через clearInterval.
(delay 1s)
<div class="timer-delay">нажми (delay 1s)</div>
<div class="timer-interval"><div class="tick-count">0</div>тики</div>
/* setTimeout — выполнить один раз через N мс */
const delayCircle = document.querySelector('.timer-delay')
delayCircle.addEventListener('click', () > {
setTimeout(() > {
delayCircle.classList.toggle('fired')
}, 1000)
})
/* setInterval — выполнять каждые N мс */
const tickDisplay = document.querySelector('.tick-count')
const intervalCircle = document.querySelector('.timer-interval')
let ticks = 0
let intervalId = null
intervalCircle.addEventListener('click', () > {
if (intervalId) {
clearInterval(intervalId)
intervalId = null
} else {
intervalId = setInterval(() > {
ticks++
tickDisplay.textContent = ticks
}, 500)
}
})
/* clearInterval останавливает таймер.
Клик запускает/останавливает счётчик. */
Левый круг: клик запускает setTimeout с задержкой 1 секунда. Через секунду круг меняет цвет. Правый круг: клик запускает setInterval, который каждые 500 мс увеличивает счётчик. Повторный клик останавливает его через clearInterval.
Для веб-плаката setInterval полезен для циклических процессов, которые не получается реализовать через CSS-анимации: переключение текстового контента, обновление данных, последовательные действия по расписанию. Но если анимацию можно сделать на CSS — делайте на CSS. Он работает плавнее и не нагружает основной поток JavaScript.




