横向滚动条 css js html

目的:

1. 练习手写滚动条

2. 市面上多是竖向滚动条,横向滚动条较少

3. 横向滚动条,需要滑动到容器底部才能使用,不方便,因此想自己写一个横向滚动条放置在容器内部的视口高度的最低处

3. 问题复现:

如果容器的内容超过了容器的宽度,就会出现横向滚动条(暂不考虑换行),但是如果该容器的高度过高,用户需要滑到容器的底部才能操作横向滚动条(横向滚动条默认在容器的底部,当然我们不考虑使用shift+鼠标左键的方式横向移动)

问题演示视频:

横向滚动条-问题演示

制作横向滚动条

样式:

滚动条包含两个方面:track(滚动轨道) + thumb(滚动块)

最开始是只有content容器的,然后我们在content下面添加横向滚动条容器,并且在最外层添加box容器。

最外层的box是相对定位(没有宽高),滚动条是绝对定位

     .box {
        position: relative;
      }
      .content {
        width: 100px;
        height: 1000px;
        background-color: pink;
        overflow: auto;
      }
      .content::-webkit-scrollbar {
        display: none;
      }
      .track {
        position: absolute;
        left: 0;
        bottom: 0; /*0<=bottom<=1000-10px*/
        width: 100px;
        height: 10px;
        background-color: red;
      }
      .thumb {
        cursor: grab;
        position: absolute;
        left: 0;
        top: 0;
        width: 10px;
        height: 100%;
        background-color: blue;
      }
    

    <div class="box">
      <div class="content">
        asdawdkjaslkdjalkwjdlkasjdlawkldakslldjawlkdjlkasjdkawdasdawes
        asdawdkjaslkdjalkwjdlkasjdlawkldakslldjawlkdjlkasjdkawdasdawes
        asdawdkjaslkdjalkwjdlkasjdlawkldakslldjawlkdjlkasjdkawdasdawes
      </div>
      <div class="track" id="scrollbar">
        <div class="thumb" id="scrollbar-thumb"></div>
      </div>
    </div>

逻辑:

监听容器横向滚动,同步滑块位置

监听content容器的滚动动作,同步到滑块的位置

const content = document.querySelector(".content")
const track = document.querySelector(".track")
const thumb = document.querySelector(".thumb") 
function updateScrollbar() {
    const scrollPercentage =
          content.scrollLeft / (content.scrollWidth - content.clientWidth)
    const thumbPosition =
          scrollPercentage * (track.clientWidth - thumb.clientWidth)
    thumb.style.left = thumbPosition + "px"
}
// content(这样还包括了shift+鼠标左键)
content.addEventListener("scroll", updateScrollbar)

拖动滑块

然后,我们再来制作拖动滑块同时横向移动容器的功能,主要用到三个动作,mousedown,mousemove,mouseup

      // 监听滑块拖动事件
      let isDragging = false
      let startX
      let startScrollLeft
      thumb.addEventListener("mousedown", function (e) {
        isDragging = true
        startX = e.clientX
        startScrollLeft = content.scrollLeft

        // 拖动开始时改变鼠标样式为正在抓取
        thumb.style.cursor = "grabbing"

        // 防止在拖动时选择文本
        e.preventDefault()
      })

      document.addEventListener("mousemove", function (e) {
        if (isDragging) {
          const deltaX = e.clientX - startX
          const scrollDelta =
            (deltaX / track.clientWidth) *
            (content.scrollWidth - content.clientWidth)
          content.scrollLeft = startScrollLeft + scrollDelta
        }
      })

      document.addEventListener("mouseup", function () {
        isDragging = false
      })

规定横向滚动条的位置的界限

(横向滚动条的位置最低不低于容器的边界底部,最高不高于容器的边界顶部)

      let contentRec = content.getBoundingClientRect()//得到content容器的边界
      track.style.bottom =
        content.clientHeight - (window.innerHeight - contentRec.top) + "px"


      let trackBottom = parseInt(track.style.bottom) // 获取轨道的底部位置
      if (
        trackBottom <= 0 ||
        trackBottom >= content.clientHeight - track.clientHeight
      ) {
        track.style.bottom = "0px" // 设置时加上单位
      }


      // 更新 track.style.bottom 的逻辑
      document.addEventListener("scroll", function () {
        let viewHeight = window.innerHeight + scrollY
        contentRec = content.getBoundingClientRect()
        // 计算新的 bottom 值
        let newBottom =
          content.clientHeight - (window.innerHeight - contentRec.top)

        // 确保 newBottom 不小于 0 且不大于 content.clientHeight - track.clientHeight
        newBottom = Math.max(
          0,
          Math.min(newBottom, content.clientHeight - track.clientHeight)
        )

        // 更新 track 的 bottom 样式
        track.style.bottom = `${newBottom}px`
      })

成品

代码:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }
      .header {
        width: 100px;
        height: 1000px;
        background-color: skyblue;
      }
      .footer {
        width: 100px;
        height: 300px;
        background-color: green;
      }
      .box {
        position: relative;
      }
      .content {
        width: 100px;
        height: 1000px;
        background-color: pink;
        overflow: auto;
      }
      .content::-webkit-scrollbar {
        display: none;
      }
      .track {
        position: absolute;
        left: 0;
        bottom: 0; /*0<=bottom<=1000-10px*/
        width: 100px;
        height: 10px;
        background-color: red;
      }
      .thumb {
        cursor: grab;
        position: absolute;
        left: 0;
        top: 0;
        width: 10px;
        height: 100%;
        background-color: blue;
      }
    </style>
  </head>
  <body>
    <div class="header"></div>
    <div class="box">
      <div class="content">
        asdawdkjaslkdjalkwjdlkasjdlawkldakslldjawlkdjlkasjdkawdasdawes
        asdawdkjaslkdjalkwjdlkasjdlawkldakslldjawlkdjlkasjdkawdasdawes
        asdawdkjaslkdjalkwjdlkasjdlawkldakslldjawlkdjlkasjdkawdasdawes
        asdawdkjaslkdjalkwjdlkasjdlawkldakslldjawlkdjlkasjdkawdasdawes
        asdawdkjaslkdjalkwjdlkasjdlawkldakslldjawlkdjlkasjdkawdasdawes
        asdawdkjaslkdjalkwjdlkasjdlawkldakslldjawlkdjlkasjdkawdasdawes
      </div>
      <!-- 我觉得这个滚动条应该是不能在内容容器内部的 -->
      <div class="track" id="scrollbar">
        <div class="thumb" id="scrollbar-thumb"></div>
      </div>
    </div>
    <div class="footer"></div>

    <script>
      const content = document.querySelector(".content")
      const track = document.querySelector(".track")
      const thumb = document.querySelector(".thumb")

      // console.log("window.innerHeight", window.innerHeight)
      // track.style.bottom = window.innerHeight + "px"
      let contentRec = content.getBoundingClientRect()
      track.style.bottom =
        content.clientHeight - (window.innerHeight - contentRec.top) + "px"

      function updateScrollbar() {
        const scrollPercentage =
          content.scrollLeft / (content.scrollWidth - content.clientWidth)
        const thumbPosition =
          scrollPercentage * (track.clientWidth - thumb.clientWidth)
        thumb.style.left = thumbPosition + "px"
      }
      // content(这样还包括了shift+鼠标左键)
      content.addEventListener("scroll", updateScrollbar)

      // 提取数值进行比较
      let trackBottom = parseInt(track.style.bottom) // 将字符串转换为整数
      if (
        trackBottom <= 0 ||
        trackBottom >= content.clientHeight - track.clientHeight
      ) {
        track.style.bottom = "0px" // 设置时加上单位
      }

      // 更新 track.style.bottom 的逻辑
      document.addEventListener("scroll", function () {
        let viewHeight = window.innerHeight + scrollY
        contentRec = content.getBoundingClientRect()
        // 计算新的 bottom 值
        let newBottom =
          content.clientHeight - (window.innerHeight - contentRec.top)

        // 确保 newBottom 不小于 0 且不大于 content.clientHeight - track.clientHeight
        newBottom = Math.max(
          0,
          Math.min(newBottom, content.clientHeight - track.clientHeight)
        )

        // 更新 track 的 bottom 样式
        track.style.bottom = `${newBottom}px`

        console.log(track.style.bottom)
      })

      // 监听滑块拖动事件
      let isDragging = false
      let startX
      let startScrollLeft
      thumb.addEventListener("mousedown", function (e) {
        isDragging = true
        startX = e.clientX
        startScrollLeft = content.scrollLeft

        // 拖动开始时改变鼠标样式为正在抓取
        thumb.style.cursor = "grabbing"

        // 防止在拖动时选择文本
        e.preventDefault()
      })

      document.addEventListener("mousemove", function (e) {
        if (isDragging) {
          const deltaX = e.clientX - startX
          const scrollDelta =
            (deltaX / track.clientWidth) *
            (content.scrollWidth - content.clientWidth)
          content.scrollLeft = startScrollLeft + scrollDelta
        }
      })

      document.addEventListener("mouseup", function () {
        isDragging = false
      })
    </script>
  </body>
</html>

 演示视频:

横向滚动条

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值