📜 ⬆️ ⬇️

Low FPS while scrolling the page. Problem solving background-attachment: fixed

I recently decided to make an easy redesign on one of my sites. And it came to the background. He seemed to me somehow boring. I wanted to “revive” him a little. Picked up a suitable image of a small size, drove it into the background property:

body{ background: url("../images/bg.jpg") no-repeat center center / cover fixed; } 


and pleased pressed F5. Beauty, and only!
')
I started scrolling down the page and I feel that something is not right ...


It feels like I'm playing Crysis on a very old computer. Why did the brakes start on the site and the scrolling is jerky?

I began my investigation ...


At first, I sinned on the cover property, but the point was not in it. Turning off the fixed background position (removing the fixed one), my Crysis gave me more than 30 FPS ! "In business ...", I thought. How so? Why? Why did I not notice this before? Perhaps this is not very noticeable on lightweight sites where there are not so many html elements.

And the thing turned out to be this. Using background-attachment : fixed each time it scrolls it causes a redraw operation. The page must move its content. And when it comes to a fixed background, the browser must re-draw the image in a new location, relative to existing DOM elements.

To solve this problem, our background image needs its own element so that it can move independently of others. And also we need the CSS3 will-change property. About him will be discussed below.

As soon as we solve the problem with drawing, scrolling will no longer be jerky here. Since the background will be on its own layer, you no longer need to redraw the page every time you scroll.

Let me show you with an example.

This is our original code (I have expanded the properties for clarity):

 body{ background: url("../images/bg.jpg") no-repeat center center; background-attachment: fixed; background-size: cover; } 


And here is what we need to do to solve the problem:

 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; } 


We added position: relative to the body element to then position the pseudo-element, which will be a separate layer for our background. The rest of the properties regarding the background, we moved to ::before . In the pseudo-element, we now use position : fixed , instead of the previous background-attachment: fixed in body . And most importantly, without which the whole undertaking will fail, this property will-change .

The will-change property instructs the browser to display an element, regardless of other elements surrounding it. It seems to be saying to the browser: “Hey, friend, this element will change sometime later, in the future, so draw it only once on its own layer. And do not take into account the other elements - it is in itself. "

Such are the cases.

I tested this build in different browsers, and here is a small summary:

  1. Google Chrome. Everything is OK, it works like a clock.
  2. Mozilla Firefox. Everything is OK, it works like a clock.
  3. Opera. Everything is OK, it works like a clock.
  4. Safari. Everything is OK, it works like a clock. Thanks for checking smssystem
  5. Microsoft Edge. The method works, but there is one cant. If you turn the wheel, then the top and bottom of the page twitches, but then they return to normal. If you twist using scrollbar, then everything is OK.
  6. Internet Explorer. Same problem as Edge.

Source: https://habr.com/ru/post/282079/


All Articles