DOM 을 보다 잘! 활용하기 위해, 익숙해지기 위해 컨텐츠 영역을 스크롤 했을 때 해당 id 가 나타나게 되면 해당 id 와 매칭되어 있는 목차에 하이라이팅이 되는 기능을 구현해보고자 하였다.

📝 요구 사항
- 현재 목차에는 href 속성으로 id 가 달려 있고 컨텐츠 영역에 id 들이 달려 있어 매칭이 되어 있으나 스크롤 시나 해당 위치로 이동했을 때 목차에 하이라이팅이 되지 않는다.
- DOM을 활용하여, 스크롤이 되었을 때 해당 목차의 색상을 변경하도록 할 것이다.
- 해당 id가 달려있는 element의 스크롤 위치가 상단 기준 80px로 도달 하였을 때 해당 목차를 하이라이팅 할 것이다.
- 먼저 DOM 요소를 찾기 위해 개발자 도구를 켜서 목차와 컨텐츠 영역에 id 가 어떤 클래스에서, 어떤 태그에서 어떻게 매칭되어 있는지 확인했다.
✅ document.querySelectorAll() : 해당 아이디를 가진 dom 요소를 찾는다. - 이후 리스트에 컨텐츠 영역의 id 를 넣고 forEach 를 사용하여 “element의 스크롤 위치가 상단 기준 80px로 도달 하였을 때” 라는 조건일 때 목차에 하이라이팅이 되도록 하였다.
✅ getBoundingClientRect() : 요소의 크기와 현재 뷰포트에서의 요소의 상대적인 위치 정보를 반환하는 메서드이다.
🚨 이슈 발생
1. 코드를 잘 작성하여 console 에 붙여 넣었는데 아무 일도 일어나지 않았다. 처음에는 리스트에 컨텐츠 영역의 id 를 넣을 때 잘못 가져와서 넣어서 그런가 하고 class 에서도 가져와 보고 다양한 시도를 해보았지만 역시나 아무 일도 일어나지 않았다. 보니까, scroll event 가 아예 일어나지 않고 있었다.
=> 왜 내 코드가 적용되지 않았을까?
바로 스크롤이 냅다 페이지 전체에 적용되고 있던 것이 아니라 “.whitepaper_wrapper” 클래스를 가진 별도의 요소 안에서만 스크롤이 시작되고 있었기 때문이다.
아래와 같이 문서 내에서 첫 번째로 해당 클래스를 가진 요소를 찾아 레이아웃으로 지정해주고, 그 요소가 발견되었을 때 scroll event 가 일어나도록 했다. addEvenvListener 에 바로 docoment.querySelector 을 해주면 scroll 이 일어날 때마다 실행되기 때문에 따로 지정해줬다.
const contentLayout = document.querySelector(".whitepaper_wrapper");
...
contentLayout.addEventListener("scroll", highlightOnScroll);
2. 이제 목차가 하이라이팅 되긴 하는데, 1 번 목차가 하이라이팅 되고 스크롤을 내려서 2 번 목차가 하이라이팅 되었을 때 1 번은 원래대로 돌아와야 하는데 그대로 있는 사건이 발생했다. 4 번 목차 까지 스크롤을 내렸을 때는 1,2,3,4 모두 하이라이팅 되어 있고 원래 색으로 돌아오지 않았다.
=> 아예 원래 색으로 돌아오지 않는 것은 아니고 스크롤을 다시 위로 올리면 “상단 기준 80px로 도달 하였을 때” 조건을 만족하지 않아 원래대로 돌아왔다. 그렇다면 조건 문제인가? 이리저리 조건을 수정해보다가 되지 않아 결국 higlightenIndesId 를 만들어서 현재 하이라이팅 된 id 와 이전에 하이라이팅 된 prevHighlightedIndex 를 구분하기로 했다.
- 괜히 getBoundingClientRect().bottom ≥ 0 같은 요상한 조건을 시도하고 있었는데 해당 조건의 존재 이유는 단지 “콘텐츠 영역 헤더의 상단 기준 80px로 도달 하였을 때 해당 목차를 하이라이팅 할 것이다.” 라는 이유이기 때문에 이 조건 수정은 의미가 없었다.
let highlightedIndexId = null;
if (correspondingIndex && heading.getBoundingClientRect().top <= 80) {
if (highlightedIndexId !== targetId) {
if (highlightedIndexId) {
const prevHighlightedIndex = document.querySelector(
`a[href="#${highlightedIndexId}"]`
);
if (prevHighlightedIndex) {
prevHighlightedIndex.style.color = "";
}
}
correspondingIndex.style.color = "#6119D1";
highlightedIndexId = targetId;
}
}
});
3. 처음에 컨텐츠 영역의 id 를 가져올 때는 다음과 같이 해당 페이지의 모든 h2 태그의 id 를 가져왔는데 h2에 다른 id가 들어가 있을 경우 문제가 될 수 있음을 알았다.
=> 해결 방법으로는 forEach 를 돌릴 때 다른 id 가 있을 수 없는 목차의 id 로 돌리거나, 예외 처리를 해주는 방법이 있다.
나는 h2 태그 말고 class 에서 id 를 가져오는 방법을 택했다.
const headings = document.querySelectorAll("h2[id]");
// 이 코드를 아래와 같이 바꿔주었다.
const headingClass = "heading";
const headings = document.querySelectorAll(`.${headingClass}`);
🥳 🥳 🥳
💻 전체 코드
let highlightedLinkId = null;
function highlightOnScroll() {
const headings = document.querySelectaorAll("h2[id]");
headings.forEach((heading) => {
const targetId = heading.id;
const correspondingLink = document.querySelector(`a[href="#${targetId}"]`);
if (
correspondingLink &&
heading.getBoundingClientRect().top <= 80
) {
if (highlightedLinkId !== targetId) {
if (highlightedLinkId) {
const prevHighlightedLink = document.querySelector(
`a[href="#${highlightedLinkId}"]`
);
if (prevHighlightedLink) {
prevHighlightedLink.style.color = "";
}
}
correspondingLink.style.color = "#6119D1";
highlightedLinkId = targetId;
}
}
});
}
document
.querySelector(".whitepaper_wrapper")
.addEventListener("scroll", highlightOnScroll);
이렇게 스크롤에 따른 목차 하이라이트를 만들어보았다.
간단한 문제였음에도 깔끔하고 신속하게 해결하지 못했고 여러 블로그들을 따라하면서 어떻게든 구현해낸 것에 가깝지만 많은 시도를 해볼 수 있었다.아직도 내가 맞게 했는지 잘 모르겠고 글을 작성하면서도 이게 이거던가? 하고 헷갈리기도 했지만 그러니까 이렇게 글로 작성해 보아야 한다고 생각한다. 더 하다보면 잘할 수 있을 거라고 생각한다. 🥲
'주제 업슴' 카테고리의 다른 글
[빅데이터 최신 기술] ADHD 관련 텍스트 마이닝: 키워드 네트워크와 감정 흐름 기반 분석 - 1 (0) | 2025.03.26 |
---|---|
Jest 로 프론트엔드 테스트 코드 작성하기 (0) | 2025.02.18 |
Git 브랜치 전략 (0) | 2024.07.07 |
[모각코] 컴퓨터 네트워크 혼내주기 2 🍕 (0) | 2024.05.29 |
[모각코] 컴퓨터 네트워크 혼내주기 🍕 (2) | 2024.05.22 |
DOM 을 보다 잘! 활용하기 위해, 익숙해지기 위해 컨텐츠 영역을 스크롤 했을 때 해당 id 가 나타나게 되면 해당 id 와 매칭되어 있는 목차에 하이라이팅이 되는 기능을 구현해보고자 하였다.

📝 요구 사항
- 현재 목차에는 href 속성으로 id 가 달려 있고 컨텐츠 영역에 id 들이 달려 있어 매칭이 되어 있으나 스크롤 시나 해당 위치로 이동했을 때 목차에 하이라이팅이 되지 않는다.
- DOM을 활용하여, 스크롤이 되었을 때 해당 목차의 색상을 변경하도록 할 것이다.
- 해당 id가 달려있는 element의 스크롤 위치가 상단 기준 80px로 도달 하였을 때 해당 목차를 하이라이팅 할 것이다.
- 먼저 DOM 요소를 찾기 위해 개발자 도구를 켜서 목차와 컨텐츠 영역에 id 가 어떤 클래스에서, 어떤 태그에서 어떻게 매칭되어 있는지 확인했다.
✅ document.querySelectorAll() : 해당 아이디를 가진 dom 요소를 찾는다. - 이후 리스트에 컨텐츠 영역의 id 를 넣고 forEach 를 사용하여 “element의 스크롤 위치가 상단 기준 80px로 도달 하였을 때” 라는 조건일 때 목차에 하이라이팅이 되도록 하였다.
✅ getBoundingClientRect() : 요소의 크기와 현재 뷰포트에서의 요소의 상대적인 위치 정보를 반환하는 메서드이다.
🚨 이슈 발생
1. 코드를 잘 작성하여 console 에 붙여 넣었는데 아무 일도 일어나지 않았다. 처음에는 리스트에 컨텐츠 영역의 id 를 넣을 때 잘못 가져와서 넣어서 그런가 하고 class 에서도 가져와 보고 다양한 시도를 해보았지만 역시나 아무 일도 일어나지 않았다. 보니까, scroll event 가 아예 일어나지 않고 있었다.
=> 왜 내 코드가 적용되지 않았을까?
바로 스크롤이 냅다 페이지 전체에 적용되고 있던 것이 아니라 “.whitepaper_wrapper” 클래스를 가진 별도의 요소 안에서만 스크롤이 시작되고 있었기 때문이다.
아래와 같이 문서 내에서 첫 번째로 해당 클래스를 가진 요소를 찾아 레이아웃으로 지정해주고, 그 요소가 발견되었을 때 scroll event 가 일어나도록 했다. addEvenvListener 에 바로 docoment.querySelector 을 해주면 scroll 이 일어날 때마다 실행되기 때문에 따로 지정해줬다.
const contentLayout = document.querySelector(".whitepaper_wrapper");
...
contentLayout.addEventListener("scroll", highlightOnScroll);
2. 이제 목차가 하이라이팅 되긴 하는데, 1 번 목차가 하이라이팅 되고 스크롤을 내려서 2 번 목차가 하이라이팅 되었을 때 1 번은 원래대로 돌아와야 하는데 그대로 있는 사건이 발생했다. 4 번 목차 까지 스크롤을 내렸을 때는 1,2,3,4 모두 하이라이팅 되어 있고 원래 색으로 돌아오지 않았다.
=> 아예 원래 색으로 돌아오지 않는 것은 아니고 스크롤을 다시 위로 올리면 “상단 기준 80px로 도달 하였을 때” 조건을 만족하지 않아 원래대로 돌아왔다. 그렇다면 조건 문제인가? 이리저리 조건을 수정해보다가 되지 않아 결국 higlightenIndesId 를 만들어서 현재 하이라이팅 된 id 와 이전에 하이라이팅 된 prevHighlightedIndex 를 구분하기로 했다.
- 괜히 getBoundingClientRect().bottom ≥ 0 같은 요상한 조건을 시도하고 있었는데 해당 조건의 존재 이유는 단지 “콘텐츠 영역 헤더의 상단 기준 80px로 도달 하였을 때 해당 목차를 하이라이팅 할 것이다.” 라는 이유이기 때문에 이 조건 수정은 의미가 없었다.
let highlightedIndexId = null;
if (correspondingIndex && heading.getBoundingClientRect().top <= 80) {
if (highlightedIndexId !== targetId) {
if (highlightedIndexId) {
const prevHighlightedIndex = document.querySelector(
`a[href="#${highlightedIndexId}"]`
);
if (prevHighlightedIndex) {
prevHighlightedIndex.style.color = "";
}
}
correspondingIndex.style.color = "#6119D1";
highlightedIndexId = targetId;
}
}
});
3. 처음에 컨텐츠 영역의 id 를 가져올 때는 다음과 같이 해당 페이지의 모든 h2 태그의 id 를 가져왔는데 h2에 다른 id가 들어가 있을 경우 문제가 될 수 있음을 알았다.
=> 해결 방법으로는 forEach 를 돌릴 때 다른 id 가 있을 수 없는 목차의 id 로 돌리거나, 예외 처리를 해주는 방법이 있다.
나는 h2 태그 말고 class 에서 id 를 가져오는 방법을 택했다.
const headings = document.querySelectorAll("h2[id]");
// 이 코드를 아래와 같이 바꿔주었다.
const headingClass = "heading";
const headings = document.querySelectorAll(`.${headingClass}`);
🥳 🥳 🥳
💻 전체 코드
let highlightedLinkId = null;
function highlightOnScroll() {
const headings = document.querySelectaorAll("h2[id]");
headings.forEach((heading) => {
const targetId = heading.id;
const correspondingLink = document.querySelector(`a[href="#${targetId}"]`);
if (
correspondingLink &&
heading.getBoundingClientRect().top <= 80
) {
if (highlightedLinkId !== targetId) {
if (highlightedLinkId) {
const prevHighlightedLink = document.querySelector(
`a[href="#${highlightedLinkId}"]`
);
if (prevHighlightedLink) {
prevHighlightedLink.style.color = "";
}
}
correspondingLink.style.color = "#6119D1";
highlightedLinkId = targetId;
}
}
});
}
document
.querySelector(".whitepaper_wrapper")
.addEventListener("scroll", highlightOnScroll);
이렇게 스크롤에 따른 목차 하이라이트를 만들어보았다.
간단한 문제였음에도 깔끔하고 신속하게 해결하지 못했고 여러 블로그들을 따라하면서 어떻게든 구현해낸 것에 가깝지만 많은 시도를 해볼 수 있었다.아직도 내가 맞게 했는지 잘 모르겠고 글을 작성하면서도 이게 이거던가? 하고 헷갈리기도 했지만 그러니까 이렇게 글로 작성해 보아야 한다고 생각한다. 더 하다보면 잘할 수 있을 거라고 생각한다. 🥲
'주제 업슴' 카테고리의 다른 글
[빅데이터 최신 기술] ADHD 관련 텍스트 마이닝: 키워드 네트워크와 감정 흐름 기반 분석 - 1 (0) | 2025.03.26 |
---|---|
Jest 로 프론트엔드 테스트 코드 작성하기 (0) | 2025.02.18 |
Git 브랜치 전략 (0) | 2024.07.07 |
[모각코] 컴퓨터 네트워크 혼내주기 2 🍕 (0) | 2024.05.29 |
[모각코] 컴퓨터 네트워크 혼내주기 🍕 (2) | 2024.05.22 |