[FRONT] 브라우저 렌더링 과정

렌더링 이해하기

Posted by lim.Chuck on December 26, 2024

[FRONT]

  1. [FRONT] 프론트엔드 쿠키 이슈 해결하기
  2. [FRONT] Nuxt Proxy 설정과 활용
  3. [FRONT] 웹 캐시 전략과 구현
  4. [FRONT] Next.js와 Nuxt.js 비교 분석
  5. [FRONT] Monorepo vs Multi-repo vs Monolith 아키텍처
  6. [FRONT] mitmproxy를 활용한 디버깅
  7. [FRONT] Storybook 활용 가이드
  8. [FRONT] Vercel Turbopack 소개
  9. [FRONT] 캐시와 캐싱 전략
  10. [FRONT] SWC 컴파일러 이해하기
  11. [FRONT] 인터섹션 옵저버로 인터섹션 여부 감지하기
  12. [FRONT] BroadcastChannel 사용해서 같은 도메인 브라우저 간 통신하기
  13. [FRONT] DOM이벤트 버블링(Bubbling)과 캡처링(Capturing)
  14. [FRONT] XSS와 CSRF
  15. [FRONT] 웹 성능 최적화
  16. [FRONT] 브라우저 렌더링 과정
  17. [FRONT] 웹 접근성
  18. [FRONT] URL과 Domain 정확히 이해하자 (url구조)
  19. [FRONT] HTTP 헤더 이해하기

브라우저 렌더링 과정 완벽 가이드 🎨

1. Critical Rendering Path (중요 렌더링 경로)

렌더링 단계

  1. DOM 트리 생성 (HTML → DOM)
  2. CSSOM 트리 생성 (CSS → CSSOM)
  3. 렌더 트리 생성 (DOM + CSSOM)
  4. 레이아웃 (요소 위치와 크기 계산)
  5. 페인트 (화면에 그리기)
1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- 1. HTML 파싱 -->
<div class="container">
  <p>안녕하세요!</p>
</div>

<!-- 2. CSS 파싱 -->
<style>
  .container {
    width: 100px;
    height: 100px;
    background: red;
  }
</style>

2. Reflow(리플로우)와 Repaint(리페인트)

Reflow가 발생하는 경우

  • 요소의 크기나 위치가 변경될 때
  • 윈도우 리사이징
  • 폰트 변경
  • 내용 변경
1
2
3
4
5
6
7
8
9
// 나쁜 예시 (❌) - 여러번의 리플로우 발생
const box = document.getElementById("box");
box.style.width = "100px"; // 리플로우 발생
box.style.height = "200px"; // 리플로우 발생
box.style.margin = "10px"; // 리플로우 발생

// 좋은 예시 (✅) - 한 번의 리플로우
const box = document.getElementById("box");
box.classList.add("box-style"); // 한 번에 스타일 적용

Repaint가 발생하는 경우

  • 배경색 변경
  • 텍스트 색상 변경
  • 그림자 등 시각적 요소 변경
1
2
3
// Repaint만 발생 (위치나 크기 변경 없음)
element.style.backgroundColor = "red";
element.style.color = "blue";

3. 성능 최적화 방법

1) 리플로우 최소화

1
2
3
4
5
6
7
8
// 1. CSS 클래스 활용
// 나쁜 예시 (❌)
element.style.width = "100px";
element.style.height = "100px";
element.style.backgroundColor = "red";

// 좋은 예시 (✅)
element.classList.add("box-styles");

2) 애니메이션 최적화

1
2
3
4
5
6
7
8
9
10
11
/* 나쁜 예시 (❌) - left 변경은 리플로우 발생 */
.box {
  left: 0;
  transition: left 0.3s;
}

/* 좋은 예시 (✅) - transform은 리플로우 없음 */
.box {
  transform: translateX(0);
  transition: transform 0.3s;
}

3) 프래그먼트 활용

1
2
3
4
5
6
7
// 여러 요소 추가 시 프래그먼트 사용
const fragment = document.createDocumentFragment();
for (let i = 0; i < 10; i++) {
  const el = document.createElement("div");
  fragment.appendChild(el);
}
document.body.appendChild(fragment); // 한 번에 DOM 업데이트

4. 실제 최적화 예시

1) 스크롤 이벤트 최적화

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 스크롤 성능 최적화
class 스크롤최적화 {
  constructor() {
    this.ticking = false;
    window.addEventListener("scroll", () => this.onScroll());
  }

  onScroll() {
    if (!this.ticking) {
      requestAnimationFrame(() => {
        this.업데이트();
        this.ticking = false;
      });
      this.ticking = true;
    }
  }

  업데이트() {
    // 실제 업데이트 로직
  }
}

2) 리스트 렌더링 최적화

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class 리스트최적화 {
  렌더링(items) {
    const fragment = document.createDocumentFragment();

    // 오프스크린에서 요소 생성
    items.forEach((item) => {
      const el = this.요소생성(item);
      fragment.appendChild(el);
    });

    // 한 번에 DOM 업데이트
    this.컨테이너.appendChild(fragment);
  }
}

5. 성능 체크 포인트 ✅

  1. 레이아웃 스래싱 방지

    • 한 번에 스타일 변경하기
    • CSS 클래스 활용하기
    • position: absolute/fixed 활용
  2. 애니메이션 최적화

    • transform/opacity 사용
    • will-change 속성 활용
    • requestAnimationFrame 사용
  3. DOM 조작 최적화

    • 프래그먼트 사용
    • 오프스크린 렌더링
    • 불필요한 DOM 접근 줄이기
  4. CSS 최적화

    • 복잡한 선택자 피하기
    • 불필요한 규칙 제거
    • CSS 상속 활용

이러한 최적화 기법들을 적용하면 더 부드럽고 빠른 웹 페이지를 만들 수 있습니다! 😊