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

base target="" specifies the target of the base link to open the frame

<base target=_blank> changes the target fram...

Build a WebRTC video chat in 5 minutes

In the previous article, I introduced the detaile...

Implementing WeChat tap animation effect based on CSS3 animation attribute

Seeing the recent popular WeChat tap function, I ...

Rules for registration form design

I finished reading "Patterns for Sign Up &...

How to solve jQuery conflict problem

In front-end development, $ is a function in jQue...

What you need to know about creating MySQL indexes

Table of contents Preface: 1. Create index method...

MySQL database implements MMM high availability cluster architecture

concept MMM (Master-Master replication manager fo...

Let you understand the deep copy of js

Table of contents js deep copy Data storage metho...

Nginx/Httpd load balancing tomcat configuration tutorial

In the previous blog, we talked about using Nginx...

Summary of MySQL's commonly used concatenation statements

Preface: In MySQL, the CONCAT() function is used ...

Basic knowledge of HTML: a preliminary understanding of web pages

HTML is the abbreviation of Hypertext Markup Langu...

Token verification login in Vue project (front-end part)

This article example shares the specific code of ...