Use Smart CSS to apply styles based on the user's scroll position

Use Smart CSS to apply styles based on the user's scroll position

By adding the current scroll offset to the attributes of the html element, we can style elements on the page based on the current scroll position. We can use this to build a navigation component that floats on top of the page.

This is the HTML we will use. The <header> component is the one we want to always float at the top of the page as we scroll down.

<header>I'm the page header</header>
<p>Lot's of content here...</p>
<p>More beautiful content...</p>
<p>Content...</p>

First, we'll listen for the 'scroll' event on the document, and every time the user scrolls we'll get the current scrollY value.

document.addEventListener('scroll', () => {
  document.documentElement.dataset.scroll = window.scrollY;
});

We store the scroll position in the data attribute of the html element. If you look at the DOM using the dev tools it will look like this: <html data-scroll="0">
Now we can use this property to style elements 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 height as the header's min-height at the top of the page */
html:not([data-scroll='0']) body {
  padding-top: 3em;
}

/* Switch the header tag to fixed positioning mode and fix it to the top of the page*/
html:not([data-scroll='0']) header {
  position: fixed;
  top: 0;
  z-index: 1;

  /* The box-shadow property can enhance the floating effect*/
  box-shadow: 0 0 .5em rgba(0, 0, 0, .5);
}

That’s basically it, when the user scrolls down, the header tag will automatically detach from the page and float 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 some areas that can be improved, mainly in terms of performance.

First, we have to modify the JavaScript script to accommodate the situation where the scroll position is not at the top when the page loads. In such cases, the header tag will be rendered incorrectly.

When the page loads, we must quickly get the current scroll offset, which ensures that we are always in sync with the current state of the page.

// Read the scroll position of the current page and store it in the document's data property // so we can use it in our stylesheet const storeScroll = () => {
  document.documentElement.dataset.scroll = window.scrollY;
}

// Listen for scroll events document.addEventListener('scroll', storeScroll);

// Update the scroll position when the page is opened for the first time storeScroll();

Next we'll look at some performance improvements. If we want to get the scrollY position, the browser will have to calculate the position of every element on the page to make sure it returns the correct position. It would be best if we didn't force it to take a value every time it scrolls.

To do this, we need a debounce method, which will queue our fetch requests until the browser is ready to draw the next frame. At this point, it has already calculated the positions of all the elements on the page, so it doesn't keep doing the same work over and over again.

// The debounce function accepts a custom function as a parameter const debounce = (fn) => {

  // This contains a reference to requestAnimationFrame so we can stop it whenever we want let frame;
  
  // The debounce function will return a new function that can accept multiple parameters return (...params) => {
    
    // If the value of frame exists, clear the corresponding callback if (frame) { 
      cancelAnimationFrame(frame);
    }

    // Make our callback execute when the browser refreshes the next frame frame = requestAnimationFrame(() => {
      
      // Execute our custom function and pass our parameters fn(...params);
    });

  } 
};

// Reads out the scroll position and stores it in 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();

By marking the event as passive, we can tell the browser that our scroll event will not be blocked by touch interactions (such as when interacting with plugins 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 });

With the performance issue fixed, we can now use JavaScript in a stable way to feed the fetched data into CSS and use it to style elements on the page.

Live Demo on CodePen

The above is the full content of this article. I hope it will be helpful for everyone’s study. I also hope that everyone will support 123WORDPRESS.COM.

<<:  Use js to call js functions in iframe pages

>>:  Analysis of several situations where MySQL index fails

Recommend

A brief analysis of the best way to deal with forgotten MySQL 8 passwords

Preface Readers who are familiar with MySQL may f...

Docker Compose installation and usage steps

Table of contents 1. What is Docker Compose? 2. D...

Vue implements the countdown component for second kills

This article shares the specific code of Vue to i...

Example of automatic import method of vue3.0 common components

1. Prerequisites We use the require.context metho...

Introduction to the use of several special attribute tags in HTML

The following attributes are not very compatible w...

CSS to achieve compatible text alignment in different browsers

In the front-end layout of the form, we often nee...

The difference between absolute path and relative path in web page creation

1. Absolute path First of all, on the local compu...

Summary of various methods for JavaScript to determine whether it is an array

Table of contents Preface Array.isArray construct...

Nginx implements https website configuration code example

https base port 443. It is used for something cal...

An Uncommon Error and Solution for SQL Server Full Backup

1. Error details Once when manually performing a ...

vue-table implements adding and deleting

This article example shares the specific code for...

MySQL trigger simple usage example

This article uses examples to illustrate the simp...

MySQL join buffer principle

Table of contents 1. MySQL join buffer 2. JoinBuf...

Unzipped version of MYSQL installation and encountered errors and solutions

1 Installation Download the corresponding unzippe...