Mobile Draggable Scrollbar

모바일 브라우저에 반투명한 스크롤바 추가하고 드래그 가능하게 만듦 (최소 크기 및 터치 개선)

24.02.2025 itibariyledir. En son verisyonu görün.

Bu betiği kurabilmeniz için Tampermonkey, Greasemonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Userscripts gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

You will need to install an extension such as Tampermonkey to install this script.

Bu komut dosyasını yüklemek için bir kullanıcı komut dosyası yöneticisi uzantısı yüklemeniz gerekecek.

(Zaten bir kullanıcı komut dosyası yöneticim var, kurmama izin verin!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Zateb bir user-style yöneticim var, yükleyeyim!)

// ==UserScript==
// @name         Mobile Draggable Scrollbar
// @namespace    http://tampermonkey.net/
// @version      1.2
// @description  모바일 브라우저에 반투명한 스크롤바 추가하고 드래그 가능하게 만듦 (최소 크기 및 터치 개선)
// @author       ChatGPT
// @license      MIT
// @match        *://*/*
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    // 스타일 적용
    const style = document.createElement("style");
    style.textContent = `
        .custom-scrollbar-container {
            position: fixed;
            right: 3px;
            top: 0;
            width: 14px; /* 터치 영역을 넓히기 위해 큰 컨테이너 */
            height: 100%;
            z-index: 9999;
            pointer-events: none;
        }
        
        .custom-scrollbar {
            position: absolute;
            right: 3px;
            width: 8px;
            background: rgba(0, 0, 0, 0.4);
            border-radius: 4px;
            opacity: 0;
            transition: opacity 0.3s ease-in-out;
            touch-action: none; /* 터치 드래그 활성화 */
            pointer-events: auto;
        }
        
        .custom-scrollbar.active {
            background: rgba(0, 0, 0, 0.6); /* 터치 중일 때 색상 강조 */
        }
    `;
    document.head.appendChild(style);

    // 스크롤바 컨테이너 생성 (터치 영역 확대용)
    const scrollbarContainer = document.createElement("div");
    scrollbarContainer.classList.add("custom-scrollbar-container");
    document.body.appendChild(scrollbarContainer);

    // 스크롤바 요소 생성
    const scrollbar = document.createElement("div");
    scrollbar.classList.add("custom-scrollbar");
    scrollbarContainer.appendChild(scrollbar);

    let timeoutId = null;
    let isDragging = false;
    let startY = 0;
    let startScrollTop = 0;

    function updateScrollbar() {
        const scrollHeight = document.documentElement.scrollHeight;
        const clientHeight = window.innerHeight;
        const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;

        if (scrollHeight <= clientHeight) {
            scrollbar.style.opacity = "0"; // 스크롤이 필요 없는 경우 숨김
            return;
        }

        // 최소 크기 적용 (너무 작아지지 않도록)
        const minScrollbarHeight = 40;
        let scrollbarHeight = Math.max((clientHeight / scrollHeight) * clientHeight, minScrollbarHeight);

        // 스크롤 위치 비율 계산
        const maxScrollTop = scrollHeight - clientHeight;
        const maxScrollbarTop = clientHeight - scrollbarHeight;
        let scrollbarTop = (scrollTop / maxScrollTop) * maxScrollbarTop;

        scrollbar.style.height = `${scrollbarHeight}px`;
        scrollbar.style.top = `${scrollbarTop}px`;
        scrollbar.style.opacity = "1";

        // 일정 시간이 지나면 서서히 사라짐
        clearTimeout(timeoutId);
        timeoutId = setTimeout(() => {
            if (!isDragging) {
                scrollbar.style.opacity = "0";
            }
        }, 800);
    }

    function startDrag(event) {
        isDragging = true;
        scrollbar.classList.add("active");

        startY = event.touches ? event.touches[0].clientY : event.clientY;
        startScrollTop = document.documentElement.scrollTop || document.body.scrollTop;

        event.preventDefault();
    }

    function onDrag(event) {
        if (!isDragging) return;

        const currentY = event.touches ? event.touches[0].clientY : event.clientY;
        const deltaY = currentY - startY;

        const scrollHeight = document.documentElement.scrollHeight;
        const clientHeight = window.innerHeight;
        const maxScrollTop = scrollHeight - clientHeight;

        const minScrollbarHeight = 40;
        const scrollbarHeight = Math.max((clientHeight / scrollHeight) * clientHeight, minScrollbarHeight);
        const maxScrollbarTop = clientHeight - scrollbarHeight;
        const scrollRatio = maxScrollTop / maxScrollbarTop;

        document.documentElement.scrollTop = startScrollTop + deltaY * scrollRatio;
        document.body.scrollTop = startScrollTop + deltaY * scrollRatio;

        updateScrollbar();
    }

    function endDrag() {
        isDragging = false;
        scrollbar.classList.remove("active");
        timeoutId = setTimeout(() => {
            scrollbar.style.opacity = "0";
        }, 800);
    }

    // 이벤트 리스너 추가
    scrollbarContainer.addEventListener("touchstart", startDrag);
    window.addEventListener("touchmove", onDrag);
    window.addEventListener("touchend", endDrag);

    scrollbarContainer.addEventListener("mousedown", startDrag);
    window.addEventListener("mousemove", onDrag);
    window.addEventListener("mouseup", endDrag);

    window.addEventListener("scroll", updateScrollbar);
    window.addEventListener("resize", updateScrollbar);

    updateScrollbar();
})();