📌

javascriptのスムーズscrollライブラリを作成しました。便利!!

に公開

以下のコードコピペで試せます。

js部分がライブラリ。

scrollしたい要素に、scrollable-boxを付けてください。

スクロールバーもそのまま使えます。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>スムーズスクロールのモック</title>
    <style>
        body {
            font-family: sans-serif;
            margin: 0;
            padding: 20px;
            background-color: #f0f2f5;
        }
        .container {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 20px;
        }
        .panel {
            background-color: #fff;
            border-radius: 8px;
            padding: 20px;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
            margin-bottom: 20px; /* Add margin for more content below */
        }
        h2 {
            border-bottom: 2px solid #ddd;
            padding-bottom: 10px;
        }
        .scrollable-box {
            height: 200px;
            overflow: auto; /* Enable scrolling here */
            border: 1px solid #ccc;
            padding: 10px;
            margin-top: 10px;
            background-color: #fafafa;
            transition: box-shadow 0.3s ease; /* Add transition for a smoother effect */
        }

        .scrollable-box:hover {
            box-shadow: 0 6px 10px rgba(0, 0, 0, 0.2); /* Highlight on hover */
        }
        .scroll-content {
            height: 500px; /* Height for scrolling */
            background-image: linear-gradient(to bottom, #a1c4fd, #c2e9fb);
            padding: 10px;
        }
        
        /* Modal-related styles */
        .modal-overlay {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.5);
            display: none;
            justify-content: center;
            align-items: center;
            z-index: 1000;
        }
        .modal-content {
            background-color: #fff;
            padding: 20px;
            border-radius: 8px;
            max-width: 80%;
            max-height: 80%;
            overflow: hidden;
        }
        .modal-body {
            height: 300px; /* Scrolling inside modal */
            overflow: auto;
            border: 1px solid #ddd;
            padding: 10px;
            margin-top: 10px;
            transition: box-shadow 0.3s ease;
        }

        .modal-body:hover {
            box-shadow: 0 6px 10px rgba(0, 0, 0, 0.2);
        }
        .modal-scroll-content {
            height: 800px;
            background-image: linear-gradient(to bottom, #d4fc79, #96e6a1);
            padding: 10px;
        }
        
        button {
            padding: 10px 20px;
            background-color: #007bff;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
        }
        
        /* Style for the extra content to make the body scrollable */
        .filler-content {
            padding: 20px;
            text-align: center;
            color: #555;
        }
    </style>
</head>
<body>

    <h1>スムーズスクロールのデモ</h1>
    <p>以下のスクロール可能なボックスや、モーダル内のコンテンツに<strong>マウスカーソルを乗せて</strong>、マウスホイールでスクロールしてみてください。</p>
    <p>※ マウスカーソルがどのボックスにも乗っていない場合は、ページ全体がスムーズにスクロールします。</p>
    <div class="container">
        <div class="panel" id="panel-1">
            <h2>パネル 1</h2>
            <p>このセクション内のスクロールボックスです。</p>
            <div class="scrollable-box">
                <div class="scroll-content">
                    <p>このボックスはスクロール可能です。</p>
                    <p>ホイールを回すと滑らかに動きます。</p>
                    <p>たくさんのコンテンツ...</p>
                    <p>たくさんのコンテンツ...</p>
                    <p>たくさんのコンテンツ...</p>
                    <p>たくさんのコンテンツ...</p>
                    <p>たくさんのコンテンツ...</p>
                </div>
            </div>
        </div>
        
        <div class="panel" id="panel-2">
            <h2>パネル 2</h2>
            <p>こちらにも別のスクロールボックスがあります。</p>
            <div class="scrollable-box">
                <div class="scroll-content">
                    <p>別のボックスです。</p>
                    <p>滑らかなスクロールを体験しましょう。</p>
                    <p>コンテンツをいっぱい入れてみました。</p>
                    <p>コンテンツをいっぱい入れてみました。</p>
                    <p>コンテンツをいっぱい入れてみました。</p>
                    <p>コンテンツをいっぱい入れてみました。</p>
                    <p>コンテンツをいっぱい入れてみました。</p>
                </div>
            </div>
        </div>
    </div>
    
    <button id="openModalBtn">モーダルを開く</button>
    
    <div class="modal-overlay">
        <div class="modal-content">
            <h2>モーダルウィンドウ</h2>
            <div class="modal-body">
                <div class="modal-scroll-content">
                    <p>これはモーダル内のスクロール可能なコンテンツです。</p>
                    <p>ここをクリックしてホイールを回してみてください。</p>
                    <p>コンテンツ...</p>
                    <p>コンテンツ...</p>
                    <p>コンテンツ...</p>
                    <p>コンテンツ...</p>
                    <p>コンテンツ...</p>
                    <p>コンテンツ...</p>
                    <p>コンテンツ...</p>
                    <p>コンテンツ...</p>
                </div>
            </div>
            <button id="closeModalBtn">閉じる</button>
        </div>
    </div>

    <!-- Additional content to make the body scrollable -->
    <div class="filler-content">
        <h3>追加のコンテンツ</h3>
        <p>このセクションは、ページ全体がスクロール可能であることをテストするために追加されました。</p>
        <p>画面下の方までスクロールして、スムーズな動きを体験してください。</p>
        <p>ダミーテキスト...</p><p>ダミーテキスト...</p><p>ダミーテキスト...</p><p>ダミーテキスト...</p><p>ダミーテキスト...</p>
        <p>ダミーテキスト...</p><p>ダミーテキスト...</p><p>ダミーテキスト...</p><p>ダミーテキスト...</p><p>ダミーテキスト...</p>
        <p>ダミーテキスト...</p><p>ダミーテキスト...</p><p>ダミーテキスト...</p><p>ダミーテキスト...</p><p>ダミーテキスト...</p>
        <p>ダミーテキスト...</p><p>ダミーテキスト...</p><p>ダミーテキスト...</p><p>ダミーテキスト...</p><p>ダミーテキスト...</p>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', () => {
            let targetScrollElement = document.body;
            const scrollSpeed = 0.05;
            const scroll_size = 3;
            const animationInstances = new Map(); // マップを使用して要素ごとのアニメーションを管理

            // スムーズスクロールを実行する関数
            function smoothScroll(element, targetPosition) {
                let currentPosition = element === document.body ? window.scrollY : element.scrollTop;
                
                // 既にアニメーションが存在する場合はキャンセル
                if (animationInstances.has(element)) {
                    cancelAnimationFrame(animationInstances.get(element));
                }

                function animate() {
                    currentPosition += (targetPosition - currentPosition) * scrollSpeed;
                    
                    if (element === document.body) {
                        window.scrollTo(0, currentPosition);
                    } else {
                        element.scrollTop = currentPosition;
                    }

                    if (Math.abs(targetPosition - currentPosition) < 0.5) {
                        if (element === document.body) {
                            window.scrollTo(0, targetPosition);
                        } else {
                            element.scrollTop = targetPosition;
                        }
                        // アニメーション終了時にマップから削除
                        animationInstances.delete(element);
                        return;
                    }

                    animationInstances.set(element, requestAnimationFrame(animate));
                }
                
                // アニメーション開始
                animationInstances.set(element, requestAnimationFrame(animate));
            }

            const scrollableElements = document.querySelectorAll('.scrollable-box, .modal-body');

            scrollableElements.forEach(element => {
                element.addEventListener('mouseenter', () => {
                    targetScrollElement = element;
                    console.log("Hovered on a scrollable element:", targetScrollElement);
                });

                element.addEventListener('mouseleave', () => {
                    targetScrollElement = document.body;
                    console.log("Mouse left scrollable element. Target reset to body.");
                });
            });

            // Mouse wheel event listener
            document.addEventListener('wheel', (event) => {
                if (!targetScrollElement) return;

                event.preventDefault();
                
                // 現在のスクロール位置を正確に取得
                let currentPosition = targetScrollElement === document.body 
                    ? window.scrollY 
                    : targetScrollElement.scrollTop;

                // 新しい目標地点を計算
                let newTargetPosition = currentPosition + event.deltaY * scroll_size;
                
                const maxScrollTop = targetScrollElement === document.body 
                    ? document.documentElement.scrollHeight - window.innerHeight 
                    : targetScrollElement.scrollHeight - targetScrollElement.clientHeight;

                newTargetPosition = Math.max(0, Math.min(newTargetPosition, maxScrollTop));

                // スムーズスクロール関数を呼び出し、アニメーションを開始
                smoothScroll(targetScrollElement, newTargetPosition);

            }, { passive: false });


             // スクロールを一番上にリセットする関数
            function resetScrollPosition(element) {
                if (!element) {
                    console.error("要素が指定されていません。");
                    return;
                }
        
                // スムーズスクロールが実行中の場合はキャンセル
                if (animationInstances.has(element)) {
                    cancelAnimationFrame(animationInstances.get(element));
                    animationInstances.delete(element);
                }
                
                // スクロール位置を0に設定
                if (element === document.body) {
                    window.scrollTo(0, 0);
                } else {
                    element.scrollTop = 0;
                }
        
        
            }
            // 関数をグローバルスコープに公開
            window.resetScrollPosition = resetScrollPosition;


            // Modal-related logic
            const openModalBtn = document.getElementById('openModalBtn');
            const closeModalBtn = document.getElementById('closeModalBtn');
            const modalOverlay = document.querySelector('.modal-overlay');

            openModalBtn.addEventListener('click', () => {
                modalOverlay.style.display = 'flex';
                document.body.style.overflow = 'hidden';
            });

            closeModalBtn.addEventListener('click', () => {
                modalOverlay.style.display = 'none';
                document.body.style.overflow = '';
                targetScrollElement = document.body;
            });

            modalOverlay.addEventListener('click', (event) => {
                if (event.target === modalOverlay) {
                    closeModalBtn.click();
                }
            });
            
        });
    </script>
</body>
</html>


Discussion