Barra de progresso ao rolar a página

Como fazer uma barra de progresso que indique a rolagem da página?

Vamos por partes:

clientHeight e clientWidth são as dimensões da janela do navegador, ou seja, apenas o que o usuário vê.

scrollHeight e scrollWidth são as dimensões da página.

Segue imagem abaixo:

Imagem representando clientHeight, clientWidth, scrollHeight, scrollWidth entre outros

App.js

import ProgressBar from "./ProgressBar"

import "./styles.css"

export default function App() {
  return (
    <div className="App">
      <ProgressBar />
      <div>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nec nisi
        libero. Nulla sed ligula eu magna imperdiet dapibus. Suspendisse sed
        ultrices metus. Integer sapien urna, pharetra et ante at, congue rutrum
        tortor. Sed elit ligula, vestibulum at ex non, convallis tincidunt mi.
        Cras quis luctus nunc, nec accumsan augue. Curabitur finibus nibh ac
        gravida mollis.
        <br />
        <br />
        Etiam non convallis lorem. Vivamus eget magna sit amet urna condimentum luctus
        a non nibh. Vestibulum magna risus, tempor non mollis eget, hendrerit vel
        metus. Suspendisse vel purus tristique, convallis lectus ut, varius ligula.
        Nulla eget lacinia sapien. Nulla non neque ut lacus hendrerit imperdiet.
        Suspendisse enim quam, mollis id mauris sit amet, suscipit varius lorem.
        In convallis enim lacus, id viverra justo commodo in. Vestibulum pulvinar
        dolor nec tempor sodales. Aenean ut erat vel tellus auctor bibendum. Mauris
        hendrerit interdum arcu in elementum.
      </div>
    </div>
  )
}

ProgressBar/index.js

import { useState, useEffect } from "react"

import "./styles.css"

export default function ProgressBar() {
  const [scroll, setScroll] = useState(0)

  useEffect(() => {
    let progressBarHandler = () => {
      const totalScroll = document.documentElement.scrollTop
      const windowHeight =
        document.documentElement.scrollHeight -
        document.documentElement.clientHeight
      const scroll = `${totalScroll / windowHeight}`
      setScroll(scroll)
    }
    window.addEventListener("scroll", progressBarHandler)
    return () => window.removeEventListener("scroll", progressBarHandler)
  }, [])

  return (
    <div className="ProgressBar" style={{ transform: `scale(${scroll}, 1)` }} />
  )
}

ProgressBar/styles.css

.ProgressBar {
  position: sticky;
  background: linear-gradient(to left, rgb(108, 37, 223), rgb(153, 9, 84));
  height: 6px;
  z-index: 1;
  top: 0;
  left: 0;
  transform-origin: top left;
  transform: scale(0, 0);
  border-radius: 8px;
}

Comentários