preface

Which websites did everyone go shopping on the past Double 11? No matter which website you go to, it is estimated that you can’t miss Tmall. When browsing Tmall, you found such an interesting phenomenon:

While this effect is fairly common, there is one detail that makes it different. For example, let’s take a look at a normal header that fades out as the window scrolls:

The normal version is completely transparent at first, and then displays slowly as the window scrolls, by controlling the opacity property of opacity on opacity.

The black box version starts with a gradient, which is almost translucent. This way looks more elegant, but it looks like it only starts with a nice gradient when entering the page without scrolling, and behaves the same as before when scrolling with transparency.

What we want to improve is to use the rolling distance to control the background-position, with the window rolling, will slowly change the gradient gradient and control the effect of hidden.

style

First, let’s write out the header style:

header {
      /* Set a CSS variable to control the position of the background color, easy JS control */
      --position: 100;

      /* Displays the child element */ in the lower center
      display: grid;
      place-items: end center;

      /* Set to fixed location */
      position: fixed;

      /* 0 */ from the top to the left
      top: 0;
      left: 0;

      /* Spread the width of the screen */
      width: 100%;

      /* Give a suitable height */
      height: 40px;

      /* White font */
      color: white;

      /* Font size */
      font-size: 16px;

      /* Make the font thinner */
      font-weight: 100;

      /* Add the next internal change to prevent the text from being too low */
      padding-bottom: 10px;

      /* Set the transition effect */
      transition: background-position .2s;

      /* Black gradient background */
      background: linear-gradient(black, rgba(148.88.88.0.3) 80%.rgba(0.0.0.0)) 0 calc(var(--position) * 1%) / 100% 300%;
    }
Copy the code

Running result:

You can see that we’ve set a CSS variable in the header, if you’re not sure what a CSS variable is click here, and we also use gird to center it, not exactly center it, but a little bit down, because I think that’s what tmall’s little black box does.

The overall implementation

Then we started to write JS code, because pure CSS is still unable to get the scrolling distance of the screen, but in order to be more convenient for the interaction between the two sides, we still use CSS variables, because the CSS variables brought by the improvement is not only to save a bit of CSS code, and reduce the cost of CSS development and maintenance.

More importantly, much of the interactive development in the component is moved from JS to CSS code, making the component code cleaner and making the visual presentation implementation more flexible. – Zhang Xinxu

For details on the benefits of CSS variables, please refer to Zhang Xinxu’s blog:

The Improvement and Change brought by CSS Variables to THE development of JS Interactive Components

Take a look at how CSS variables interact with JS:

<! DOCTYPEhtml>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0, user - scalable = no">
  <title>A little black box of your own</title>
  <style>
    /* Clear the default style */
    * { padding: 0; margin: 0 }

    header {
      /* Set a CSS variable to control the position of the background color, easy JS control */
      --position: 100;

      /* Displays the child element */ in the lower center
      display: grid;
      place-items: end center;

      /* Set to fixed location */
      position: fixed;

      /* 0 */ from the top to the left
      top: 0;
      left: 0;

      /* Spread the width of the screen */
      width: 100%;

      /* Give a suitable height */
      height: 40px;

      /* White font */
      color: white;

      /* Font size */
      font-size: 16px;

      /* Make the font thinner */
      font-weight: 100;

      /* Add the next internal change to prevent the text from being too low */
      padding-bottom: 10px;

      /* Set the transition effect */
      transition: background-position .2s;

      /* Black gradient background */
      background: linear-gradient(black, rgba(148.88.88.0.3) 80%.rgba(0.0.0.0)) 0 calc(var(--position) * 1%) / 100% 300%;
    }

    main {
      /* Give a suitable height */
      height: 1000px;
    }
  </style>
</head>
<body>
  <header>Our own little black box</header>
  <main></main>

  <script>
    / / get the header
    const header = document.getElementsByTagName('header') [0]

    addEventListener('scroll'.() = > {
      // Get the offset value
      const top = document.documentElement.scrollTop

      // Set an appropriate range
      if (top <= 200) {
        // Change the gradient position of the header to the calculated gradient position
        header.style.setProperty('--position'.100 - Math.min(100, top))
      } else {
        // Make it completely opaque after moving within a certain range
        header.style.setProperty('--position'.0)}})</script>
</body>
</html>
Copy the code

Running result:

Imagine what would happen if you didn’t use CSS variables:

header.style.backgroundPosition = '0' + 100 - Math.min(100, top) + The '%'
Copy the code

It may not seem like much, but it can be a disaster when you have a lot of properties to control, and having CSS units like PX, %, rem all the time adds an unnecessary mental burden and slows down the performance of the application.

You don’t have to use units when you use CSS variables, you just assign a number, so why don’t you use units? The answer lies in the calc function:

calc(var(--position) * 1%)

In JS, we use + because it represents string concatenation. In JS, we multiply the number by one percent and it becomes a percentage. Similarly, if you need other units, you can modify them flexibly according to your needs:

calc(var(--position) * 1px)

⚠️ Note that the 1 in front of px is very important and cannot be omitted!

You don’t have to write a 1, but you can use multiples based on specific requirements:

Calc (var (position) * 6.6 rem)

extension

In fact, from the code and from what we see in everyday life, basically the opacity of the header is fixed after a certain distance and it doesn’t change anymore, so it’s a waste of listening for onScroll events. But you can’t cancel the listen because you don’t know when the user will slide to the top again, but this situation is perfect for doing the other effect:

I forgot what this effect is called, but it’s like a progress bar at the top of the page as you scroll down the page, so you know where you are on the page.

<! DOCTYPEhtml>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0, user - scalable = no">
  <title>A little black box of your own</title>
  <style>
    /* Clear the default style */
    * { padding: 0; margin: 0 }

    header {
      /* Set a CSS variable to control the position, easy JS control */
      --position: 0;

      /* Set to fixed location */
      position: fixed;

      /* 0 */ from the top to the left
      top: 0;
      left: 0;

      /* Spread the width of the screen */
      width: 100%;

      /* Give a suitable height */
      height: 10px;

      /* Set the transition effect */
      transition: transform .1s;

      /* Gradient background */
      background: linear-gradient(to right,#4481eb.#04befe);

      /* Set the deformation effect */
      transform: scaleX(var(--position));

      /* Set deformation reference point */
      transform-origin: left;
    }

    main {
      /* Give a suitable height */
      height: 10000px;

      /* Gradient background */
      background: linear-gradient(#30cfd0.# 330867)}</style>
</head>
<body>
  <header></header>
  <main></main>

  <script>
    / / get the header
    const header = document.getElementsByTagName('header') [0]

    addEventListener('scroll'.() = > {
      // Get the offset value
      const top = document.documentElement.scrollTop

      // Get the total height of the page
      const height = document.documentElement.scrollHeight

      // Set the CSS variables
      header.style.setProperty('--position', top / (height - document.documentElement.clientHeight))
    })
  </script>
</body>
</html>
Copy the code

This article was published on wechat official account: “Front-end Learning does not Move”

Previous excellent article

  • Microsoft launches comments section on GitHub
  • Vue 3.0.3: New CSS variable passing and the latest Ref Proposal
  • You Yuxi: Ref Grammar Sugar Proposal
  • “Don’t underestimate how one question can reveal a candidate’s true colors.”
  • “Mobile Layout Interview Questions to test your CSS Skills (Center)”
  • A series of confusing behaviors after setting prototype Objects as Proxies
  • Vue’s Super Fun New Feature: DOM Portal
  • A fun new feature of Vue: Introducing JS variables into CSS
  • Create your own Visual Data Map without any libraries
  • “Use of React’s Super-popular CSS-in-JS Library in the Vue Project: Styled – Components”
  • Is It Finally Vue’s Turn to Inspire React?
  • A Small Pit in Vue3 on IOS
  • Upgrade your React project to Immer instead of Immutable by 2020
  • “Soul Interrogation from the Author of React Hooks and Immutable”
  • Good news, Vue3 official document is available in Chinese!
  • Hooks use of the New VUe-Router
  • Vue 3:20 Years of Status Updates
  • React 17 is officially a transition version!
  • Yu Yuxi: The Design Process of Vue3
  • The Father of Node’s refactoring Deno is finally released. Will it Replace Node after all?
  • The Vue3 beta was released early this morning and openly supports scaffolding!