javascriptjs-scrollto

window.scrollTo issue with position fixed menu


I'm looking for some help about a fixed position menu on my project.

When I'm scrolling down, my click events don't work anymore. Instead of scrolling smoothly in the right section, my menu is repositioned on top after clicking on the links.

For information, the links work perfectly when my menu is on his default position.

Does anyone know where the problem is ?

const arr = ['home', 'about', 'services', 'tours'];
const containerArticles = document.querySelector('.container-articles');
const containerNav = document.querySelector('.nav');
const links = document.querySelectorAll('.nav-links > li > a');

const getArticles = arr.map(item => {
    return `    <article data-id=${item}>
    <h1>${item}</h1>
</article>
`;
});

containerArticles.innerHTML = getArticles.join('');


// Select all the links
for (let link of links) {
    link.addEventListener('click', e => {
        const target = e.target;

        for (let article of document.querySelectorAll('article')) {
            if (target.textContent == article.dataset.id) {

                window.scrollTo({
                    top: article.getBoundingClientRect().top - containerNav.offsetHeight,
                    left: 0,
                    behavior: 'smooth'
                });
            }
        }
    });
}

// Scrolling event
window.addEventListener('scroll', (e) => {
    if (pageYOffset > containerNav.offsetHeight) {
        containerNav.classList.add('nav-sticky');
    } else {
        containerNav.classList.remove('nav-sticky');
    }
});
*,
::after,
::before {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

header {
    position: relative;
    min-height: 100vh;
    background-color: antiquewhite;
    background: url('img/mountain.jpeg') center/cover no-repeat;
    display: flex;
    flex-wrap: wrap;
    align-items: start;
    justify-content: center;
}

header::after {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    width: 100%;
    background-color: rgba(8, 126, 88, 0.5);
}

.nav {
    position: fixed;
    top: 0;
    width: 100%;
    height: 50px;
    background-color: aliceblue;
    display: flex;
    justify-content: end;
    align-items: center;
    padding: 1rem;
    transition: 0.4s;
    z-index: 999;

}

.nav-sticky {
    height: 60px;
    background-color: white;
    justify-content: center;
}

.nav ul {
    list-style-type: none;
}

.nav ul li {
    display: inline-block;
    padding-left: 1rem;
    padding-right: 1rem;
}

.header-container {
    align-self: center;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    width: 50%;
    z-index: 1;
}

.header-title,
.header-desc {
    text-align: center;
    color: white;
}

.header-title {
    margin-bottom: 1rem;
}

.header-desc {
    margin-top: 1rem;
    margin-bottom: 1rem;
    letter-spacing: 1px;
    line-height: 20px;
}

.btn-explore {
    margin-top: 1rem;
    width: 110px;
    height: 40px;
    border: 1px solid white;
    background-color: transparent;
    color: white;
    font-weight: 900;
    border-radius: 10px;
    cursor: pointer;
}

article {
    min-height: 90vh;
    background-color: aliceblue;
}

article h1 {
    text-align: center;
    text-transform: uppercase;
}
<body>
<header>
    <nav class="nav">
        <ul class="nav-links">
            <li><a href="#">home</a></li>
            <li><a href="#">about</a></li>
            <li><a href="#">services</a></li>
            <li><a href="#">tours</a></li>
        </ul>
    </nav>
    <div class="header-container">
        <h1 class="header-title">Scroll Project</h1>
        <p class="header-desc">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Vero sed tempore ipsam distinctio delectus doloribus excepturi quidem eum ratione doloremque.</p>
        <button class="btn-explore">Explore Tours</button>
    </div>
</header>
<section class="container-articles">
    <article>
        <h1></h1>
    </article>
</section>
</body>


Solution

  • 1. You need to modify your window.scrollTo to add the current y-position of the vertical scrollbar to your elements bounding rectangle top value then subtract the navbar height, since your bounding rectangle top value will change relative to the visible part of the window, ie. your top becomes close to zero when scrolled into view.

    2. The # in your href's was causing the page to reload on click, so I stopped this by using event.preventDefault() in your click handler.

    const arr = ['home', 'about', 'services', 'tours'];
    const containerArticles = document.querySelector('.container-articles');
    const containerNav = document.querySelector('.nav');
    const links = document.querySelectorAll('.nav-links > li > a');
    
    const getArticles = arr.map(item => {
        return `    <article data-id=${item}>
        <h1>${item}</h1>
    </article>
    `;
    });
    
    containerArticles.innerHTML = getArticles.join('');
    
    
    // Select all the links
    for (let link of links) {
        link.addEventListener('click', e => {
            //***added preventDefault() to stop the anchor from reloading the page***
            e.preventDefault();
            const target = e.target;
    
            for (let article of document.querySelectorAll('article')) {
                if (target.textContent == article.dataset.id) {
                    //***added the value of window.scrollY to the article's top***
                    window.scrollTo({
                        top: (article.getBoundingClientRect().top + window.scrollY) - containerNav.offsetHeight,
                        left: 0,
                        behavior: 'smooth'
                    });
                }
            }
        });
    }
    
    // Scrolling event
    window.addEventListener('scroll', (e) => {
        if (pageYOffset > containerNav.offsetHeight) {
            containerNav.classList.add('nav-sticky');
        } else {
            containerNav.classList.remove('nav-sticky');
        }
    });
    *,
    ::after,
    ::before {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }
    
    header {
        position: relative;
        min-height: 100vh;
        background-color: antiquewhite;
        background: url('img/mountain.jpeg') center/cover no-repeat;
        display: flex;
        flex-wrap: wrap;
        align-items: start;
        justify-content: center;
    }
    
    header::after {
        content: '';
        position: absolute;
        top: 0;
        left: 0;
        height: 100%;
        width: 100%;
        background-color: rgba(8, 126, 88, 0.5);
    }
    
    .nav {
        position: fixed;
        top: 0;
        width: 100%;
        height: 50px;
        background-color: aliceblue;
        display: flex;
        justify-content: end;
        align-items: center;
        padding: 1rem;
        transition: 0.4s;
        z-index: 999;
    
    }
    
    .nav-sticky {
        height: 60px;
        background-color: white;
        justify-content: center;
    }
    
    .nav ul {
        list-style-type: none;
    }
    
    .nav ul li {
        display: inline-block;
        padding-left: 1rem;
        padding-right: 1rem;
    }
    
    .header-container {
        align-self: center;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        width: 50%;
        z-index: 1;
    }
    
    .header-title,
    .header-desc {
        text-align: center;
        color: white;
    }
    
    .header-title {
        margin-bottom: 1rem;
    }
    
    .header-desc {
        margin-top: 1rem;
        margin-bottom: 1rem;
        letter-spacing: 1px;
        line-height: 20px;
    }
    
    .btn-explore {
        margin-top: 1rem;
        width: 110px;
        height: 40px;
        border: 1px solid white;
        background-color: transparent;
        color: white;
        font-weight: 900;
        border-radius: 10px;
        cursor: pointer;
    }
    
    article {
        min-height: 90vh;
        background-color: aliceblue;
    }
    
    article h1 {
        text-align: center;
        text-transform: uppercase;
    }
    <body>
    <header>
        <nav class="nav">
            <ul class="nav-links">
                <li><a href="#">home</a></li>
                <li><a href="#">about</a></li>
                <li><a href="#">services</a></li>
                <li><a href="#">tours</a></li>
            </ul>
        </nav>
        <div class="header-container">
            <h1 class="header-title">Scroll Project</h1>
            <p class="header-desc">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Vero sed tempore ipsam distinctio delectus doloribus excepturi quidem eum ratione doloremque.</p>
            <button class="btn-explore">Explore Tours</button>
        </div>
    </header>
    <section class="container-articles">
        <article>
            <h1></h1>
        </article>
    </section>
    </body>