- PVSM.RU - https://www.pvsm.ru -
Решил я тут недавно на одном из своих сайтов сделать легкий редизайн. И дошло дело до фона. Показался он мне каким-то скучным. Захотелось его немного «оживить». Подобрал подходящую картинку небольшого размера, загнал ее в свойство фона:
body{
background: url("../images/bg.jpg") no-repeat center center / cover fixed;
}
и довольный нажал F5. Красота, да и только!
Начал скроллить страничку вниз и чувствую, что-то не то…
Такое чувство, как будто я играю в Crysis на очень старом компьютере. Почему же на сайте начались «тормоза» и прокрутка проходит рывками?
Я начал свое расследование…
Сначала я погрешил на свойство cover
, но дело оказалось не в нем. Отключив фиксированное положение фона (убрав fixed), мой «Crysis» выдал мне больше 30 FPS! «Во дела...», подумал я. Как же так? Почему? Почему я не замечал этого раньше? Возможно, это не очень заметно на легковесных сайтах, где не так много html элементов.
А дело оказалось вот в чем. Использование background-attachment : fixed
каждый раз при прокрутке вызывает операцию перерисовки. Страница должна переместить свое содержимое. И когда дело доходит до фиксированного фона, браузер должен заново прорисовать картинку в новом месте, относительно существующих DOM-элементов.
Чтобы решить эту проблему, нашему фоновому изображению нужен свой элемент, чтобы оно могло двигаться независимо от других. А также нам понадобится CSS3-свойство will-change
. О нем речь пойдет ниже.
Как только мы решим проблему с прорисовкой, скроллинг уже не будет проходить у нас рывками. Так как фон будет лежать на своем собственном слое, больше не потребуется перерисовывать страницу каждый раз при прокрутке.
Давайте я покажу все на примере.
Это наш изначальный код (я развернул свойства для наглядности):
body{
background: url("../images/bg.jpg") no-repeat center center;
background-attachment: fixed;
background-size: cover;
}
А вот, что нам необходимо сделать для решения проблемы:
body{
position: relative;
}
body::before {
background: url("../images/bg.jpg") no-repeat center center;
background-size: cover;
content: ' ';
height: 100%;
left: 0;
position: fixed;
top: 0;
width: 100%;
will-change: transform;
z-index: -1;
}
Мы добавили position: relative
для элемента body
, чтобы затем спозиционировать псевдо-элемент, который будет отдельным слоем для нашего фона. Остальные свойства, касательно фона, мы перенесли в ::before
. У псевдо-элемента мы теперь используем position : fixed
, вместо прежнего background-attachment: fixed
у body
. Ну и самое важное, без чего вся затея потерпит крах, — это свойство will-change [1].
Свойство will-change
предписывает браузеру отображать элемент, независимо от окружающих его других элементов. Оно как бы говорит браузеру: «Эй, друг, этот элемент изменится когда-нибудь потом, в будущем, так что прорисуй его только один раз на его собственном слое. И не нужно учитывать остальные элементы — он сам по себе».
Такие вот дела.
Данный билд я протестировал в разных браузерах, и вот небольшое резюме:
В Safari, к сожалению, проверить нет возможности. Но, по идее, все должно работать без проблем. Буду признателен, если кто-то протестирует и напишет результат в комментариях.
Автор: Tomio
Источник [2]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/css3/118673
Ссылки в тексте:
[1] will-change: https://www.w3.org/TR/css-will-change-1/
[2] Источник: https://habrahabr.ru/post/282079/
Нажмите здесь для печати.