- Applying Styles Based on the User Scroll Position with Smart CSS
- Rik Schennink
- The Nuggets translation Project
- Permanent link to this article: github.com/xitu/gold-m…
- Translator: jerryOnlyZRJ
- Proofreader: ScDadaguo
By adding the current scroll offset to the attributes of the HTML element, we can set the element style on the page based on the current scroll position. We can use it to build a navigation component that floats at the top of the page.
This is the HTML we’ll use, and the
<header>I'm the page header</header>
<p>Lot's of content here... </p> <p>More beautiful content... </p> <p>Content... </p>Copy the code
First, we’re going to listen for the ‘scroll’ event on the document, and every time the user scrolls we’re going to pull out the current scrollY value.
document.addEventListener('scroll', () => {
document.documentElement.dataset.scroll = window.scrollY;
});
Copy the code
We store the scroll position in the data attributes of the HTML element. If you use a developer tool to view the DOM, it will look like this: < HTML data-scroll=”0″>
We can now use this property to set the element style on the page.
/* Ensure that the header tag is always higher than 3em */ header {min-height: 3em; width: 100%; background-color:#fff;} /* Keep the same min-height of the header at the top of the page */ HTML :not([data-scroll='0']) body { padding-top: 3em; } /* Switch the header TAB to fixed mode and fix it at the top of the page */ HTML :not([data-scroll='0']) header { position: fixed; top: 0; z-index: 1; /* Box-shadow: 0 0.5em rgba(0, 0, 0,.5); }Copy the code
Basically, as the user scrolls down, the header tag is automatically detached from the page and floats above the content. The JavaScript code doesn’t care about this; its job is to put the scroll offset in the data attribute. This is perfect because there is no tight coupling between JavaScript and CSS.
But there are still areas where improvements can be made, mainly in terms of performance.
First, we had to modify the JavaScript script to accommodate the scrolling position not at the top when the page loaded. In this case, the header tag will render the wrong style.
When the page loads, we must quickly get the current scroll offset, which ensures that we are always in sync with the state of the current page.
Const storeScroll = () => {// Read the scrolling position of the current page and store it in the data property of the document document.documentElement.dataset.scroll = window.scrollY; } / / listening scroll event document. AddEventListener ('scroll', storeScroll); // Update the scroll position storeScroll() when opening the page for the first time;Copy the code
Next we’ll look at some performance improvements. If we want to get the scrollY scroll position, the browser will have to calculate the position of every element on the page to make sure it returns the correct position. It’s best if we don’t force it to be evaluated every time it scrolls.
To do this, we need a debounce method that puts our value request in a queue and doesn’t revalue until the browser is ready to draw the next frame, at which point it has already calculated the position of all the elements on the page so it doesn’t do the same thing over and over again.
// The anti-jitter function takes our own custom function const debounce = (fn) => {// This contains a reference to requestAnimationFrame, so we can stop it at any time we wishletframe; // The anti-jitter function returns a new function that can accept multiple argumentsreturn(... Params) => {// If the frame value exists, clear the corresponding callbackif(frame) { cancelAnimationFrame(frame); } // Make our callback execute frame = requestAnimationFrame(() => {// execute our custom function and pass our parameter fn(... params); }); }}; // Reads out the scroll position and stores itin the data attribute
// so we can use it in our stylesheets
const storeScroll = () => {
document.documentElement.dataset.scroll = window.scrollY;
}
// Listen for new scroll events, here we debounce our `storeScroll` function
document.addEventListener('scroll', debounce(storeScroll));
// Update scroll position for first time
storeScroll();
Copy the code
By marking the event as passive, we can tell the browser that our scrolling event will not be blocked by touch interaction (such as when interacting with plug-ins such as Google Maps). This allows the browser to scroll the page immediately because it now knows that the event will not be blocked.
document.addEventListener('scroll', debounce(storeScroll), { passive: true });
Copy the code
With the performance issues resolved, we can now use JavaScript in a stable way to feed data to CSS and use it to style elements on the page.
Live Demo on CodePen
If you find any mistakes in your translation or other areas that need to be improved, you are welcome to the Nuggets Translation Program to revise and PR your translation, and you can also get the corresponding reward points. The permanent link to this article at the beginning of this article is the MarkDown link to this article on GitHub.
The Nuggets Translation Project is a community that translates quality Internet technical articles from English sharing articles on nuggets. The content covers Android, iOS, front-end, back-end, blockchain, products, design, artificial intelligence and other fields. If you want to see more high-quality translation, please continue to pay attention to the Translation plan of Digging Gold, the official Weibo, Zhihu column.