为什么在计算 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%
。我不明白为什么我在这里错了!
所以,我的问题是为什么我们需要减少 windowHeight
的 html.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
,因此从 0px
到 100px
。
在滚动位置 100px
,您可以看到 100px
到 200px
的范围,因为您已经移动了页面,因此可见范围在 [=10] =].
在滚动位置 400px
,因此您可以看到范围 400px
到 500px
– 换句话说,您已经滚动到底部。
这表明页面的可滚动高度(400px
)小于页面的实际高度(500px
),即小于客户端的高度。
要获得滚动百分比,需要使用可滚动高度,所以需要用页面高度减去客户端高度才能得到正确的值,否则永远无法滚动到底部。在只有 500px
长的网站上无法滚动 500px
!
我正在尝试显示用户在带有进度条的页面上滚动了多少,我已经做到了。但是我在这里有点困惑。
这是我找到的用于计算 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%
。我不明白为什么我在这里错了!
所以,我的问题是为什么我们需要减少 windowHeight
的 html.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
,因此从 0px
到 100px
。
在滚动位置 100px
,您可以看到 100px
到 200px
的范围,因为您已经移动了页面,因此可见范围在 [=10] =].
在滚动位置 400px
,因此您可以看到范围 400px
到 500px
– 换句话说,您已经滚动到底部。
这表明页面的可滚动高度(400px
)小于页面的实际高度(500px
),即小于客户端的高度。
要获得滚动百分比,需要使用可滚动高度,所以需要用页面高度减去客户端高度才能得到正确的值,否则永远无法滚动到底部。在只有 500px
长的网站上无法滚动 500px
!