JavaScript 自定义滚动条实现原理与代码详解

作者:小圆点

时间:2026-10-23

浏览:140

本文详细解析如何使用原生 JavaScript 实现自定义滚动条。通过嵌套布局隐藏原生滚动条,利用 offsetHeight、clientHeight 和 scrollHeight 计算比例,动态调整滚动条高度与位置,并提供面向对象封装方案,解决跨浏览器样式不一致问题。

文章目录

自定义滚动条实现概述

在元素应用 overflow: auto 属性时,浏览器会生成滚动条,但不同浏览器的渲染样式存在差异,部分默认样式视觉效果较差。

为此,需要手动实现一个滚动条,主要需厘清以下核心逻辑:

1、滚动条 bar 的高度需根据内容总量动态计算。

2、滚动条 bar 的 top 偏移量需与内容区域的 scrollTop 保持同步。

布局结构与核心算法

实现思路如下:

采用嵌套布局结构,具体层级关系如下:


<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
    <style type="text/css">
      *{
        padding: 0;
        margin: 0;
      }
      .wrap{
        width: 400px;
        height: 400px;
        border: 2px solid deeppink;
        margin: 0 auto;
        overflow: hidden;
        position: relative;
      }
      .box-middle{
        height: 100%;
        overflow: auto;
        width: 200%;
      }
      .box{
        width: 50%;
      }
      .bar{
        background: #000;
        width: 10px;
        position: absolute;
        top: 0;
        right: 0;
      }
      .s1{
        height: 400px;
        background: pink;
      }
      .s2{
        height: 400px;
        background: deeppink;
      }
      .s3{
        height: 400px;
        background: deepskyblue;
      }
    </style>
  </head>
  <body>
    <div class="wrap" id="wrap">
      <div class="box-middle" id="boxMidle">
        <div class="box" id="content">
          <div class="s1">内容1</div>
          <div class="s2">内容2</div>
          <div class="s3">内容3</div>
        </div>
      </div>
      <div class="bar" id="bar"></div>
    </div>
     
  </body>
</html>

wrap 作为最外层容器,设置 overflow: hidden 以隐藏溢出内容。

box-middle 为中间层,即具备滚动功能的区域,可适当增加其宽度以隐藏原生滚动条。

box 为内容层,通过 JavaScript 计算并设置其宽度,使其与 wrap 宽度一致,从而彻底隐藏原生滚动条。

bar 为自定义滚动条元素。

编写 JavaScript 代码前,需明确以下三个关键属性:


offsetHeight : height + padding + border
clientHeight : height + padding
scrollHeight : 内容的高度(所有子元素高度和) + padding

1、计算比例关系:

bar 的高度 / wrap 的高度 = wrap 的高度 / wrap 内容部子元素的高度和;此处假设 wrap 的 padding 为 0。

bar 的 top / wrap 的 scrollTop = wrap 的高度 / wrap 内容部子元素的高度和。

需注意,当计算出的比例值小于 1 时,表示内容未溢出,无需显示滚动条。

JavaScript 代码实现

明确算法后,编写普通版代码如下:


var $wrap = document.getElementById("wrap");
var $boxMidle = document.getElementById("boxMidle");
var $content = document.getElementById("content");
var $bar = document.getElementById("bar");
$content.style.width = $wrap.clientWidth + "px"; //内容的宽度
var rate = $boxMidle.clientHeight/ $boxMidle.scrollHeight; //滚动条高度的比例,也是滚动条top位置的比例
 var barHeight = rate * $boxMidle.clientHeight; //滚动条的 bar 的高度
if(rate < 1){
  //需要出现滚动条,并计算滚动条的高度
  $bar.style.height = barHeight + "px";
}else{
  //不需要出现滚动条
  $bar.style.display = "none";
}
$boxMidle.onscroll = function(e){
  console.log("offsetHeight"+this.offsetHeight); //height + padding + border
  console.log("clientHeight"+this.clientHeight); // height + padding
  console.log("scrollHeight"+this.scrollHeight); //内容的高度(所有子元素高度和) + padding
  console.log(this.scrollTop);
  $bar.style.top = this.scrollTop*rate + "px";
}

使用面向对象方式封装的代码如下:


function ScrollBar(opt){
  var me = this;
  me.$wrap = document.getElementById(opt.wrap);
  me.$boxMidle = document.getElementById(opt.boxMidle);
  me.$content = document.getElementById(opt.content);
  me.$bar = document.getElementById(opt.bar);
  me.init();
  me.$boxMidle.onscroll = function(e){
    //console.log("offsetHeight"+this.offsetHeight); //content + padding + border
    //console.log("clientHeight"+this.clientHeight); // content + padding
    //console.log("scrollHeight"+this.scrollHeight); //内容的高度 + padding
    console.log(this.scrollTop);
    me.scrollToY(this.scrollTop * me.rate)
  }
}
ScrollBar.prototype.init = function(){
  this.$content.style.width = this.$wrap.clientWidth + "px"; //内容的宽度
  this.rate = this.$boxMidle.clientHeight/this.$boxMidle.scrollHeight; //滚动条高度的比例,也是滚动条top位置的比例
   this.barHeight = this.rate * this.$boxMidle.clientHeight; //滚动条的 bar 的高度
  if(this.rate < 1){
    //需要出现滚动条,并计算滚动条的高度
    this.$bar.style.height = this.barHeight + "px";
  }else{
    //不需要出现滚动条
    this.$bar.style.display = "none";
  }
}
ScrollBar.prototype.scrollToY = function(y){
  if(this.rate < 1){
    this.$bar.style.top = y + 'px';
  }
}
 
var obj = new ScrollBar({"wrap":"wrap","boxMidle":"boxMidle","content":"content","bar":"bar"});

最终实现效果如下:

尽管初始视觉效果可能不够美观,但已具备可控性,可根据需求自行调整样式。

自定义滚动条实现概述

以上为本文全部内容,希望能为读者提供学习参考,欢迎支持本站。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章