自定义滚动条拇指超出范围
Custom scrollbars thumb goes out of bounds
我正在尝试创建一个与默认滚动条(带动画)一起滚动的拇指滚动条。我终于能够实现它,唯一的问题是,自定义滚动条不会在确切位置滚动。如果一直向下滚动,则拇指滚动条会越过其父元素。
此外,拇指滚动条比默认滚动条大。这是数学:
scrollBarThumb.style.height = (innerWrapper.parentElement.offsetHeight * innerWrapper.parentElement.offsetHeight / innerWrapper.scrollHeight) + 'px';
scrollBarPosition = clamp(scrollBarPosition, 0, scrolledToBottom)
scrollBarPosition = scrollBar.offsetHeight * scrollBarPosition / innerWrapper.scrollHeight;
我使用的公式是自定义滚动条的公认公式。
两个问题是:(它们可能是一个问题,因为我认为如果高度固定,那么滚动位置也会自动固定。)首先,滚动条的拇指比默认的大。其次,当您一直向下滚动时,滚动条拇指会越过其父项。
我做错了什么,我该如何解决?
console.clear();
var innerWrapper = document.getElementById('innerWrapper');
var scrollBar = document.getElementById('scrollbar');
var scrollBarThumb = scrollBar.firstElementChild
scrollBarThumb.style.height = (innerWrapper.parentElement.offsetHeight * innerWrapper.parentElement.offsetHeight / innerWrapper.scrollHeight) + 'px';
innerWrapper.addEventListener('mousewheel', handleScroll);
innerWrapper.addEventListener('DOMMouseScroll', handleScroll);
var duration = 35,
scrollSpeed = 2,
animateAmount = 30;
var scrolledToBottom = 0,
scrollDirection = 0, // 1 = scroll down, -1 = scroll up
animationID;
function handleScroll(e) {
// Cancel previous animation
cancelAnimationFrame(animationID);
// Scroll faster
scrollSpeed += 2;
// Reason for negative `-.wheelDelta` because Firefox
// return oposite value. See http://phrogz.net/js/wheeldelta.html
// Get 1 or -1
var delta = Math.max(-1, Math.min(1, (-e.wheelDelta || e.detail)));
// Check if scroll direction changed
if (scrollDirection != delta) {
scrollSpeed = 2; // Start slowly - restart speed
scrollDirection = delta;
}
var start = innerWrapper.parentElement.scrollTop,
end = start + animateAmount * scrollSpeed * delta, // Where to end the scroll
change = end - start, // base change in one scroll
step = 0, // current step in animation
tempScrollPosition; // Cannot assign any number yet (i.e. 0), because `scrollPosition` may be 0.
// Get amount of scrolled to bottom
scrolledToBottom = innerWrapper.scrollHeight - innerWrapper.parentElement.offsetHeight;
animationID = requestAnimationFrame(smoothScrollAnim); // Start animation
function smoothScrollAnim() {
animationID = requestAnimationFrame(smoothScrollAnim); // Restart animation
// Get scroll position
var scrollBarPosition = easeOut(step++, start, change, duration);
scrollBarPosition = clamp(scrollBarPosition, 0, scrolledToBottom)
scrollBarPosition = scrollBar.offsetHeight * scrollBarPosition / innerWrapper.scrollHeight;
// Apply scroll movement
scrollBarThumb.style.top = scrollBarPosition + 'px';
// Check if scroll finished (either animation finished, or bumped to top or bottom)
if (step >= duration || tempScrollPosition === scrollBarPosition) {
// Clean up
tempScrollPosition = null;
scrollSpeed = 2;
cancelAnimationFrame(animationID);
} else {
tempScrollPosition = scrollBarPosition;
}
}
}
function easeOut(time, begin, change, duration) {
time /= duration;
return -change * time * (time - 2) + begin;
}
function clamp(val, min, max) {
if (typeof min !== 'number') min = 0;
if (typeof max !== 'number') max = 1;
return Math.min(Math.max(val, min), max);
}
html {
height: 100%;
overflow-y: hidden;
}
body {
height: 100%;
overflow-y: hidden;
display: flex;
}
#outerWrapper {
height: 400px;
overflow: auto;
background-color: black;
}
#content {
background-image: url("http://images.freeimages.com/images/premium/previews/3037/30376024-beautiful-flower-portrait.jpg");
width: 400px;
}
#scrollbar {
height: 400px;
width: 50px;
background-color: orange;
border: 2px solid green;
}
#scrollbar_thumb {
background-color: yellow;
border: 2px solid blue;
position: relative;
}
<div id="outerWrapper">
<div id="innerWrapper">
<div id="content">
Lorem ipsum dolor sit amet consectetuer laoreet faucibus id ut et. Consequat Ut tellus enim ante nulla molestie vitae sem interdum turpis. Fames ridiculus cursus pellentesque Vestibulum justo sem lorem neque accumsan nulla. Lacinia Suspendisse vitae libero
sem et laoreet risus Sed condimentum Cras. Nunc massa mauris tempor dolor pulvinar justo neque dui ipsum vitae. Lacinia dui cursus pellentesque Vestibulum justo sem lorem neque accumsan nulla. Lacinia Suspendisse vitae libero sem et laoreet risus
Sed condimentum Cras. Nunc massa mauris tempor dolor pulvinar justo neque dui ipsum vitae. Lacinia dui scelerisque Sed convallis nonummy orci Vestibulum orci tempusLorem ipsum dolor sit amet consectetuer laoreet faucibus id ut et. Consequat Ut tellus
enim ante nulla molestie vitae sem interdum turpis. Fames ridiculus cursus pellentesque Vestibulum justo sem lorem neque accumsan nulla. Lacinia Suspendisse vitae libero sem et laoreet risus Sed condimentum Cras. Nunc massa mauris tempor dolor pulvinar
justo neque dui ipsum vitae. Lacinia dui scelerisque Sed convallis nonummy orci Vestibulum orci tempusLorem ipsum dolor sit amet consectetuer laoreet faucibus id ut et. Consequat Ut tellus enim ante nulla molestie vitae sem interdum turpis. Fames
ridiculus cursus pellentesque Vestibulum justo sem lorem neque accumsan nulla. Lacinia Suspendisse vitae libero sem et laoreet risus Sed condimentum Cras. Nunc massa mauris tempor dolor pulvinar justo neque dui ipsum vitae. Lacinia dui scelerisque
Sed convallis nonummy orci Vestibulum orci tempusLorem ipsum dolor sit amet consectetuer laoreet faucibus id ut et. Consequat Ut tellus enim ante nulla molestie vitae sem interdum turpis. Fames ridiculus cursus pellentesque Vestibulum justo sem
lorem neque accumsan nulla. Lacinia Suspendisse vitae libero sem et laoreet risus Sed condimentum Cras. Nunc massa mauris tempor dolor Lorem ipsum dolor sit amet consectetuer laoreet faucibus id ut et. Consequat Ut tellus enim ante nulla molestie
vitae sem interdum turpis. Fames ridiculus cursus pellentesque Vestibulum justo sem lorem neque accumsan nulla. Lacinia Suspendisse vitae libero sem et laoreet risus Sed condimentum Cras. Nunc massa mauris tempor dolor pulvinar justo neque dui ipsum
vitae. Lacinia dui scelerisque Sed convallis nonummy orci Vestibulum orci tempusLorem ipsum dolor sit amet consectetuer laoreet faucibus id ut et. Consequat Ut tellus enim ante nulla molestie vitae sem interdum turpis. Fames ridiculus cursus pellentesque
Vestibulum justo sem lorem neque accumsan nulla. Lacinia Suspendisse vitae libero sem et laoreet risus Sed condimentum Cras. Nunc massa mauris tempor dolor pulvinar justo neque dui ipsum vitae. Lacinia dui scelerisque Sed convallis nonummy orci
Vestibulum orci tempusLorem ipsum dolor sit amet consectetuer laoreet faucibus id ut et. Consequat Ut tellus enim ante nulla molestie vitae sem interdum turpis. Fames ridiculus cursus pellentesque Vestibulum justo sem lorem neque accumsan nulla.
Lacinia Suspendisse vitae libero sem et laoreet risus Sed condimentum Cras. Nunc massa mauris tempor dolor pulvinar justo neque dui ipsum vitae. Lacinia dui scelerisque Sed convallis nonummy orci Vestibulum orci tempusLorem ipsum dolor sit amet
consectetuer laoreet faucibus id ut et. Consequat Ut tellus enim ante nulla molestie vitae sem interdum turpis. Fames ridiculus cursus pellentesque Vestibulum justo sem lorem neque accumsan nulla. Lacinia Suspendisse vitae libero sem et laoreet
risus Sed condimentum Cras. Nunc massa mauris tempor dolor pulvinar justo neque dui ipsum vitae. Lacinia dui scelerisque Sed convallis nonummy orci Vestibulum orci tempusLorem ipsum dolor sit amet consectetuer laoreet faucibus id ut et. Consequat
Ut tellus enim ante nulla molestie vitae sem interdum turpis. Fames ridiculus cursus pellentesque Vestibulum justo sem lorem neque accumsan nulla. Lacinia Suspendisse vitae libero sem et laoreet risus Sed condimentum Cras. Nunc massa mauris tempor
dolor
</div>
</div>
</div>
<div id="scrollbar">
<div id="scrollbar_thumb"></div>
</div>
我认为你把事情复杂化了。
对于滚动,只需注册 "scroll"
事件,
对于捕捉延迟效果,使用 CSS3 transition
对于涉及的简单数学,请参见下面的示例:
var content = document.querySelector("#content"),
scrollbar = document.querySelector("#scrollbar"),
handler = document.querySelector("#handler");
// FROM ELEMENT SCROLL TO HANDLER POSITION
function moveScrollbar() {
// Calculate scrollbar height
var height = content.clientHeight,
scrollHeight = content.scrollHeight,
handlerHeight = height * height / scrollHeight;
// Calculate scrollbar position
var handlerTop = content.scrollTop / height * handlerHeight;
handler.style.height = handlerHeight+'px';
handler.style.top = handlerTop+'px';
}
moveScrollbar(); // At init
content.addEventListener("scroll", moveScrollbar); // and on scroll
body {
display: flex;
}
#content{
height:190px;
width:300px;
overflow-y:scroll;
font-size:3em;
}
#scrollbar{
position:relative;
background:orange;
width:30px;
}
#handler{
position:absolute;
top:0;
background:yellow;
width: 100%;
transition: 0.2s; /* ♪ */
}
<div id="content">
Scroll and see the custom scrollbar move.<br>Lorem ipsum dolor sit amet consectetuer laoreet faucibus id ut et. Consequat Ut tellus enim ante nulla molestie vitae sem interdum turpis. Fames ridiculus cursus pellentesque Vestibulum justo sem lorem neque accumsan nulla. Lacinia Suspendisse vitae libero
</div>
<div id="scrollbar">
<div id="handler" draggable="true"></div>
</div>
当你决定构建一个点击拖动来让你的处理程序真正滚动内容时,这里也是数学:
// FROM HANDLER POSITION TO ELEMENT SCROLL:
var height = content.clientHeight,
scrollHeight = content.scrollHeight,
scrollPos = scrollHeight / height * handler.clientTop;
我正在尝试创建一个与默认滚动条(带动画)一起滚动的拇指滚动条。我终于能够实现它,唯一的问题是,自定义滚动条不会在确切位置滚动。如果一直向下滚动,则拇指滚动条会越过其父元素。
此外,拇指滚动条比默认滚动条大。这是数学:
scrollBarThumb.style.height = (innerWrapper.parentElement.offsetHeight * innerWrapper.parentElement.offsetHeight / innerWrapper.scrollHeight) + 'px';
scrollBarPosition = clamp(scrollBarPosition, 0, scrolledToBottom)
scrollBarPosition = scrollBar.offsetHeight * scrollBarPosition / innerWrapper.scrollHeight;
我使用的公式是自定义滚动条的公认公式。
两个问题是:(它们可能是一个问题,因为我认为如果高度固定,那么滚动位置也会自动固定。)首先,滚动条的拇指比默认的大。其次,当您一直向下滚动时,滚动条拇指会越过其父项。
我做错了什么,我该如何解决?
console.clear();
var innerWrapper = document.getElementById('innerWrapper');
var scrollBar = document.getElementById('scrollbar');
var scrollBarThumb = scrollBar.firstElementChild
scrollBarThumb.style.height = (innerWrapper.parentElement.offsetHeight * innerWrapper.parentElement.offsetHeight / innerWrapper.scrollHeight) + 'px';
innerWrapper.addEventListener('mousewheel', handleScroll);
innerWrapper.addEventListener('DOMMouseScroll', handleScroll);
var duration = 35,
scrollSpeed = 2,
animateAmount = 30;
var scrolledToBottom = 0,
scrollDirection = 0, // 1 = scroll down, -1 = scroll up
animationID;
function handleScroll(e) {
// Cancel previous animation
cancelAnimationFrame(animationID);
// Scroll faster
scrollSpeed += 2;
// Reason for negative `-.wheelDelta` because Firefox
// return oposite value. See http://phrogz.net/js/wheeldelta.html
// Get 1 or -1
var delta = Math.max(-1, Math.min(1, (-e.wheelDelta || e.detail)));
// Check if scroll direction changed
if (scrollDirection != delta) {
scrollSpeed = 2; // Start slowly - restart speed
scrollDirection = delta;
}
var start = innerWrapper.parentElement.scrollTop,
end = start + animateAmount * scrollSpeed * delta, // Where to end the scroll
change = end - start, // base change in one scroll
step = 0, // current step in animation
tempScrollPosition; // Cannot assign any number yet (i.e. 0), because `scrollPosition` may be 0.
// Get amount of scrolled to bottom
scrolledToBottom = innerWrapper.scrollHeight - innerWrapper.parentElement.offsetHeight;
animationID = requestAnimationFrame(smoothScrollAnim); // Start animation
function smoothScrollAnim() {
animationID = requestAnimationFrame(smoothScrollAnim); // Restart animation
// Get scroll position
var scrollBarPosition = easeOut(step++, start, change, duration);
scrollBarPosition = clamp(scrollBarPosition, 0, scrolledToBottom)
scrollBarPosition = scrollBar.offsetHeight * scrollBarPosition / innerWrapper.scrollHeight;
// Apply scroll movement
scrollBarThumb.style.top = scrollBarPosition + 'px';
// Check if scroll finished (either animation finished, or bumped to top or bottom)
if (step >= duration || tempScrollPosition === scrollBarPosition) {
// Clean up
tempScrollPosition = null;
scrollSpeed = 2;
cancelAnimationFrame(animationID);
} else {
tempScrollPosition = scrollBarPosition;
}
}
}
function easeOut(time, begin, change, duration) {
time /= duration;
return -change * time * (time - 2) + begin;
}
function clamp(val, min, max) {
if (typeof min !== 'number') min = 0;
if (typeof max !== 'number') max = 1;
return Math.min(Math.max(val, min), max);
}
html {
height: 100%;
overflow-y: hidden;
}
body {
height: 100%;
overflow-y: hidden;
display: flex;
}
#outerWrapper {
height: 400px;
overflow: auto;
background-color: black;
}
#content {
background-image: url("http://images.freeimages.com/images/premium/previews/3037/30376024-beautiful-flower-portrait.jpg");
width: 400px;
}
#scrollbar {
height: 400px;
width: 50px;
background-color: orange;
border: 2px solid green;
}
#scrollbar_thumb {
background-color: yellow;
border: 2px solid blue;
position: relative;
}
<div id="outerWrapper">
<div id="innerWrapper">
<div id="content">
Lorem ipsum dolor sit amet consectetuer laoreet faucibus id ut et. Consequat Ut tellus enim ante nulla molestie vitae sem interdum turpis. Fames ridiculus cursus pellentesque Vestibulum justo sem lorem neque accumsan nulla. Lacinia Suspendisse vitae libero
sem et laoreet risus Sed condimentum Cras. Nunc massa mauris tempor dolor pulvinar justo neque dui ipsum vitae. Lacinia dui cursus pellentesque Vestibulum justo sem lorem neque accumsan nulla. Lacinia Suspendisse vitae libero sem et laoreet risus
Sed condimentum Cras. Nunc massa mauris tempor dolor pulvinar justo neque dui ipsum vitae. Lacinia dui scelerisque Sed convallis nonummy orci Vestibulum orci tempusLorem ipsum dolor sit amet consectetuer laoreet faucibus id ut et. Consequat Ut tellus
enim ante nulla molestie vitae sem interdum turpis. Fames ridiculus cursus pellentesque Vestibulum justo sem lorem neque accumsan nulla. Lacinia Suspendisse vitae libero sem et laoreet risus Sed condimentum Cras. Nunc massa mauris tempor dolor pulvinar
justo neque dui ipsum vitae. Lacinia dui scelerisque Sed convallis nonummy orci Vestibulum orci tempusLorem ipsum dolor sit amet consectetuer laoreet faucibus id ut et. Consequat Ut tellus enim ante nulla molestie vitae sem interdum turpis. Fames
ridiculus cursus pellentesque Vestibulum justo sem lorem neque accumsan nulla. Lacinia Suspendisse vitae libero sem et laoreet risus Sed condimentum Cras. Nunc massa mauris tempor dolor pulvinar justo neque dui ipsum vitae. Lacinia dui scelerisque
Sed convallis nonummy orci Vestibulum orci tempusLorem ipsum dolor sit amet consectetuer laoreet faucibus id ut et. Consequat Ut tellus enim ante nulla molestie vitae sem interdum turpis. Fames ridiculus cursus pellentesque Vestibulum justo sem
lorem neque accumsan nulla. Lacinia Suspendisse vitae libero sem et laoreet risus Sed condimentum Cras. Nunc massa mauris tempor dolor Lorem ipsum dolor sit amet consectetuer laoreet faucibus id ut et. Consequat Ut tellus enim ante nulla molestie
vitae sem interdum turpis. Fames ridiculus cursus pellentesque Vestibulum justo sem lorem neque accumsan nulla. Lacinia Suspendisse vitae libero sem et laoreet risus Sed condimentum Cras. Nunc massa mauris tempor dolor pulvinar justo neque dui ipsum
vitae. Lacinia dui scelerisque Sed convallis nonummy orci Vestibulum orci tempusLorem ipsum dolor sit amet consectetuer laoreet faucibus id ut et. Consequat Ut tellus enim ante nulla molestie vitae sem interdum turpis. Fames ridiculus cursus pellentesque
Vestibulum justo sem lorem neque accumsan nulla. Lacinia Suspendisse vitae libero sem et laoreet risus Sed condimentum Cras. Nunc massa mauris tempor dolor pulvinar justo neque dui ipsum vitae. Lacinia dui scelerisque Sed convallis nonummy orci
Vestibulum orci tempusLorem ipsum dolor sit amet consectetuer laoreet faucibus id ut et. Consequat Ut tellus enim ante nulla molestie vitae sem interdum turpis. Fames ridiculus cursus pellentesque Vestibulum justo sem lorem neque accumsan nulla.
Lacinia Suspendisse vitae libero sem et laoreet risus Sed condimentum Cras. Nunc massa mauris tempor dolor pulvinar justo neque dui ipsum vitae. Lacinia dui scelerisque Sed convallis nonummy orci Vestibulum orci tempusLorem ipsum dolor sit amet
consectetuer laoreet faucibus id ut et. Consequat Ut tellus enim ante nulla molestie vitae sem interdum turpis. Fames ridiculus cursus pellentesque Vestibulum justo sem lorem neque accumsan nulla. Lacinia Suspendisse vitae libero sem et laoreet
risus Sed condimentum Cras. Nunc massa mauris tempor dolor pulvinar justo neque dui ipsum vitae. Lacinia dui scelerisque Sed convallis nonummy orci Vestibulum orci tempusLorem ipsum dolor sit amet consectetuer laoreet faucibus id ut et. Consequat
Ut tellus enim ante nulla molestie vitae sem interdum turpis. Fames ridiculus cursus pellentesque Vestibulum justo sem lorem neque accumsan nulla. Lacinia Suspendisse vitae libero sem et laoreet risus Sed condimentum Cras. Nunc massa mauris tempor
dolor
</div>
</div>
</div>
<div id="scrollbar">
<div id="scrollbar_thumb"></div>
</div>
我认为你把事情复杂化了。
对于滚动,只需注册 "scroll"
事件,
对于捕捉延迟效果,使用 CSS3 transition
对于涉及的简单数学,请参见下面的示例:
var content = document.querySelector("#content"),
scrollbar = document.querySelector("#scrollbar"),
handler = document.querySelector("#handler");
// FROM ELEMENT SCROLL TO HANDLER POSITION
function moveScrollbar() {
// Calculate scrollbar height
var height = content.clientHeight,
scrollHeight = content.scrollHeight,
handlerHeight = height * height / scrollHeight;
// Calculate scrollbar position
var handlerTop = content.scrollTop / height * handlerHeight;
handler.style.height = handlerHeight+'px';
handler.style.top = handlerTop+'px';
}
moveScrollbar(); // At init
content.addEventListener("scroll", moveScrollbar); // and on scroll
body {
display: flex;
}
#content{
height:190px;
width:300px;
overflow-y:scroll;
font-size:3em;
}
#scrollbar{
position:relative;
background:orange;
width:30px;
}
#handler{
position:absolute;
top:0;
background:yellow;
width: 100%;
transition: 0.2s; /* ♪ */
}
<div id="content">
Scroll and see the custom scrollbar move.<br>Lorem ipsum dolor sit amet consectetuer laoreet faucibus id ut et. Consequat Ut tellus enim ante nulla molestie vitae sem interdum turpis. Fames ridiculus cursus pellentesque Vestibulum justo sem lorem neque accumsan nulla. Lacinia Suspendisse vitae libero
</div>
<div id="scrollbar">
<div id="handler" draggable="true"></div>
</div>
当你决定构建一个点击拖动来让你的处理程序真正滚动内容时,这里也是数学:
// FROM HANDLER POSITION TO ELEMENT SCROLL:
var height = content.clientHeight,
scrollHeight = content.scrollHeight,
scrollPos = scrollHeight / height * handler.clientTop;