Решил я тут недавно на одном из своих сайтов сделать легкий редизайн. И дошло дело до фона. Показался он мне каким-то скучным. Захотелось его немного «оживить». Подобрал подходящую картинку небольшого размера, загнал ее в свойство фона:
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.
Свойство will-change
предписывает браузеру отображать элемент, независимо от окружающих его других элементов. Оно как бы говорит браузеру: «Эй, друг, этот элемент изменится когда-нибудь потом, в будущем, так что прорисуй его только один раз на его собственном слое. И не нужно учитывать остальные элементы — он сам по себе».
Такие вот дела.
Данный билд я протестировал в разных браузерах, и вот небольшое резюме:
- Google Chrome. Все ОК, работает как часы.
- Mozilla Firefox. Все ОК, работает как часы.
- Opera. Все ОК, работает как часы.
- Microsoft Edge. Метод работает, но есть один косяк. Если крутить колесиком, то дергается верх и низ страницы, но потом приходят в норму. Если же крутить с помощью скроллбара, то все ОК.
- Internet Explorer. Та же проблема, что и у Edge.
В Safari, к сожалению, проверить нет возможности. Но, по идее, все должно работать без проблем. Буду признателен, если кто-то протестирует и напишет результат в комментариях.
ссылка на оригинал статьи https://habrahabr.ru/post/282079/
Добавить комментарий