2025. 12. 3. 13:18ㆍ개발/fe
1. 브라우저가 실제로 느려지는 기준(실제 현업 경험 기반)
아래는 Chrome·Safari·Firefox 공통적으로 널리 받아들여지는 DOM 규모 기준이다.
DOM 노드 개수 기준
DOM 노드 수 체감 성능 설명
| 0 ~ 1,500개 | 매우 빠름 | 거의 모든 상황에서 문제 없음 |
| 1,500 ~ 3,000개 | 대체로 빠름 | 스타일 복잡하면 느려질 수 있음 |
| 3,000 ~ 10,000개 | 주의 필요 | 스크롤 시 프레임 드랍 시작 |
| 10,000 ~ 50,000개 | 느려짐 | 레이아웃 계산과 페인트에 랙 발생 |
| 50,000개 이상 | 매우 느려짐 | 가상화 없이는 실사용 불가 |
※ “div 개수”가 아니라 “DOM 전체 노드” 기준임
(각 div 안에 span, text node 등이 있으면 실제 노드는 훨씬 많아짐)
2. 리스트/테이블 같은 반복 요소에서의 기준
리스트 렌더링의 경우에는 다음이 더 Practical한 기준이다.
스크롤 가능한 UI에서의 가상화 필요 기준
DOM 항목 수 가상화 필요 여부
| 0 ~ 200개 | 불필요 |
| 200 ~ 500개 | 조건부 필요. 애니메이션/반응형 레이아웃 사용 시 가상화 권장 |
| 500 ~ 2,000개 | 대부분 가상화 필요 |
| 2,000개 이상 | 무조건 가상화해야 함 |
React·Vue 기반 앱에서도 동일하며, React Window/Virtualized 등이 바로 이 기준을 근거로 만들어진 것.
3. 왜 느려지는가 (Chrome 기준 성능 병목 요소)
Chrome의 렌더링 파이프라인에서 느려지는 구간은 아래와 같다.
- 스타일 계산 (Style Recalc)
- DOM 노드 수와 CSS 복잡도에 비례해 증가한다.
- 레이아웃(Layout / Reflow)
- 부모-자식 전체 트리를 다시 계산해야 해서 트리 크기에 민감하다.
- 페인팅(Paint) + 컴포지팅
- 영역이 많아지고 오버플로우/스크롤/섀도우 등이 많을수록 느려진다.
즉, 단순히 div 개수만 문제가 아니라:
- CSS depth
- flex / grid 사용 여부
- shadowDom 여부
- resize 발생 빈도
- 스크롤 시 repaint 영역
등이 모두 영향을 준다.
4. “가상화 적용해야 하는 기준” 결론
가상화(virtual scrolling, windowing)를 적용해야 할 판단 기준을 요약하면 다음과 같다.
✔ 반드시 가상화해야 하는 상황
- 리스트 항목이 500개 이상
- DOM 노드가 총 10,000개 이상
- “스크롤 시 렉”이 발생
- 테이블 컬럼/로우가 동적으로 늘어나는 UI
- 모바일 사양 고려해야 할 때
✔ 고려할 필요 없는 상황
- 화면 전체 DOM이 1,500개 이하
- 항상 고정된 UI(리스트 스크롤 없음)
- 애니메이션, sticky header, infinite scroll 등 기능이 없는 단순 렌더링
5. 추천 실무 가이드라인
- 스크롤 되는 리스트라면
→ 100개 이하면 가상화 불필요,
→ 300개 넘어가면 무조건 가상화 고려 - DOM 전체 노드 수가
→ 3,000개 넘어가면 성능 점검,
→ 10,000개 넘어가면 반드시 최적화 필요 - Lighthouse 성능 점수 기준
- “Large DOM” 경고가 뜨면 노드 수가 약 1,400개 이상이라는 의미
갯수 확인 방법
Chrome DevTools에서 DOM 노드 개수를 직접 확인하는 가장 신뢰성 높은 방법을 정리해준다. 실무에서 성능 체크할 때 흔히 쓰는 방식들이다.
1. Chrome DevTools → Performance 패널로 측정
가장 정확하고 권장되는 방법.
방법
- Chrome DevTools 열기 (F12)
- 상단 탭에서 Performance 선택
- Record 버튼 클릭
- 페이지를 스크롤하거나 문제 구간을 재현
- Record 중지
- 하단에 Summary → DOM Nodes 확인
장점
- 전체 DOM 노드 수 확인 가능
- GC 후 살아남은 노드 개수(Live DOM Nodes)도 확인 가능 → 메모리 누수 분석에 중요
- 스크립트·레이아웃·페인트까지 트리거 원인을 종합 분석 가능
2. Memory 패널 → Heap Snapshot에서 확인
대규모 페이지 진단할 때 유용.
방법
- DevTools → Memory
- Take Heap Snapshot
- 생성된 Snapshot에서 Summary 뷰 선택
- HTMLDivElement / Node / Element 기반으로 개수 확인 가능
장점
- div, span, li 등 개별 노드 타입별 개수 확인 가능
- “Detached DOM Nodes”도 보여줘서 메모리 누수 감지 가능
3. 콘솔에서 JavaScript로 직접 DOM 노드 수 계산
빠르게 보는 간단한 방법.
방법 A) 전체 노드 수(모든 element)
document.getElementsByTagName('*').length
방법 B) 특정 태그만
document.querySelectorAll('div').length
방법 C) Text node 포함한 전체 노드 수
(function count(node) {
let total = 1;
node.childNodes.forEach(n => total += count(n));
return total;
})(document.body)
장점
- 가장 빠르고 단순
- 특정 섹션별 DOM 수 확인 가능
- 스크롤 이벤트 중에 실시간 측정도 가능
4. Chrome DevTools → Elements → “DOM Breakpoints” 사용
직접 개수를 보여주진 않지만, 노드 추가/삭제를 추적할 수 있어 DOM 증가 패턴 분석에 유용.
사용법
- Elements 패널에서 body 또는 특정 컨테이너 선택
- 우클릭 → Break on → Subtree modifications
- 변경 시점에서 call stack 추적 가능
장점
- 의도치 않은 DOM 폭증 문제 디버깅에 적합
- 프레임워크 이슈(React useEffect 중복 실행 등) 찾는 데 좋음
5. Lighthouse 성능 점검
"Avoid large DOM size" 경고로 DOM 노드 수(대략 1,400개 이상임)를 알려줌.
방법
- DevTools → Lighthouse
- Performance → Generate Report
- Avoid large DOM size 항목 확인
추천 실무 팁
- 2000개 이상이면 성능 점검 필요
- 5000~10000개는 레이아웃 리플로우에 영향
- 10000개 이상은 가상화(Windowing) 고려 필수
DOM 크기가 커질 때 발생하는 주요 성능 문제
DOM이 커질수록 다음 작업 비용이 증가한다:
1) 스타일 계산(style recalc)
CSS 선택자가 깊어질수록 재계산 비용 증가
특히 div div div input[type="checkbox"] 같은 깊은 selector 사용 시 더 악화됨
2) 레이아웃(Reflow)
부모 → 자식 트리를 전체 순회하므로, 트리 깊이가 성능에 직접 영향
3) 페인트(Paint)
요소 수가 많거나 clipping/scroll 영역이 많으면 paint 시간이 증가
4) 메모리 증가
DOM 객체 자체가 일정 메모리를 사용
3. DOM 크기 최적화 전략 (실제 적용 가능한 항목 위주)
✔ 1) DOM 깊이 완화: Nesting 줄이기
현재 깊이 21은 웹 페이지 기준으로 꽤 깊다.
개선 방향
- 불필요한 <div> 래퍼 제거
- 스타일링 목적의 중첩 div → CSS Grid/Flexbox 로 구조 간소화
- 의미 없는 wrapper 요소 제거 (예: .container > .inner > .wrapper 구조)
체크 예시
문제 있는 패턴:
<div>
<div>
<div>
<input ... >
</div>
</div>
</div>
개선:
<div class="input-wrapper">
<input ...>
</div>
✔ 2) Scroll 영역 내 DOM 최적화
가장 많은 자식을 가진 요소가
DIV.c-topnav-navcontainer-scroll 이라면, 스크롤 영역 가상화 고려 가능
적용 기준
- 자식 50~200개: 문제 없을 가능성 큼
- 300개 이상: 스크롤 시 랙 발생 가능 → virtual scroll 검토
현재 자식 수 22개는 문제 없음.
그러나 확장될 가능성이 있다면 구조 미리 설계하는 것이 좋다.
✔ 3) CSS 선택자 최적화
DOM 깊이가 깊다면 CSS selector 계산 비용도 증가한다.
지양:
.header .nav .menu .item input[type="checkbox"] { ... }
권장:
.chk-all { ... }
✔ 4) 불필요한 DOM 제거
다음 패턴은 성능을 악화시키는 공통 요소:
- 숨겨진 영역을 DOM에 미리 렌더링 해둔 경우
- 탭/모달을 display: none 상태로 쌓아 둔 경우
- 리스트 항목 템플릿을 화면에 미리 복제한 경우
→ IntersectionObserver 를 이용한 lazy render 도 가능
✔ 5) 이벤트 위임 사용
많은 input/checkbox가 존재한다면 각 요소에 직접 handler를 붙이지 말고 상위에서 event delegation 처리.
document.querySelector('.table').addEventListener('click', e => {
if (e.target.matches('input[type="checkbox"]')) {
// 처리
}
})
✔ 6) 너무 많은 SVG 아이콘 inline 삽입 금지
Inline SVG가 늘어나면 DOM 수 폭증
→ sprite sheet, symbol, img 태그로 대체 가능
'개발 > fe' 카테고리의 다른 글
| Turborepo 개념 정리 (0) | 2025.12.10 |
|---|---|
| console.log와 성능 (1) | 2025.12.03 |
| AI 로 프런트 디자인 하는 방법 (0) | 2025.08.18 |
| "data-toggle" (0) | 2023.05.18 |
| 컴포넌트 만들시 (0) | 2023.04.25 |