Created
October 9, 2025 03:48
-
-
Save Be1zebub/b8c99d3dd6afe26f3ed404e0a01ca931 to your computer and use it in GitHub Desktop.
the idea was make a custom customizable scrollbar track/thumb since default is bad at styling. so we disable defaults rendering & make custom. havent finished it, even idk if this works XD
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <script lang="ts"> | |
| // WIP! Not finished yet! | |
| import { onDestroy, onMount } from "svelte" | |
| let wrapperNode: HTMLElement | |
| let contentNode: HTMLElement | |
| let showBar = false | |
| let thumbHeight = 0 | |
| let thumbTop = 0 | |
| // dragging | |
| let thumbDragging = false | |
| let thumbDraggingStartY = 0 | |
| let thumbDraggingStartTop = 0 | |
| function startDragging(e: MouseEvent) { | |
| e.preventDefault() | |
| thumbDragging = true | |
| thumbDraggingStartY = e.clientY | |
| thumbDraggingStartTop = thumbTop | |
| window.addEventListener("mousemove", handleDragging) | |
| window.addEventListener("mouseup", stopDragging) | |
| } | |
| function handleDragging(e: MouseEvent) { | |
| if (!thumbDragging) return | |
| e.preventDefault() | |
| const deltaY = e.clientY - thumbDraggingStartY | |
| const trackHeight = wrapperNode.clientHeight | |
| const scrollDelta = (deltaY / trackHeight) * contentNode.scrollHeight | |
| contentNode.scrollTop = scrollDelta | |
| } | |
| function stopDragging() { | |
| thumbDragging = false | |
| window.removeEventListener("mousemove", handleDragging) | |
| window.removeEventListener("mouseup", stopDragging) | |
| } | |
| // main | |
| let observer: ResizeObserver | |
| function updateScrollbar() { | |
| if (!contentNode || !wrapperNode) return | |
| const { clientHeight, scrollHeight, scrollTop } = contentNode | |
| showBar = scrollHeight > clientHeight | |
| if (!showBar) return | |
| const trackHeight = wrapperNode.clientHeight | |
| thumbHeight = Math.max(20, (clientHeight / scrollHeight) * trackHeight) | |
| const maxScrollTop = scrollHeight - clientHeight | |
| const maxThumbTop = trackHeight - thumbHeight | |
| thumbTop = Math.min(maxThumbTop, (scrollTop / maxScrollTop) * maxThumbTop) | |
| } | |
| onMount(() => { | |
| updateScrollbar() | |
| observer = new ResizeObserver(updateScrollbar) | |
| observer.observe(wrapperNode) | |
| if (contentNode.children[0]) { | |
| observer.observe(contentNode.children[0]) | |
| } | |
| }) | |
| onDestroy(() => { | |
| stopDragging() | |
| if (observer) { | |
| observer.disconnect() | |
| } | |
| }) | |
| </script> | |
| <div class="scroll-wrapper" bind:this={wrapperNode}> | |
| <div | |
| class="scroll-content" | |
| bind:this={contentNode} | |
| on:scroll={updateScrollbar} | |
| > | |
| <slot /> | |
| </div> | |
| {#if showBar} | |
| <div class="scroll-track"> | |
| <button | |
| aria-label="Scroll-thumb" | |
| class="scroll-thumb" | |
| style:bind:clientHeight={thumbHeight} | |
| style:top={thumbTop} | |
| class:dragging={thumbDragging} | |
| on:mousedown={startDragging} | |
| ></button> | |
| </div> | |
| {/if} | |
| </div> | |
| <style> | |
| .scroll-wrapper { | |
| position: relative; | |
| height: 100%; | |
| width: 100%; | |
| overflow: hidden; | |
| } | |
| .scroll-content { | |
| height: 100%; | |
| overflow-y: scroll; | |
| width: calc(100% + 17px); | |
| -ms-overflow-style: none; | |
| scrollbar-width: none; | |
| } | |
| .scroll-content::-webkit-scrollbar { | |
| display: none; | |
| } | |
| .scroll-track { | |
| position: absolute; | |
| top: 2px; | |
| right: 2px; | |
| bottom: 2px; | |
| width: 8px; | |
| background-color: rgba(255, 255, 255, 0.32); | |
| border-radius: 4px; | |
| } | |
| .scroll-thumb { | |
| position: absolute; | |
| left: 0; | |
| width: 100%; | |
| background-color: rgb(255, 0, 0); | |
| border-radius: 4px; | |
| cursor: pointer; | |
| transition: background-color 0.2s; | |
| } | |
| .scroll-thumb:hover, | |
| .scroll-thumb.dragging { | |
| background-color: #a8a8a8; | |
| } | |
| </style> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment