изменение цвета ссылки в зависимости от пролистывания к якорю в закреплённом меню

как сделать, чтобы цвет ссылки менялся при прокрутке страницы к нужному якорю, меню при этом закреплено?


Ответы (3 шт):

Автор решения: Meth0d
// создаем переменную со всеми ссылками
const links = document.querySelectorAll('.links')

// навешиваем на каждую обработчик события "клик"
links.forEach(link => link.addEventListener('click', () => {
  
  // находим уже активную ссылку
  const active = document.querySelector('.link.active')

  // если она есть, снимаем с нее класс active
  active && active.classList.remove('active')

  // накидываем класс active на ту ссылку на которую мы нажали
  link.classList.add('active')

}))

соответственно так же прописываем классу active нужные стили

→ Ссылка
Автор решения: soledar10

Пример 1

const sections = document.querySelectorAll("section");
const navbarLinks = document.querySelectorAll(".navbar__link");
const navbarHeight = document.querySelector(".navbar").offsetHeight;

window.addEventListener('scroll', () => {

  let current = "";

  sections.forEach(section => {
    const sectionTop = section.offsetTop;

    if (pageYOffset >= sectionTop - navbarHeight) {
      current = section.getAttribute("id");
    }
  });

  navbarLinks.forEach(link => {
    link.classList.remove("is-active");

    if (link.classList.contains(current)) {
      link.classList.add("is-active");
    }
  });

})
* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
}

.navbar {
  position: fixed;
  top: 0;
  left: 0;
  height: 60px;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #000;
  width: 100%;
}

.navbar__link {
  padding: .5rem 1rem;
  color: #fff;
}

.navbar__link.is-active {
  color: #f00;
}

section {
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 10vw;
  background-color: #ccc;
}

section:nth-of-type(even) {
  background-color: #ddd;
}
<nav class="navbar">
  <a href="#s1" class="navbar__link s1 is-active">Link 1</a>
  <a href="#s2" class="navbar__link s2">Link 2</a>
  <a href="#s3" class="navbar__link s3">Link 3</a>
  <a href="#s4" class="navbar__link s4">Link 4</a>
</nav>

<section id="s1">Section 1</section>
<section id="s2">Section 2</section>
<section id="s3">Section 3</section>
<section id="s4">Section 4</section>

<footer>Footer</footer>

Пример 2

window.addEventListener('DOMContentLoaded', () => {

  const observerCallback = (entries, observer) => {
    entries.forEach((entry) => {
      if (entry.isIntersecting && entry.intersectionRatio >= .5) {
        document.querySelector('.is-active').classList.remove('is-active');
        const id = entry.target.getAttribute("id");
        const newLink = document.querySelector('[href="#' + id + '"]').classList.add('is-active');
      }
    });
  };

  const options = {
    threshold: .5,
  };

  const observer = new IntersectionObserver(observerCallback, options);

  const sections = document.querySelectorAll('section');
  sections.forEach((section) => observer.observe(section));

});
* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
}

.navbar {
  position: fixed;
  top: 0;
  left: 0;
  height: 60px;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #000;
  width: 100%;
}

.navbar__link {
  padding: .5rem 1rem;
  color: #fff;
}

.navbar__link.is-active {
  color: #f00;
}

section {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 10vw;
  background-color: #ccc;
}

section:nth-of-type(even) {
  background-color: #ddd;
}
<nav class="navbar">
  <a href="#s1" class="navbar__link is-active">Link 1</a>
  <a href="#s2" class="navbar__link">Link 2</a>
  <a href="#s3" class="navbar__link">Link 3</a>
  <a href="#s4" class="navbar__link">Link 4</a>
</nav>

<section id="s1">Section 1</section>
<section id="s2">Section 2</section>
<section id="s3">Section 3</section>
<section id="s4">Section 4</section>

<footer>Footer</footer>

→ Ссылка
Автор решения: puffleeck

#ody{
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
}
.y{
border: 1px solid green;
grid-row: 1;
}
.y:nth-child(1){grid-column: 1;}
.y:nth-child(2){grid-column: 2;}
.y:nth-child(3){grid-column: 3;}
.y:nth-child(4){grid-column: 4;}

.y:after{
content: 'xyz';
position: fixed;
}

:target ~ .y{color: red}
.x{
grid-column: 1 / 5;
border: 1px solid violet;
height: 100vh;
}
<b id='ody'>
<div id='div1' class='x'>aaaa</div>
<a href='#div1' class='y'>a1</a>

<div id='div2' class='x'>aaaa</div>
<a href='#div2' class='y'>a2</a>

<div id='div3' class='x'>aaaa</div>
<a href='#div3' class='y'>a3</a>

<div id='div4' class='x'>aaaa</div>
<a href='#div4' class='y'>a4</a>
</b>

осталось только слушалку скрола повесить с подменой хэша(location.hash \ history.hash)

правда так порядок пунктов меню не самый адекватный получается, но всё таки...

→ Ссылка