Властивість box-shadow в css: як анімувати без втрати продуктивності

2

Від автора: як анімувати CSS властивість box-shadow таким чином, щоб об’єкт на кожному кадрі не отрисовывался заново, а також без втрати продуктивності сторінки? Якщо коротко, то ніяк. Анімація властивості box-shadow сильно впливає на продуктивність.

Тим не менш, є більш простий спосіб імітувати цей ефект з мінімальною перемальовуванням об’єкта і з 60FPS: анімація властивості opacity на псевдоклассе.

Демо

Властивість box-shadow в css: як анімувати без втрати продуктивності

Подивіться на демо і порівняйте дві різні техніки, які ми сьогодні розглянемо. Якщо ви не бачите різниці, то ми домоглися того, чого хотіли. Різниця тільки в тому, як ми призначаємо і анимируем тінь об’єкта. Зліва ми анимируем властивість box-shadow події hover, а праворуч ми додаємо псевдоклас, до нього додаємо тінь, а потім анимируем властивість opacity даного елемента.

Якщо ви скористаєтеся панеллю розробника і наведете вказівник миші на одну з двох демо, то ви побачите щось схоже на (зелені стовпчики це оновлення, чим менше, тим краще):

Властивість box-shadow в css: як анімувати без втрати продуктивності

Чітко видно, що порівняно з карткою праворуч (анімація властивості opacity псевдокласу) перерисовок більше при наведенні на картку зліва (анімація властивості box-shadow).

Чому ж ми спостерігаємо такий ефект? В CSS є декілька властивостей, які можна анімувати без виклику постійної перемальовування об’єкта на кожному кадрі, і це opacity і transform. Змінюючи тільки ці дві властивості під час анімації, ми мінімізуємо кількість перерисовок об’єкта (тим самим зменшуємо роботу браузеру). Різниця між підходами істотна, напишемо стилі:

/* Повільний спосіб */
.make-it-slow {
box-shadow: 0 1px 2px rgba(0,0,0,0.15);
transition: box-shadow 0.3 s ease-in-out:
}
/* Велика тінь при наведенні миші */
.make-it-slow:hover {
box-shadow: 0 15px 5px rgba(0,0,0,0.3);
}
/* Швидкий спосіб */
.make-it-fast {
box-shadow: 0 1px 2px rgba(0,0,0,0.15);
}
/* Промальовуємо велику тінь, але не показуємо */
.make-it-fast::after {
box-shadow: 0 15px 5px rgba(0,0,0,0.3);
opacity: 0;
transition: opacity 0.3 s ease-in-out:
}
/* Плавно показуємо тінь при наведенні */
.make-it-fast:hover::after {
opacity: 1;
}

У прикладі з більшою продуктивністю два шари: один для блоку, інший для тіні. Анімації піддається тільки шар для тіні і конкретно властивість opacity.

Принцип роботи

Давайте розберемо, як створити 3D ефект для картки з демо вище. Перший крок це задати тінь псевдоклассу, як ми робили вище. Також додамо весь необхідний для створення картки код:

/* З HTML потрібно тільки

*/
/* Створюємо простий білий квадрат і додаємо йому тінь за замовчуванням */
.box {
position: relative;
display: inline-block;
width: 100px;
height: 100px;
border-radius: 5px;
background-color: #fff;
box-shadow: 0 1px 2px rgba(0,0,0,0.15);
transition: all 0.3 s ease-in-out;
}
/* Створюємо прихований псевдоклас */
/* Додаємо кінцевий стан тіні */
.box::after {
content: «;
position: absolute;
z-index: -1;
width: 100%;
height: 100%;
opacity: 0;
border-radius: 5px;
box-shadow: 0 15px 5px rgba(0,0,0,0.3);
transition: opacity 0.3 s ease-in-out;
}

Зауважте, що ми додали властивість transition як до .box, так і до .box::after, тому що ми будемо анімувати обидва елементи: transform .box і opacity .box::after. У нас вийшов білий квадрат з тоненькою тінню box-shadow. Більш чітка тінь елемента .box::after повністю прихована, з квадратом ніяк не можна взаємодіяти.

Для створення ефекту, як у демо, нам лише потрібно збільшувати .box при наведенні миші і плавно показувати псевдоклас з його тінню:

/* Збільшуємо квадрат */
.box:hover {
transform: scale(1.2, 1.2);
}
/* Плавно показуємо псевдоклас з великою тінню */
.box:hover::after {
opacity: 1;
}

От і все! Наведіть курсор миші, щоб побачити ефект. В результаті ми отримуємо ось такий CSS код з додаванням всіх вендорних префіксів і парочки користувальницьких функцій анімації:

.box {
position: relative;
display: inline-block;
width: 100px;
height: 100px;
background-color: #fff;
border-radius: 5px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
border-radius: 5px;
-webkit-transition: all 0.6 s cubic-bezier(0.165, 0.84, 0.44, 1);
transition: all 0.6 s cubic-bezier(0.165, 0.84, 0.44, 1);
}
.box::after {
content: «»;
border-radius: 5px;
position: absolute;
z-index: -1;
top: 0;
left: 0;
width: 100%;
height: 100%;
box-shadow: 0 15px 5px rgba(0, 0, 0, 0.3);
opacity: 0;
-webkit-transition: all 0.6 s cubic-bezier(0.165, 0.84, 0.44, 1);
transition: all 0.6 s cubic-bezier(0.165, 0.84, 0.44, 1);
}
.box:hover {
-webkit-transform: scale(1.25, 1.25);
transform: scale(1.25, 1.25);
}
.box:hover::after {
opacity: 1;
}

Коду набагато більше, ніж якщо просто анімувати властивість box-shadow. Так навіщо ж так хвилюватися? Навіть якщо ваш комп’ютер обробляє анімацію властивості box-shadow без видимих труднощів, не факт, що ваш телефон впорається. Навіть комп’ютери почнуть пригальмовувати при обробці більш складної анімації.

Використовуйте властивість transition тільки з властивостями transform і opacity, і ви отримаєте максимально можливу продуктивність, а значить, і самий кращий користувальницький досвід.