Scrollbar problem

The default scrollbars vary from browser to browser, and they all feel ugly. There are also big differences between Windows and MAC.

So I plan to start with the CSS basic properties of the scroll bar, and then develop two solutions, and elaborated.

What I want to achieve is that the scroll bar floats over the box and doesn’t take up the width of the box. Similar to fixed effect

Composition of scroll bar

Scroll bars help the box display more content in a fixed area, and the MAC is ideal for comparing the two operating systems.

Chrome under Windows (92)

Chrome for MAC (92)

Scroll bar base properties

  1. ::-webkit- scrollBar The entire scrollbar
  2. ::-webkit-scrollbar-button A button on the scrollbar. The button has up and down arrows. Click to control the movement of the scrollbar
  3. ::-webkit-scrollbar-thumb scroll slider on the scrollbar that can be dragged by clicking
  4. ::-webkit-scrollbar-track Scrollbar track
  5. ::-webkit-scrollbar-track-piece the track part of a scrollbar without a slider
  6. ::-webkit-scrollbar-corner ::-webkit-scrollbar-corner ::-webkit-scrollbar-corner ::-webkit-scrollbar-corner
  7. ::-webkit-resizer partial styles for the corner section of some elements (example: draggable button for Textarea)

Hide the scroll bar and create a virtual scroll bar

Mainly the realization of the following 3 goals 💡

  1. Listen to the content page scroll event = “the page scrolls accordingly
  2. Listen for scroll bar drag = scroll bar scroll & page content scroll
  3. Listen to the scroll track blank click = “scroll bar jump & page content scroll

The preparatory work

HTML part

<div class="box" id="box"> <div class="content" ID ="content"> <div class="blue"> Blue background line </div> </div class="scrollbar" id="scrollbar"> <div class="thumb" id="thumb"></div> </div> </div>Copy the code

The CSS part

/* Use CSS */. Box {width: 400px; height: 400px; background-color: orange; overflow: hidden; position: relative; } .content { width: 400px; height: 400px; overflow-y: scroll; overflow-x: hidden; } /* Display scroll */. Box :hover. Scrollbar {opacity: 1! important; } /* Hide native scrollbar */. Box ::-webkit-scrollbar {display: none; } /* scrollbar */. Scrollbar {height: 100%; width: 6px; position: absolute; top: 0px; right: 0; opacity: 0; The transition: 0.1 s ease - out; } /* thumb scroll bar */. Thumb {width: 6px; height: 100%; background-color: red; border-radius: 8px; position: absolute; cursor: pointer; top: 0px; }Copy the code

Get the DOM from js

Const scrollBar = document.getelementById ('scrollbar') // Thumb = document.getelementById ('thumb' Scrollbar const Content = document.getelementById ('content') // In parallel with the scrollbar containerCopy the code

Js set content container fill & set scrollbar height

Content.innerhtml = content.innerhtml + new Array(400).fill('123').join('-') Thumb.style. height = scrollHeight * 100 + '%'Copy the code

Listen for the scrolling of the content container

Const canScrollHeight = content.scrollheight - clientHeight // Const canScrollHeight = content.scrollheight - clientHeight // Const scrollHeight = clientHeight/content.scrollHeight // Scrollbar height (length, AddEventListener ('scroll', Function (e) {const scrollTop = content.scrollTop // Set the thumb top of the scrollbar. Content: Thumb. Style. Top = (clientHeight - clientHeight * scrollHeight) * (scrollTop / canScrollHeight) + 'px' })Copy the code

Listen for scroll bar drags

thumb.addEventListener('mousedown', DownHandler) /** * Start scrolling */ let cursorDown = false // Drag the flag let y1 = 0 // click the position of the scroll bar from the distance to the top of the scroll bar let y2 = 0 // click the position of the scroll bar Function downHandler(e) {y1 = e.layery // The layerY property of the scrollbar is the distance from the click position to the top of the element y2 = scrollHeight * ClientHeight -y1 // Scrollbar length -y1 // Start dragging cursorDown = true // If multiple events are added to an element, they will be added in the order they are triggered. If you add stopImmediatePropagation (), then the elements of other events will not perform e.s topImmediatePropagation (); / / show the scroll bar container scrollbar. Style. Opacity = 1 / / listening full screen. Drag the document addEventListener (" mousemove ", MoveHandler) / / listening full screen drag over the document. The addEventListener (" mouseup ", Document.onselectstart = () => {return false}} // mousemove {console.log('moveHandler') const contentY = e.pagey Don't do deal with the if (contentY < = y1 | | contentY > = (clientHeight - y2)) {return} / / set the scroll bar thumb thumb. The top attribute style. The top = e.p ageY excuse - X,y content.scrollto (0, 0) Thumb. OffsetTop/(clientHeight - scrollHeight * clientHeight) * canScrollHeight)} {console.log(' Drag to end, ') // End drag cursorDown = false // restore the selected event document. onselectStart = null // Remove two events listening for full screen document.removeEventListener('mousemove', moveHandler) document.removeEventListener('mouseup', upHandler) scrollbar.style.opacity = 0 }Copy the code

Listen to click on the scroll track

scrollbar.addEventListener('mousedown', Function clickScrollbar(e) {const pageY = e.layery const height = scrollHeight * clientHeight  let top = (pageY - height / 2) if (top < 0) { top = 0 } if (top > (clientHeight - clientHeight * scrollHeight)) { top =  (clientHeight - clientHeight * scrollHeight) } thumb.style.top = top + 'px' content.scrollTo(0, thumb.offsetTop / (clientHeight - scrollHeight * clientHeight) * canScrollHeight) }Copy the code

conclusion

  1. Each step of implementing a custom scrollbar is straightforward and requires patience as it is pieced together

  2. The implementation principle is basically the same as el-ScrollBar, but the common components of the project are implemented by ourselves as much as possible under the premise of cost. On the one hand, many excellent usages can be accumulated by learning or reviewing the knowledge points of this component as a whole, such as dealing with the interaction between DOM and body. On the other hand, you can customize the team’s ideas, although there isn’t much you can customize with this scroll bar

  3. When I’m listening for mousemove events, I’m listening for document.body at first, and I lose my listening when I mouse out of the browser, and then I scroll back out. So you need to listen for mousemove on document

  4. The corresponding meaning of the location attribute of the mouse event and the DOM directly acquired should be understood and applied separately