WebGL Enhanced Drag Slider Tutorial With curtains.js — Part 3
Improve the overall performance of the slider by removing any layout repaint calls
In this final part, we’ll see how to improve the overall performance of the slider by removing any layout repaint calls.
Here’s the final pen:
As a reminder, we used curtains.js to add everything related to WebGL.
We can then see the advantages of using curtains.js:
- Clean and SEO-friendly HTML code.
- You don’t have to worry about your WebGL objects’ sizes and positions as most of the stuff (like resize) will be handled under the hood by the library.
- If, in any case, there’s an error during the WebGL initialization or in your shaders, the slider will still work!
Layout Repaint Calls / Reflow
First of all, you’ll need to understand what layout repaint and reflow are and what causes them. There’s a neat article written by Paul Irish, explaining it on GitHub.
element.getBoundingClientRect()), or every time you’re trying to access the window scroll value via
window.scrollY, the browser needs to redraw the whole web page to calculate those values.
This could lead to a performance bottleneck and could cause jank issues.
As a matter of fact, curtains.js does internally use
getBoundingClientRect each time you’re adding a plane, or each time you resize your window to copy the plane’s HTML size and position, and apply it to its associated WebGL plane object.
There’s no way to avoid that, but, fortunately, this does not happen often so it’s not really a big deal.
But, we used the
updatePosition method in our slider’s
onTranslation hook and this function also calls
getBoundingClientRect, therefore triggering a reflow call.
We’ll now see how to improve our slider to get rid of those layout repaint calculations.
Usually, when you’re using curtains.js, you’ll be using the
updatePosition inside a scroll event listener to update the positions of your planes according to the window scroll value.
Because there’s no way to get your scroll or HTML element’s position without triggering a reflow call, that’s still the best way to handle planes’ positions when using a native scroll.
But, if you are using a virtual scroll library, for example, you’ll have access to scroll values that get calculated without causing reflow calls and you’ll be able to update your planes’ positions accordingly, with our
Now, back to our slider. At any given time, we have access to its current translation (which gets calculated without triggering reflow) so why not use it to update our positions instead? That’s precisely what we are going to do.
The overall concept is fairly simple: we will apply our translation to the planes using the
As our planes’ positions are automatically updated each time we resize our browser window, we’ll have to reset their relative positions there.
By doing that, we’ll break the sync between the slider’s current translation and our relative positions’ values. We then have to keep track of our slider’s previous translation and subtract those values to our relative position.
The slider and the WebGL are now synced again!
Updating the Code
First of all, we’ll add a
previousTranslation property to our WebGL slider class.
Let’s update our
WebGLSlider class constructor:
Next, we’ll have to update our
onTranslation Hook to use the
setRelativePosition function instead of the previous
The last thing we need to do is rewrite our
onSliderResized Hook to update our
previousTranslation property values, reset our planes’ relative positions, and we’re done!
And that’s all folks!
Now you’re ready to use curtains.js on your website with minimal performance impact.
You can try to change some values in your shader pass fragment shaders to tweak the effect a bit. You can also try to use a different displacement image (remember, you’ll have to use a pattern to obtain a seamless effect).
Here’s a bonus example with a different displacement image and a few variations in the shaders: