Search code examples
javascripthtmlcss

How do you make an overlay div sticky relevant to a parent div that is horizontally scrollable?


Pretty much whats in the title. I am trying to make those circular buttons to be horizontal scrollable. I also would like to provide some kind of feedback to the user whether there is more to scroll to either direction, so I am trying to do it via the overlay. As of now, the overlays seem to be moving when scrolling, I would like it to stick to the sides of the circular buttons.

Here is the code I tried:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Scrollable Circular Buttons</title>
    <style>
        /* Custom styles */
        .scrollable-div {
            position: relative;
            width: 50%;
            overflow-x: auto;
            white-space: nowrap;
            padding: 10px 0; 
            margin-bottom: 20px;
            /* Hide the scrollbar */
            scrollbar-width: none;
        }
        .scrollable-div::-webkit-scrollbar {
            display: none; /* WebKit (Safari, Chrome) */
        }
        .circular-btn {
            display: inline-block;
            width: 40px;
            height: 40px;
            border-radius: 50%;
            background-color: #007bff; /* Bootstrap primary color */
            color: #fff;
            text-align: center;
            line-height: 40px;
            margin-right: 5px; /* Reduced margin */
            cursor: pointer;
            font-size: 16px;
        }
        .scroll-overlay {
            position: absolute;
            top: 0;
            bottom: 0;
            width: 50px; /* Adjust as needed */
            pointer-events: none; /* Allow clicks to pass through */
        }
        .scroll-overlay-left {
            left: 0;
            background: linear-gradient(to right, rgba(0, 0, 0, 0.5), transparent);

        }
        .scroll-overlay-right {
            right: 0;
            background: linear-gradient(to left, rgba(0, 0, 0, 0.5), transparent);

        }
        .selected {
            background-color: #28a745 !important; /* Bootstrap success color */
        }
    </style>
</head>
<body>

    <div class="scrollable-div" id="scrollableDiv">
        <!-- List of circular buttons -->
        <div class="circular-btn selected">1</div>
        <div class="circular-btn">2</div>
        <div class="circular-btn">3</div>
        <div class="circular-btn">4</div>
        <div class="circular-btn">5</div>
        <div class="circular-btn">6</div>
        <div class="circular-btn">7</div>
        <div class="circular-btn">8</div>
        <div class="circular-btn">9</div>
        <div class="circular-btn">10</div>
        <div class="circular-btn">11</div>
        <div class="circular-btn">12</div>
        <div class="circular-btn">13</div>
        <div class="circular-btn">14</div>
        <div class="circular-btn">15</div>
        <div class="circular-btn">16</div>
        <div class="circular-btn">17</div>
        <div class="circular-btn">18</div>
        <div class="circular-btn">19</div>
        <div class="circular-btn">20</div>
        <div class="circular-btn">21</div>
        <div class="circular-btn">22</div>
        <div class="circular-btn">23</div>
        <div class="circular-btn">24</div>
        <div class="circular-btn">25</div>
        <div class="circular-btn">26</div>
        <div class="circular-btn">27</div>
        <div class="circular-btn">28</div>
        <div class="circular-btn">29</div>
        <div class="circular-btn">30</div>
        <!-- Scroll overlays to indicate end of content -->
        <div class="scroll-overlay scroll-overlay-left"></div>
        <div class="scroll-overlay scroll-overlay-right"></div>
    </div>

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            const scrollableDiv = document.getElementById('scrollableDiv');
            const scrollOverlayLeft = document.querySelector('.scroll-overlay-left');
            const scrollOverlayRight = document.querySelector('.scroll-overlay-right');

        // Check scroll status on initial load
            updateOverlayVisibility();

        // Update overlay visibility based on scroll position
            scrollableDiv.addEventListener('scroll', updateOverlayVisibility);

            function updateOverlayVisibility() {
                const scrollPosition = scrollableDiv.scrollLeft;
                const scrollWidth = scrollableDiv.scrollWidth;
                overlayWidth = Math.min((scrollPosition / scrollWidth) * 50 , 50);
                scrollOverlayLeft.style.width = overlayWidth + ' px';
                scrollOverlayRight.style.width = overlayWidth + ' px';
                scrollOverlayLeft.style.display = scrollPosition > 0 ? 'block' : 'none';
                scrollOverlayRight.style.display = scrollPosition < scrollWidth ? 'block' : 'none';

            }

        // JavaScript for circular button selection
            const circularButtons = document.querySelectorAll('.circular-btn');

            circularButtons.forEach(function(btn) {
                btn.addEventListener('click', function() {
                // Remove 'selected' class from all buttons
                    circularButtons.forEach(function(btn) {
                        btn.classList.remove('selected');
                    });
                // Add 'selected' class to the clicked button
                    this.classList.add('selected');
                });
            });
        });
    </script>
</body>
</html>

Thanks!


Solution

  • You need 2 container div for this. First one which does not scroll and another which does. Your overlap will be absolute to parent one. Here is JSBIn

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Scrollable Circular Buttons</title>
        <style>
            /* Custom styles */
            .scrollable-div {
                position: relative;
                width: 50%;
                overflow-x: none;
                white-space: nowrap;
                padding: 10px 0; 
                margin-bottom: 20px;
                /* Hide the scrollbar */
                scrollbar-width: none;
            }
          .scrollable-div > div{
            overflow-x: auto;
          }
            .scrollable-div::-webkit-scrollbar {
                display: none; /* WebKit (Safari, Chrome) */
            }
            .circular-btn {
                display: inline-block;
                width: 40px;
                height: 40px;
                border-radius: 50%;
                background-color: #007bff; /* Bootstrap primary color */
                color: #fff;
                text-align: center;
                line-height: 40px;
                margin-right: 5px; /* Reduced margin */
                cursor: pointer;
                font-size: 16px;
            }
            .scroll-overlay {
                position: absolute;
                top: 0;
                bottom: 0;
                width: 50px; /* Adjust as needed */
                pointer-events: none; /* Allow clicks to pass through */
            }
            .scroll-overlay-left {
                left: 0;
                background: linear-gradient(to right, rgba(0, 0, 0, 0.5), transparent);
    
            }
            .scroll-overlay-right {
                right: 0;
                background: linear-gradient(to left, rgba(0, 0, 0, 0.5), transparent);
    
            }
            .selected {
                background-color: #28a745 !important; /* Bootstrap success color */
            }
        </style>
    </head>
    <body>
    
        <div class="scrollable-div" id="scrollableDiv">
          <div>
            <!-- List of circular buttons -->
            <div class="circular-btn selected">1</div>
            <div class="circular-btn">2</div>
            <div class="circular-btn">3</div>
            <div class="circular-btn">4</div>
            <div class="circular-btn">5</div>
            <div class="circular-btn">6</div>
            <div class="circular-btn">7</div>
            <div class="circular-btn">8</div>
            <div class="circular-btn">9</div>
            <div class="circular-btn">10</div>
            <div class="circular-btn">11</div>
            <div class="circular-btn">12</div>
            <div class="circular-btn">13</div>
            <div class="circular-btn">14</div>
            <div class="circular-btn">15</div>
            <div class="circular-btn">16</div>
            <div class="circular-btn">17</div>
            <div class="circular-btn">18</div>
            <div class="circular-btn">19</div>
            <div class="circular-btn">20</div>
            <div class="circular-btn">21</div>
            <div class="circular-btn">22</div>
            <div class="circular-btn">23</div>
            <div class="circular-btn">24</div>
            <div class="circular-btn">25</div>
            <div class="circular-btn">26</div>
            <div class="circular-btn">27</div>
            <div class="circular-btn">28</div>
            <div class="circular-btn">29</div>
            <div class="circular-btn">30</div>
            <!-- Scroll overlays to indicate end of content -->
            <div class="scroll-overlay scroll-overlay-left"></div>
            <div class="scroll-overlay scroll-overlay-right"></div>
            </div>
        </div>
    
        <script>
            document.addEventListener("DOMContentLoaded", function() {
                const scrollableDiv = document.getElementById('scrollableDiv');
                const scrollOverlayLeft = document.querySelector('.scroll-overlay-left');
                const scrollOverlayRight = document.querySelector('.scroll-overlay-right');
    
            // Check scroll status on initial load
                updateOverlayVisibility();
    
            // Update overlay visibility based on scroll position
                scrollableDiv.addEventListener('scroll', updateOverlayVisibility);
    
                function updateOverlayVisibility() {
                    const scrollPosition = scrollableDiv.scrollLeft;
                    const scrollWidth = scrollableDiv.scrollWidth;
                    overlayWidth = Math.min((scrollPosition / scrollWidth) * 50 , 50);
                    scrollOverlayLeft.style.width = overlayWidth + ' px';
                    scrollOverlayRight.style.width = overlayWidth + ' px';
                    scrollOverlayLeft.style.display = scrollPosition > 0 ? 'block' : 'none';
                    scrollOverlayRight.style.display = scrollPosition < scrollWidth ? 'block' : 'none';
    
                }
    
            // JavaScript for circular button selection
                const circularButtons = document.querySelectorAll('.circular-btn');
    
                circularButtons.forEach(function(btn) {
                    btn.addEventListener('click', function() {
                    // Remove 'selected' class from all buttons
                        circularButtons.forEach(function(btn) {
                            btn.classList.remove('selected');
                        });
                    // Add 'selected' class to the clicked button
                        this.classList.add('selected');
                    });
                });
            });
        </script>
    </body>
    </html>
    

    https://jsbin.com/nukonesidu/edit?html,output