为什么在计算 scrollPercent 时需要从 windowHeight 中减小 clientHeight?

Why need to decrease clientHeight from windowHeight while calculating scrollPercent?

我正在尝试显示用户在带有进度条的页面上滚动了多少,我已经做到了。但是我在这里有点困惑。

这是我找到的用于计算 scrollPercent 的代码,效果很好


windowHeight = Math.max(
html.clientHeight,
html.scrollHeight,
html.offsetHeight,
body.scrollHeight,
body.offsetHeight
);

const  scrolledPercent =
((html.scrollTop || body.scrollTop) / (windowHeight - html.clientHeight)) *
100;

最初,我想,要获得 scrollPercent ,我需要获得当前 scrollPosition 并将该数字除以页面的总高度,然后乘以 100% 。这就像我们通常如何获得某些东西的 %

const  scrolledPercent = 
((html.scrollTop || body.scrollTop) / windowHeight) * 100;

但是这条线没有像我预期的那样工作。如果我这样做,即使我滚动到页面末尾,进度条也不会到达 100%。我不明白为什么我在这里错了!

所以,我的问题是为什么我们需要减少 windowHeighthtml.clientHeight

谢谢。

此处演示:

// --------------------------------------------
// variables
// --------------------------------------------

const html = document.documentElement,
  body = document.body,
  countryList = document.querySelector(".country__list");
scrollNavigated = document.querySelector(".scroll__navigated");
let windowHeight;

// --------------------------------------------
// function
// --------------------------------------------

async function prepareListOfCountries() {
  let list = await fetch("https://restcountries.eu/rest/v2/all");
  list = Array.from(await list.json());
  let markup = list
    .map((country, index) => {
      return `<li class="country__item card">
              <span class="country__name">${country.name}</span
              ><span class="country__capital">${country.capital}</span>
              <a href="javascript:;" class="country__flag">
               <img src= '${country.flag}'> </a>
             
        </li>`;
    })
    .slice(0, 30)
    .join(" ");
  countryList.innerHTML = markup;
}

function updateScrolledStatus(e) {
  windowHeight = Math.max(
    html.clientHeight,
    html.scrollHeight,
    html.offsetHeight,
    body.scrollHeight,
    body.offsetHeight
  );

  const scrolledPercent =
    ((html.scrollTop || body.scrollTop) / (windowHeight - html.clientHeight)) *
    100;
  // const scrolledPercent =
  //   ((html.scrollTop || body.scrollTop) / windowHeight) * 100; // this line doesnot work
  scrollNavigated.style.width = scrolledPercent + "%";
}

prepareListOfCountries();

// --------------------------------------------
// event-handler
// --------------------------------------------

window.addEventListener("scroll", updateScrolledStatus);
*::after,
*::before,
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  background: #fff;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen,
 Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
}

.container {
  max-width: 980px;
  margin: 0 auto;
}

.justify-between {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.items-center {
  display: flex;
  align-items: center;
}

.card {
  background-color: #fff;
  box-shadow: 0 0 12px 12px rgba(0, 0, 0, 0.054);
  border-radius: 4px;
  padding: 16px;
}

.country__flag img {
  height: 100%;
  width: 100%;
}

.header {
  padding: 24px 0;
  background-color: #333;
  color: #f1f1f1;
  position: -webkit-sticky;
  position: sticky;
}

.content {
  padding: 50px 0;
}

.content__form {
  margin: 0 auto;
  margin-bottom: 32px;
}

.content__search {
  width: 50%;
  padding: 12px 16px;
  border-radius: 20px;
  border: 1px solid #ddd;
  transition: 0.2s;
}

.content__search:hover {
  box-shadow: 0 1px 6px 0 rgba(32, 33, 36, 0.28);
}

.content__search:focus {
  outline: none;
}

.country__list {
  margin-top: 50px;
  margin: 10px auto;
}

.country__item {
  display: flex;
  justify-content: space-between;
  margin-bottom: 16px;
}

.country__name, .country__capital, .country__flag {
  width: 33.33%;
}

.country__flag {
  width: 32px;
  height: 24px;
}

.scroll__navigator {
  height: 2px;
  margin: 0 auto 32px;
  background-color: #333;
  position: -webkit-sticky;
  position: sticky;
  top: 0;
}

.scroll__navigated {
  display: block;
  height: 100%;
  width: 0;
  background: orangered;
  transition: 0.3s linear;
}
<body>
    <header class="header">
      <div class="container">
        All countries list
      </div>
    </header>
    <main class="content">
      <div class="container">
        <form class="content__form">
          <input class="content__search" />
        </form>
        <div class="scroll__navigator">
          <span class="scroll__navigated"></span>
        </div>
        <section class="country">
          <ul class="country__list">
            <li class="country__item card">
              <span class="country__name">Nepal</span
              ><span class="country__capital">Kathmandu</span>
              <a href="javascript:;" class="country__flag"></a>
            </li>
          </ul>
        </section>
      </div>
    </main>
     
  </body>
 

举个例子,假设你的客户端的高度是100px,而你的整个页面的高度是500px

当滚动位置为 0px 时,您可以看到您网站的第一个 100px,因此从 0px100px

在滚动位置 100px,您可以看到 100px200px 的范围,因为您已经移动了页面,因此可见范围在 [=10] =].

在滚动位置 400px,因此您可以看到范围 400px500px – 换句话说,您已经滚动到底部。

这表明页面的可滚动高度(400px)小于页面的实际高度(500px),即小于客户端的高度。

要获得滚动百分比,需要使用可滚动高度,所以需要用页面高度减去客户端高度才能得到正确的值,否则永远无法滚动到底部。在只有 500px 长的网站上无法滚动 500px