令人惊讶的是,没有使用原生 JavaScript 的出色、简单的解决方案。我做了一个纯 JS 轻量级、最小化的跨浏览器解决方案。 根据自己的需要和审美来调整
*2019 年更新
W3C 有一个在标准轨道上的工作文档,以通过 css 规范开箱即用地改进这一点。尽管有限制,但如果您想使用最先进的 css,您现在可以通过 scrollbar-color 和 scrollbar-width 设置滚动条的样式。更多信息请查看https://drafts.csswg.org/css-scrollbars/
示例:
这是fiddle 和CodePen
HTML
<body>
<div id="main" class="scrollable">
<div class="content-wrapper">
<div class="content">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Incidunt accusamus maxime voluptatem quasi. Recusandae optio nobis ratione iste consectetur consequatur cupiditate saepe laborum natus neque a provident eum explicabo delectus qui accusantium nostrum reiciendis soluta hic ut at sed laboriosam possimus repudiandae deserunt velit rerum. Aliquam ratione itaque corrupti aperiam quisquam unde aspernatur odio id repellendus corporis eaque expedita in ab minus possimus! Quo tempore consequatur repellat consectetur nemo molestiae perferendis ipsum esse nesciunt blanditiis nobis dicta? Laudantium quaerat inventore deleniti exercitationem explicabo quos pariatur sunt earum labore sed eius blanditiis architecto consequuntur ad consectetur unde sapiente nisi. Sunt eos.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Incidunt accusamus maxime voluptatem quasi. Recusandae optio nobis ratione iste consectetur consequatur cupiditate saepe laborum natus neque a provident eum explicabo delectus qui accusantium nostrum reiciendis soluta hic ut at sed laboriosam possimus repudiandae deserunt velit rerum. Aliquam ratione itaque corrupti aperiam quisquam unde aspernatur odio id repellendus corporis eaque expedita in ab minus possimus! Quo tempore consequatur repellat consectetur nemo molestiae perferendis ipsum esse nesciunt blanditiis nobis dicta? Laudantium quaerat inventore deleniti exercitationem explicabo quos pariatur sunt earum labore sed eius blanditiis architecto consequuntur ad consectetur unde sapiente nisi. Sunt eos.</p>
</div>
</div>
</div>
<div>Not special and not contained within scrolling</div>
</body>
CSS
.scrollable {
padding: 0% 10%;
position: relative;
border: 1px solid gray;
overflow: hidden;
height: 400px;
}
.scrollable.showScroll::after {
position: absolute;
content: '';
top: 5%;
right: 7px;
height: 90%;
width: 3px;
background: rgba(224, 224, 255, .3);
}
.scrollable .content-wrapper {
width: 100%;
height: 100%;
padding-right: 50%;
overflow-y: scroll;
}
.scroller {
z-index: 5;
cursor: pointer;
position: absolute;
width: 10px;
border-radius: 5px;
background: rgb(111, 111, 190);
top: 0px;
right: 3px;
-webkit-transition: top .08s;
-moz-transition: top .08s;
-ms-transition: top .08s;
-o-transition: top .08s;
transition: top .08s;
}
.content {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
JS
(function () {
var scrollContainer = document.querySelector('.scrollable'),
scrollContentWrapper = document.querySelector('.scrollable .content-wrapper'),
scrollContent = document.querySelector('.scrollable .content'),
contentPosition = 0,
scrollerBeingDragged = false,
scroller,
topPosition,
scrollerHeight;
function calculateScrollerHeight() {
// *Calculation of how tall scroller should be
var visibleRatio = scrollContainer.offsetHeight / scrollContentWrapper.scrollHeight;
return visibleRatio * scrollContainer.offsetHeight;
}
function moveScroller(evt) {
// Move Scroll bar to top offset
var scrollPercentage = evt.target.scrollTop / scrollContentWrapper.scrollHeight;
topPosition = scrollPercentage * (scrollContainer.offsetHeight - 5); // 5px arbitrary offset so scroll bar doesn't move too far beyond content wrapper bounding box
scroller.style.top = topPosition + 'px';
}
function startDrag(evt) {
normalizedPosition = evt.pageY;
contentPosition = scrollContentWrapper.scrollTop;
scrollerBeingDragged = true;
}
function stopDrag(evt) {
scrollerBeingDragged = false;
}
function scrollBarScroll(evt) {
if (scrollerBeingDragged === true) {
var mouseDifferential = evt.pageY - normalizedPosition;
var scrollEquivalent = mouseDifferential * (scrollContentWrapper.scrollHeight / scrollContainer.offsetHeight);
scrollContentWrapper.scrollTop = contentPosition + scrollEquivalent;
}
}
function createScroller() {
// *Creates scroller element and appends to '.scrollable' div
// create scroller element
scroller = document.createElement("div");
scroller.className = 'scroller';
// determine how big scroller should be based on content
scrollerHeight = calculateScrollerHeight();
if (scrollerHeight / scrollContainer.offsetHeight < 1){
// *If there is a need to have scroll bar based on content size
scroller.style.height = scrollerHeight + 'px';
// append scroller to scrollContainer div
scrollContainer.appendChild(scroller);
// show scroll path divot
scrollContainer.className += ' showScroll';
// attach related draggable listeners
scroller.addEventListener('mousedown', startDrag);
window.addEventListener('mouseup', stopDrag);
window.addEventListener('mousemove', scrollBarScroll)
}
}
createScroller();
// *** Listeners ***
scrollContentWrapper.addEventListener('scroll', moveScroller);
}());
这个概念很简单。我们有一个带有“可滚动”类的主 div。 JavaScript 识别此元素并附加一个滚动 div,您可以使用 CSS 设置自己的样式。通过嵌套 content-wrapper 子 div,我们可以有效地将原生滚动条推到父 div 之外,同时仍然控制填充。
这是一个图表:
我们需要保持原生滚动能力的原因是因为 JavaScript 滚动事件只在溢出设置为滚动的元素上触发。见MDN reference on scroll。好处是如果 JS 被禁用,我们仍然可以优雅地回退到没有滚动条的滚动。
注意
您应该注意,在某些情况下,您必须调整版本以重新计算滚动条大小:
1.) 调整屏幕大小或
2.) 如果追加更多内容。
其次,如果您有多个“可滚动”元素,则必须进行修改。在这种情况下,您将需要遍历这些元素以附加滚动 div 并监听滚动事件。