Я ДЕЙСТВИТЕЛЬНО хочу получить анимацию со скоростью 60 кадров в секунду. В частности, на моих элементах ввода в событии focus. Самый высокий (согласно инструментам разработчика Chrome) fps, которого я могу достичь, составляет около 18 кадров в секунду.

Я использую все, что считается лучшей практикой: window.requestAnimationFrame в моем JavaScript, will-change в моем css, и я использую преобразования для фактической анимации. Даже со всеми этими настройками моя анимация не приближается к 60 кадрам в секунду.

var form = {};

function addActive(element) {
	element.highlightElement.classList.add("input-highlight-active");
}

function removeActive(element) {
	element.highlightElement.classList.remove("input-highlight-active");
}
// loops through the entire object removing "active" class on all elements except fo rthe element that is the target.
function setNewState(element, id, obj) {
	for (var key in obj) {
		if (id === key) {
			window.requestAnimationFrame(() => addActive(element));
		} else {
			removeActive(obj[key]);
		}
	}
}

// Captures the event.target.id and corresponding object to be passed to setNewState function
function handleEvent(e) {
	var active = form[e.target.id];
	var activeId = e.target.id;
	setNewState(active, activeId, form);
}

// Adds focus event listener to html elements
function addEvent() {
	var inputElements = document.querySelectorAll('.input-wrapper > input');
  inputElements = Array.from(inputElements);
	inputElements.map(el => el.addEventListener('focus', (e) => handleEvent(e)));
	}
  
// Creates object using input id as object key
function init() {
	var temp = {};
	var inputElements = document.querySelectorAll('.input-wrapper > input');
	for (var i = 0; i < inputElements.length; i++) {
		temp[inputElements[i].id] = {
			highlightElement: inputElements[i].nextElementSibling,
			active: false
		};
	}
	return temp;
}

form = init();
addEvent();
body {
  background-color: #121217;
}
.input-wrapper {
    position: relative;
    width: 60%;
    margin: 0px auto 40px;
    text-align: left;
}
.input-label {
    position: relative;
    text-align: left;
    font-size: 18px;
    font-weight: 300;
    letter-spacing: 0.012em;
    color: #eee;
}
input {
    appearance: none;
    -webkit-appearance: none;
    position: relative;
    width: 100%;
    margin: 8px auto 0;
    letter-spacing: 0.012em;
    font-size: 18px;
    color: #fafafa;
    background-color: #121217;
    border: 0px;
    transform-origin: left;
    border-bottom: 1px solid #fafafa;
}
input:focus {
    outline: none;
}
.input-highlight {
    will-change: transform;
    position: absolute;
    top: 99%;
    width: 101%;
    height: 2px;
    background-color: #006daa;
    z-index: 1;
    transform-origin: left;
    transform: scaleX(0);
    transition: all 0.12s linear;
}
.input-highlight-active {
    will-change: transform;
    transform: scaleX(1);
    transition: all 0.12s linear;
}
<div class="input-wrapper">
  <div class="input-label">Full name</div>
  <input type="text" id="fullName">
  <div class="input-highlight"></div>
</div>

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

0
Daniel Maixner 22 Окт 2019 в 00:32
1
Пожалуйста, не публикуйте свой код на сторонних сайтах, так как эти ссылки могут со временем исчезнуть, и ваш вопрос станет бессмысленным для любого, кто на него наткнется. Всегда публикуйте свой код прямо здесь вместе со своим вопросом.
 – 
Scott Marcus
22 Окт 2019 в 00:38
1
Максимальное (согласно инструментам разработчика Chrome) количество кадров в секунду, которое я могу достичь, составляет около 18 кадров в секунду. <-- Так почему же вы думаете, что тогда вы можете выйти за рамки этого?
 – 
Scott Marcus
22 Окт 2019 в 00:40
Слишком много JavaScript, чтобы добавить класс, который действительно важен для производительности… jsfiddle.net/9pgb5mc2
 – 
Ry-
22 Окт 2019 в 00:44
Эта маленькая нижняя полоса немного толще, цвет скользит сбоку по всему эффекту, который вы пытаетесь достичь при фокусировке и т. Д.? Если это так, вы бы предпочли сократить все это пополам и вместо этого разместить все это в потоке композитора?
 – 
Chris W.
22 Окт 2019 в 00:52
Во всяком случае, я не могу воспроизвести это на довольно слабом компьютере (60 кадров в секунду). Какое устройство вы используете? А вы пробовали просто переход по ширине, без попыток оптимизации?
 – 
Ry-
22 Окт 2019 в 00:54

1 ответ

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

Поскольку вы воспользовались преимуществами CSS-анимации, вам нужно всего лишь добавить класс, который ОДИН РАЗ изменяет масштаб в фокусе, а затем вы можете удалить его при размытии:

.input-highlight-active {
    transform: scaleX(1);
}

Поскольку у входных данных уже есть класс, в котором значение transition указывает, что он будет анимировать все свойства (которые он может анимировать), вам нужно указать только анимируемое изменение свойства.

Демо

1
inorganik 23 Окт 2019 в 19:25
Спасибо за ответ! поэтому я удалил window.requestAnimationFrame(). Насколько я понял из вашего поста, использование will-change и transform обеспечит наилучшую производительность, когда у него есть такая возможность?
 – 
Daniel Maixner
22 Окт 2019 в 02:24
Я не уверен, что will-change необходим или даже рекомендуется. Но CSS-анимация, безусловно, обеспечивает наилучшую производительность.
 – 
inorganik
22 Окт 2019 в 18:11
requestAnimationFrame назначает функцию для вызова один раз. Много раз эта функция будет снова вызывать requestAnimationFrame, но здесь этого не происходит, поэтому класс не добавляется 60 раз в секунду.
 – 
Ry-
23 Окт 2019 в 18:37
@Ry- ты прав! Спасибо. Я исправил свой ответ.
 – 
inorganik
23 Окт 2019 в 19:26