Смена свойств css при клике

Обработка событий CSS-переходов в JavaScript

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

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

Для задания CSS-перехода используются следующие свойства :

  • transition-property – для указания CSS-свойства, которое нужно анимировать;
  • transition-duration – длительность перехода;
  • transition-timing-function – задает как должна изменяться скорость во время CSS-перехода;
  • transition-delay – время задержки перед началом перехода.

Например, мы хотим, чтобы изменения цвета фона ( background-color ) происходило плавно в течение 1 секунды. При этом нам нужно, чтобы этот процесс начинался не сразу, а через 0,1 секунды после создания CSS-перехода. Кроме этого, необходимо чтобы переход начинался и заканчивался медленно, или другими словами, чтобы анимация выполнялась посредством функции ease-in-out :

  
Lorem

В CSS также можно записать все эти свойства кратко, используя transition :

.box { background-color: #fffde7; transition: background-color 1s ease-in-out 0.1s; }

При CSS-переходах могут возникать следующие события в DOM:

  • transitionrun – при создании CSS-перехода, то есть до того, как он реально начался;
  • transitionstart – когда CSS-переход фактически начался;
  • transitionend – при завершении выполнения перехода;
  • transitioncancel – при отмене CSS-перехода.
Читайте также:  Javascript class method arguments

Событие transitionrun возникает при создании CSS-перехода, то есть перед transition-delay . В то время transitionstart возникает, когда CSS-переход уже начался, то есть сразу после окончания transition-delay .

Событие transitionend возникает после завершения CSS-перехода. Если CSS-переход удаляется до завершения, то событие transitionend сгенерировано не будет. Например, если мы во время перехода удалили свойство transition или установили для элемента свойство display со значением none .

При удалении анимации до её завершения генерируется другое событие, а именно transitioncancel .

Добавление обработчиков к этим событиям осуществляется как обычно:

el.addEventListener('transitionend', () => { // действия, которые нужно выполнить при возникновении события transitionend на элементе el });

Здесь мы добавили обработчик события transitionend с помощью метода addEventListener .

Пример 1. Плавное изменение цвета фона элемента

В этом примере создадим HTML-элемент .box . При нажатии на который мы будем с помощью JavaScript менять цвет его фона на случайный. Но изменение цвета будем производить не мгновенно, а плавно с помощью CSS-перехода:

Обработка событий, возникающих при CSS-переходах в JavaScript

Стили, с помощью которых мы зададим для .box определенные размеры, цвет фона, CSS-переход, а также некоторые другие вещи:

.box { display: flex; justify-content: center; align-items: center; width: 100px; height: 100px; margin: 20px; color: black; font-size: 18px; font-family: monospace; background-color: #f2c2b4; cursor: pointer; transition: background-color 0.5s ease-in-out 0.1s; }

Код JavaScript, написанный с использованием ES6 классов:

class ColorBox { #el; #isTransition = false; constructor(selector) { this.#el = document.querySelector(selector); this.#addEventListeners(); } #addEventListeners() { this.#el.addEventListener('click', (e) => { if (this.#isTransition) { console.log('CSS-переход ещë не закончился', new Date().toLocaleTimeString()); return; } this.#isTransition = true; const hex = `#${Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0')}`; e.target.style.backgroundColor = hex; const [r, g, b] = e.target.style.backgroundColor.replace(/[^\d,]/g, '').split(','); const brightness = Math.floor((r * 299 + g * 587 + b * 114) / 1000); e.target.style.color = brightness < 128 ? 'white' : 'black'; e.target.textContent = hex; }); this.#el.addEventListener('transitionrun', () =>{ console.log('CSS-переход создан', new Date().toLocaleTimeString()); }); this.#el.addEventListener('transitionstart', () => { console.log('CSS-переход начался', new Date().toLocaleTimeString()); }); this.#el.addEventListener('transitionend', () => { this.#isTransition = false; console.log('CSS-переход закончился', new Date().toLocaleTimeString()); }); } } const colorBox = new ColorBox('.box');

В коде мы обрабатываем следующие события, возникающие на элементе .box :

  • click – при клике;
  • transitionrun – при создании CSS-перехода;
  • transitionstart – при начале CSS-перехода;
  • transitionend – при окончании CSS-перехода.

При клике мы проверяем, выполняется ли CSS-переход, то есть истинно ли значение свойства this.#isTransition . Если так, то выводим сообщение в консоль и прекращаем дальнейшее выполнение функции. В противном случае мы устанавливаем приватному свойству this.#isTransition значение true .

Далее мы генерируем случайный цвет и сохраняем его в переменную hex . После этого присваиваем CSS-свойству background-color значение hex . Затем мы объявляем переменные r , g и b и сохраняем в них компоненты соответственно красного, зеленого и синего цветов. Они нам понадобятся для определения яркости цвета и установки в зависимости от этого для текста черного или белого цвета. В конце с помощью textContent мы выведем текст цвета в формате HEX в качестве содержимого .box .

В обработчиках событий transitionrun , transitionstart и transitionend мы будем просто выводить соответствующее сообщение в консоль. Кроме этого в transitionend будем ещё дополнительно устанавливать приватному свойству this.#isTransition значение false , которое будет говорить о том, что CSS-переход завершился. И можно создавать новый при клике на .box .

Пример 2. Плавное перемещение элемента

В этом примере напишем код для плавного перемещения элемента с использованием translateX и transition :

Пример обработки событий CSS-переходов transitionrun, transitionstart, transitionend и transitioncancel в JavaScript

Для этого нам понадобится вот такой HTML-код:

Здесь .box-wrapper – это контейнер внутри которого мы будем плавно двигать элемент .box с помощью transform: translateX(300px) в течение 3 секунд. Запускать это действие будем при клике по кнопке «start», а в JavaScript в обработчике этого события будем добавлять к .box класс translating . Прервать анимацию, можно будет при клике по кнопке «stop».

В элемент .logs мы будем помещать события, связанные с CSS-переходом в порядке их возникновения.

Для оформления, а также для установки transform и transition напишем следующий CSS-код:

.container { width: 400px; margin-right: auto; margin-bottom: 1rem; margin-left: auto; } .box-wrapper { background-color: #dcedc8; } .box { width: 100px; height: 100px; background-color: #8bc34a; } .translating { transform: translateX(300px); transition: transform 3s ease-in-out 0.5s; } .controls { margin-bottom: 1rem; text-align: center; } .logs { min-height: 100px; padding: 20px 15px; font-size: 14px; font-family: monospace; background-color: #fff9c4; }
const elBox = document.querySelector('.box'); const elLogs = document.querySelector('.logs'); const btnStart = document.querySelector('.start'); const btnStop = document.querySelector('.stop'); btnStart.onclick = () => elBox.classList.add('translating'); btnStop.onclick = () => elBox.classList.remove('translating'); elBox.addEventListener('transitionrun', (e) => { btnStart.disabled = true; const now = new Date().toLocaleTimeString(); const html = `
> ${e.type} ${e.propertyName} ${now}
`; elLogs.innerHTML = html; }); elBox.addEventListener('transitionstart', (e) => { btnStop.disabled = false; const now = new Date().toLocaleTimeString(); const html = `
> ${e.type} ${e.propertyName} ${now}
`; elLogs.insertAdjacentHTML('beforeend', html); }); elBox.addEventListener('transitionend', (e) => { btnStart.disabled = false; btnStop.disabled = true; const now = new Date().toLocaleTimeString(); const elapsedTime = Math.round(e.elapsedTime * 100) / 100; const html = `
> ${e.type} ${e.propertyName} ${elapsedTime}s ${now}
`; elLogs.insertAdjacentHTML('beforeend', html); }); elBox.addEventListener('transitioncancel', (e) => { btnStart.disabled = false; btnStop.disabled = true; const now = new Date().toLocaleTimeString(); const elapsedTime = Math.round(e.elapsedTime * 100) / 100; const html = `
> ${e.type} ${e.propertyName} ${elapsedTime}s ${now}
`; elLogs.insertAdjacentHTML('beforeend', html); });

Что делает этот код? При клике по кнопке .start мы будем добавлять к элементу .box класс translating и тем самым создавать CSS-переход. При клике по .stop убираем у элемента .box класс translating и тем самым удаляем CSS-переход.

Остальные обработчики событий просто выводят сообщения в элемент .logs со следующей информацией:

  • type – тип события;
  • propertyName – имя CSS-свойства для перехода;
  • elapsedTime – количество времени в секундах, в течение которого выполнялся переход.

Пример 3. Слайдер с плавными переходами

В этом примере мы создадим простой слайдер с зацикливанием или иными словами с бесконечной прокруткой.

Пример создания простого слайдера на JavaScript с использованием CSS-переходов, transition, и событий transitionrun и transitionend

Начнём с написания HTML-кода:

Здесь .slider-item – это слайд. В этом слайдере их 4. Для смены слайдов будем использовать кнопки .slider-prev и .slider-next .

Для размещения элементов в слайдере будем использовать технологию CSS Flexbox. В качестве ширины установим .slider-item значение 200px :

.slider-wrapper { width: 200px; overflow-x: hidden; } .slider { display: flex; } .slider-item { flex: 0 0 200px; height: 150px; color: #fff; display: flex; align-items: center; justify-content: center; font-size: 2rem; }

Смещать плавно слайды будем с помощью CSS-функции translateX и transition . Здесь мы будем их устанавливать посредством JavaScript:

class Slider { constructor(selector) { this.slider = document.querySelector(selector); this.elFirst = this.slider.firstElementChild; this.elLast = this.slider.lastElementChild; this.btnPrev = document.querySelector('.slider-prev'); this.btnNext = document.querySelector('.slider-next'); this.direction = 'next'; this.width = this.slider.parentElement.getBoundingClientRect().width; this.count = this.slider.querySelectorAll('.slider-item').length; this.step = this.width * this.count; this.elLast.style.transform = `translateX(${-this.step}px)`; this.orders = [. this.slider.children].map((value, index) => index); this.orders = [. this.orders.slice(-1), . this.orders.slice(0, -1)]; this.addEventListener(); } move() { let value = new WebKitCSSMatrix(this.slider.style.transform).m41; value += this.direction === 'next' ? -this.width : this.width; this.slider.style.transform = `translateX(${value}px)`; this.slider.style.transition = 'transform 1s ease'; const el = this.slider.querySelector('.slider-item-active'); let elNew = this.direction === 'next' ? el.nextElementSibling : el.previousElementSibling; if (!elNew) { elNew = this.direction === 'next' ? this.elFirst : this.elLast; } el.classList.remove('slider-item-active'); elNew.classList.add('slider-item-active'); } addEventListener() { this.btnPrev.onclick = () => { this.direction = 'prev'; this.move(); } this.btnNext.onclick = () => { this.direction = 'next'; this.move(); } this.slider.ontransitionrun = () => { this.btnPrev.disabled = true; this.btnNext.disabled = true; const index = this.direction === 'next' ? this.orders[0] : this.orders[this.orders.length - 1]; const el = this.slider.querySelector(`.slider-item:nth-child(${index + 1})`); let value = new WebKitCSSMatrix(el.style.transform).m41; value += this.direction === 'next' ? this.step : -this.step; el.style.transform = `translateX(${value}px)`; if (this.direction === 'prev') { this.orders = [. this.orders.slice(-1), . this.orders.slice(0, -1)]; } else { this.orders = [. this.orders.slice(1), . this.orders.slice(0, 1)]; } } this.slider.ontransitionend = () => { this.btnPrev.disabled = false; this.btnNext.disabled = false; } } } const slider = new Slider('.slider');

Из интересного здесь то, что порядок следования элементов мы пишем в массив this.orders : [3, 0, 1, 2] . Который затем используем для того, чтобы организовать бесконечную прокрутку слайдера. При движении вправо, нам нужно крайний элемент слева переместить после последнего. А при движении влево, наоборот, крайний элемент справа переместить перед первым.

С помощью this.orders получить такие элементы очень легко:

  • this.orders[0] – крайний элемент слева;
  • this.orders[this.orders.length — 1] – крайний элемент справа.

Перемещение крайнего элемента для зацикливания мы делаем при создании CSS-перехода, то есть в обработчике события ontransitionrun . Здесь мы также переводим кнопки в неактивное состояние:

this.btnPrev.disabled = true; this.btnNext.disabled = true;

После завершения CSS-перехода делаем их опять активными:

this.slider.ontransitionend = () => { this.btnPrev.disabled = false; this.btnNext.disabled = false; }

Источник

Оцените статью