От автора: как анимировать CSS свойство box-shadow таким образом, чтобы объект на каждом кадре не отрисовывался заново, а также без потери в производительности страницы? Если коротко, то никак. Анимация свойства box-shadow сильно влияет на производительность.
Тем не менее, есть более простой способ имитировать этот эффект с минимальной перерисовкой объекта и с 60FPS: анимация свойства opacity на псевдоклассе.
Демо
Посмотрите на демо и сравните две разных техники, которые мы сегодня разберем. Если вы не видите разницы, то мы добились того, чего хотели. Разница только в том, как мы назначаем и анимируем тень объекта. Слева мы анимируем свойство box-shadow по событию hover, а справа мы добавляем псевдокласс, к нему добавляем тень, а затем анимируем свойство opacity данного элемента.
Если вы воспользуетесь панелью разработчика и наведете курсор мыши на одно из двух демо, то вы увидите что-то похожее на (зеленые столбцы это перерисовка, чем меньше, тем лучше):
Четко видно, что по сравнению с карточкой справа (анимация свойства opacity псевдокласса) перерисовок больше при наведении на карточку слева (анимация свойства box-shadow).
Почему же мы наблюдаем такой эффект? В CSS есть несколько свойств, которые можно анимировать без вызова постоянной перерисовки объекта на каждом кадре, и это opacity и transform. Изменяя только эти два свойства во время анимации, мы минимизируем количество перерисовок объекта (тем самым уменьшаем работу браузеру). Разница между подходами существенна, напишем стили:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
/* Медленный способ */ .make-it-slow { box-shadow: 0 1px 2px rgba(0,0,0,0.15); transition: box-shadow 0.3s ease-in-out: } /* Большая тень при наведении мыши */ .make-it-slow:hover { box-shadow: 0 5px 15px 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 5px 15px rgba(0,0,0,0.3); opacity: 0; transition: opacity 0.3s ease-in-out: } /* Плавно показываем тень при наведении */ .make-it-fast:hover::after { opacity: 1; } |
В примере с большей производительностью два слоя: один для блока, другой для тени. Анимации подвергается только слой для тени и конкретно свойство opacity.
Принцип работы
Давайте разберем, как создать 3D эффект для карточки из демо выше. Первый шаг это задать тень псевдоклассу, как мы делали выше. Также добавим весь необходимый для создания карточки код:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
/* Из HTML потребуется только <div class="box"></div> */ /* Создаем простой белый квадрат и добавляем ему тень по умолчанию */ .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.3s ease-in-out; } /* Создаем скрытый псевдокласс */ /* Добавляем конечное состояние тени */ .box::after { content: ''; position: absolute; z-index: -1; width: 100%; height: 100%; opacity: 0; border-radius: 5px; box-shadow: 0 5px 15px rgba(0,0,0,0.3); transition: opacity 0.3s ease-in-out; } |
Заметьте, что мы добавили свойство transition как к .box, так и к .box::after, потому что мы будем анимировать оба элемента: transform для .box и opacity для .box::after. У нас получился белый квадрат с тоненькой тенью box-shadow. Более четкая тень элемента .box::after полностью скрыта, с квадратом нельзя никак взаимодействовать.
Для создания эффекта, как в демо, нам всего лишь требуется увеличивать .box при наведении мыши и плавно показывать псевдокласс с его тенью:
1 2 3 4 5 6 7 8 9 |
/* Увеличиваем квадрат */ .box:hover { transform: scale(1.2, 1.2); } /* Плавно показываем псевдокласс с большой тенью */ .box:hover::after { opacity: 1; } |
Вот и все! Наведите курсор мыши, чтобы увидеть эффект. В итоге мы получаем вот такой CSS код с добавлением всех вендорных префиксов и парочки пользовательских функций анимации:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
.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.6s cubic-bezier(0.165, 0.84, 0.44, 1); transition: all 0.6s 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 5px 15px rgba(0, 0, 0, 0.3); opacity: 0; -webkit-transition: all 0.6s cubic-bezier(0.165, 0.84, 0.44, 1); transition: all 0.6s 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, и вы получите максимально возможную производительность, а значит, и самый лучший пользовательский опыт.
Автор: Tobias
Источник: //tobiasahlin.com/
Редакция: Команда webformyself.