스크롤 위치에 따라 marker가 움직이는 내비게이션

soyeon·2021년 12월 27일
0

TIL

목록 보기
3/32
post-thumbnail
post-custom-banner

👻서론


(포트폴리오에 들어간 내비게이션)
깔끔하면서도 역동적인(?) 내비게이션 효과를 만들고 싶어서 유튭 강의와 코드펜에 올라온 코드들을 참고해서 만들었습니다.

TIL용으로 코드펜에 바닐라JS로 심플하게 정리했습니다.

코드펜에 작성한 내용을 바탕으로 설명드리겠습니다!

👻HTML 작성

    <nav id="nav" class="nav">
        <ul class="nav__menu">
            <li><a href="#one"class="nav__menu--foused">ONE</a></li>
            <li><a href="#two">TWO</a></li>
            <li><a href="#three">THREE</a></li>
            <li><a href="#four">FOUR</a></li>
            <div class="marker"></div>
        </ul>
    </nav>
    <section id="one">one</section>
    <section id="two">two</section>
    <section id="three">three</section>
    <section id="four">four</section>

nav를 만들어서 안에 메뉴를 집어넣어주고 href를 해당 섹션의 id 값으로 설정해줍니다.
marker도 만들어 주시는 거 잊지말기!

👻CSS

너무 길어서 marker 부분만 정리...

.marker {
  content: "";
  position: absolute;
  bottom: 1.2rem;
  left: 50%;
  width: 0%;
  height: 3px;
  background-color: purple;
  transition: 0.2s;
}

width와 left는 javaScript에서 설정하는 부분입니다.
스크롤을 하면 보이는 설정이기 때문에 width를 0으로 했습니다.
left는 왜 50%로 했냐
새로고침을 했을 때 nav의 왼쪽 끝에서 marker가 달려오는 것보다 가운데에서 달려오는 게 좀 더 멋있기때문입니다.
취향대로 하시면 됩니다.

👻javaScript

marker의 위치와 길이를 설정하는 함수

const marker=document.querySelector(".marker");
function setMarker(e) {
    marker.style.left = e.offsetLeft+"px";
    marker.style.width = e.offsetWidth+"px";
}
  • marker의 위치 = 각 메뉴의 위치
  • marker의 길이 = 각 메뉴의 길이

좌표 구하는 프로퍼티는 항상 헷갈려서 그림으로 그려왔습니다.

스크롤 이벤트

현재 영역의 id 값을 구하기

const sections = document.querySelectorAll("section");
const menus = document.querySelectorAll(".nav__menu > li > a")

window.addEventListener("scroll",()=>{
  //현재 영역의 id 값
    let current=""

    sections.forEach(section=>{
        //각 section의 top 위치(절대적 위치)
        // The top of each section (absolute)
        const sectionTop = window.scrollY + section.getBoundingClientRect().top;
      
      //누적된 스크롤이 section의 top위치에 도달했거나 section의 안에 위치할 경우
        if(window.scrollY >= sectionTop) {
           current = section.getAttribute("id");
        }

})
  1. current라는 변수를 만들어줍니다. 여기에 현재 스크롤이 있는 영역의 id 값을 저장해줄 겁니다.
  2. forEach 메소드를 이용해 sections의 각 section의 좌표를 구해줍니다.
    이것도 그림을 그려왔습니다.
  3. 현재 스크롤이 sectionTop보다 작으면 아직 section에 도달하지 못한 상태고,
    sectionTop보다 같거나 크면 해당 section까지 스크롤이 내려갔다는 뜻입니다.
    이를 이용해서 if문 조건을 써주고 현재 섹션의 id 값을 current에 저장해줍니다.

element.getBoundingClientRect()에 대한 설명은 이쪽으로

영역과 해당하는 메뉴에 marker 이동시키기

        menus.forEach(menu=>{
            menu.classList.remove("nav__menu--foused");
            const href = menu.getAttribute("href").substring(1);
            if(href===current) {
                //현재 있는 영역의 id와 메뉴의 링크주소가 일치할때
                //When the Id of the current section matches the href of the menu
                menu.classList.add("nav__menu--foused");
                setMarker(menu);
            }
        })
  1. forEach를 이용해 menus 안의 각 menu에 함수를 적용합니다.
  2. 먼저 글자색을 바꿔주는 class를 지워주고 (글자색 중복 방지)
  3. menu의 href를 가져옵니다. 이 때 substring을 쓰는 이유는 href가 #○○○ 형식으로 되어있기 때문에 #를 제외하기 위해서입니다.
  4. if: 현재 영역의 id와 메뉴의 링크 주소가 일치하는 경우
    그 메뉴에만 글자색을 바꿔주는 class를 추가하고, 위에서 작성했던 marker의 위치(left), 너비(width)를 지정하는 함수를 호출합니다.

끝!!

👻마치며(홍보)

marker가 움직이는 내비게이션을 적용한 포트폴리오 페이지가 궁금하시다면
https://soonmac.github.io/portfolio_page/ 이쪽으로 방문해주세요!

profile
공부중
post-custom-banner

0개의 댓글