9장: 웹 브라우저 동작 원리

📋 강의 개요


📚 9.1 브라우저 구조

강의 포인트

브라우저 주요 컴포넌트

┌────────────────────────────────────────┐
│     사용자 인터페이스 (UI)               │  ← 주소창, 북마크, 뒤로가기 등
├────────────────────────────────────────┤
│     브라우저 엔진                        │  ← UI와 렌더링 엔진 사이 중개
├────────────────────────────────────────┤
│     렌더링 엔진                     ⭐   │  ← HTML, CSS를 화면에 표시
├────────────────────────────────────────┤
│     네트워킹                            │  ← HTTP 요청 처리
├────────────────────────────────────────┤
│     JavaScript 인터프리터 (V8 등)       │  ← JavaScript 실행
├────────────────────────────────────────┤
│     UI 백엔드                           │  ← 기본 위젯 그리기
├────────────────────────────────────────┤
│     데이터 저장소                        │  ← Cookie, LocalStorage 등
└────────────────────────────────────────┘

주요 렌더링 엔진

브라우저 렌더링 엔진 JavaScript 엔진
Chrome Blink V8
Firefox Gecko SpiderMonkey
Safari WebKit JavaScriptCore
Edge (구) EdgeHTML Chakra
Edge (신) Blink V8

📚 9.2 렌더링 엔진의 동작 과정

강의 포인트

렌더링 과정 (전체 흐름)

1. HTML 파싱 → DOM 트리 생성
         ↓
2. CSS 파싱 → CSSOM 트리 생성
         ↓
3. DOM + CSSOM → 렌더 트리 생성
         ↓
4. 레이아웃 (Layout/Reflow) → 위치 계산
         ↓
5. 페인트 (Paint) → 픽셀로 그리기
         ↓
6. 합성 (Composite) → 레이어 합성

단계별 상세 설명

1단계: HTML 파싱 → DOM 트리

<!DOCTYPE html>
<html>
  <head>
    <title>제목</title>
  </head>
  <body>
    <div class="container">
      <h1>안녕하세요</h1>
      <p>내용입니다</p>
    </div>
  </body>
</html>
DOM 트리:
html
├─ head
│  └─ title
│     └─ "제목"
└─ body
   └─ div.container
      ├─ h1
      │  └─ "안녕하세요"
      └─ p
         └─ "내용입니다"

파싱 과정:

  1. 바이트 → 문자 → 토큰 → 노드 → DOM 트리

2단계: CSS 파싱 → CSSOM 트리

body {
    font-size: 16px;
}
.container {
    width: 800px;
    margin: 0 auto;
}
h1 {
    font-size: 32px;
    color: blue;
}
CSSOM 트리:
body
├─ font-size: 16px
└─ .container
   ├─ width: 800px
   ├─ margin: 0 auto
   └─ h1
      ├─ font-size: 32px
      └─ color: blue

특징:

3단계: 렌더 트리 생성

DOM + CSSOM → 렌더 트리

렌더 트리:
- 화면에 표시될 노드만 포함
- display:none → 제외
- visibility:hidden → 포함 (공간 차지)
- head, script → 제외
렌더 트리 예시:
body (font-size: 16px)
└─ div.container (width: 800px)
   ├─ h1 (font-size: 32px, color: blue)
   └─ p (font-size: 16px)

4단계: 레이아웃 (Layout/Reflow)

각 노드의 정확한 위치와 크기 계산

예:
div.container
  x: 300px (화면 중앙)
  y: 0px
  width: 800px
  height: 200px

h1
  x: 300px (부모 기준)
  y: 0px
  width: 800px
  height: 50px

레이아웃이 다시 발생하는 경우:

5단계: 페인트 (Paint)

실제 픽셀로 그리기

- 배경색
- 테두리
- 그림자
- 텍스트
- 이미지
등을 그림

페인트가 다시 발생하는 경우:

6단계: 합성 (Composite)

여러 레이어를 합쳐서 최종 화면 생성

레이어:
- position: fixed
- transform: translate3d()
- opacity
- will-change
등이 별도 레이어 생성

📚 9.3 DOM 트리 / CSSOM 트리

DOM (Document Object Model)

// JavaScript로 DOM 조작
const div = document.createElement('div');
div.textContent = '새로운 내용';
document.body.appendChild(div);

// DOM 트리가 변경됨 → 리플로우 발생

CSSOM (CSS Object Model)

// JavaScript로 스타일 조작
const element = document.querySelector('.box');
element.style.width = '500px';  // CSSOM 변경 → 리플로우

// 계산된 스타일 가져오기
const styles = window.getComputedStyle(element);
console.log(styles.width);  // "500px"

📚 9.4 렌더 트리

렌더 트리 구성 규칙

<div style="display: none;">
  <p>보이지 않음</p>
</div>

<div style="visibility: hidden;">
  <p>공간은 차지</p>
</div>

<div>
  <p>보임</p>
</div>
렌더 트리:
- display:none div → 제외 ❌
- visibility:hidden div → 포함 ✅ (공간 차지)
- 일반 div → 포함 ✅

📚 9.5 리플로우(Reflow)와 리페인트(Repaint)

강의 포인트

리플로우 (Reflow / Layout)

레이아웃 재계산 (위치, 크기)

발생 조건:
✅ DOM 추가/삭제
✅ 요소 크기/위치 변경
✅ 폰트 크기 변경
✅ 창 크기 변경
✅ 애니메이션
✅ offsetWidth, scrollTop 등 속성 읽기 (강제 리플로우!)

리플로우 발생 예:

// ❌ 나쁜 예 (3번의 리플로우)
element.style.width = '100px';   // 리플로우
element.style.height = '200px';  // 리플로우
element.style.margin = '10px';   // 리플로우

// ✅ 좋은 예 (1번의 리플로우)
element.style.cssText = 'width: 100px; height: 200px; margin: 10px;';

// ✅ 더 좋은 예 (클래스 사용)
element.classList.add('new-style');

리페인트 (Repaint)

픽셀 다시 그리기 (색상 등)

발생 조건:
✅ 색상 변경
✅ 배경 이미지 변경
✅ 가시성 변경

리페인트만 발생 예:

element.style.color = 'red';           // 리페인트만
element.style.backgroundColor = 'blue'; // 리페인트만
element.style.visibility = 'hidden';   // 리페인트만

리플로우 vs 리페인트 비교

작업 리플로우 리페인트 성능
width, height 변경 느림 😢
margin, padding 변경 느림 😢
position 변경 느림 😢
color 변경 빠름 😊
background 변경 빠름 😊
transform 매우 빠름 😍
opacity 매우 빠름 😍

강제 동기 레이아웃 (Forced Synchronous Layout)

// ❌ 매우 나쁜 예 (강제 리플로우 반복!)
const boxes = document.querySelectorAll('.box');
boxes.forEach(box => {
    box.style.width = box.offsetWidth + 10 + 'px';
    // offsetWidth 읽기 → 즉시 리플로우 발생!
    // 다음 반복에서 또 리플로우... (N번 리플로우)
});

// ✅ 좋은 예 (읽기와 쓰기 분리)
const boxes = document.querySelectorAll('.box');
const widths = [];

// 1. 먼저 모든 값 읽기 (1번 리플로우)
boxes.forEach(box => {
    widths.push(box.offsetWidth);
});

// 2. 값 설정 (1번 리플로우)
boxes.forEach((box, i) => {
    box.style.width = widths[i] + 10 + 'px';
});

리플로우를 발생시키는 속성들

// ⚠️ 이 속성들을 읽으면 즉시 리플로우 발생!
element.offsetTop
element.offsetLeft
element.offsetWidth
element.offsetHeight

element.scrollTop
element.scrollLeft
element.scrollWidth
element.scrollHeight

element.clientTop
element.clientLeft
element.clientWidth
element.clientHeight

window.getComputedStyle(element)

📚 9.6 브라우저 캐싱

강의 포인트

캐시의 종류

1. 메모리 캐시 (Memory Cache)

RAM에 저장
- 매우 빠름
- 탭 닫으면 사라짐
- 용량 제한

예: 이미지, 스크립트

2. 디스크 캐시 (Disk Cache)

하드디스크에 저장
- 빠름
- 브라우저 재시작 후에도 유지
- 용량 큼

예: CSS, 폰트, 큰 이미지

3. Service Worker 캐시

오프라인 지원
- 개발자가 직접 제어
- PWA의 핵심

캐시 제어 (Cache-Control)

Cache-Control: max-age=3600
→ 3600초(1시간) 동안 캐시

Cache-Control: no-cache
→ 캐시 사용 전에 서버에 확인 (304 응답 가능)

Cache-Control: no-store
→ 절대 캐시 안 함

Cache-Control: public
→ 모든 캐시(프록시 포함)에 저장 가능

Cache-Control: private
→ 브라우저만 캐시 가능

ETag (Entity Tag)

리소스 버전 관리

1. 서버: ETag: "abc123" (리소스 해시값)
2. 클라이언트: 캐시 저장
3. 다음 요청: If-None-Match: "abc123"
4. 서버: 변경 없으면 304 Not Modified
        변경 있으면 200 OK + 새 데이터

캐시 무효화 전략

// 파일명에 버전/해시 포함
<link href="style.v1.2.3.css">
<link href="style.abc123.css">

// 쿼리 스트링 사용 (권장 안 함)
<link href="style.css?v=1.2.3">

📚 9.7 개발자 도구 (DevTools) 사용법

강의 포인트

Elements 패널 ⭐

- DOM 트리 확인
- 스타일 실시간 수정
- 계산된 스타일 확인
- 이벤트 리스너 확인

실습:

  1. F12 → Elements
  2. 요소 선택 (Ctrl+Shift+C)
  3. Styles 탭에서 실시간 수정

Console 패널 ⭐⭐⭐

// 로그 출력
console.log('일반 로그');
console.warn('경고');
console.error('에러');

// 객체 출력
console.table([{name: '홍길동', age: 25}]);

// 시간 측정
console.time('작업');
// ... 작업 ...
console.timeEnd('작업');  // 작업: 123.45ms

// 그룹화
console.group('사용자 정보');
console.log('이름: 홍길동');
console.log('나이: 25');
console.groupEnd();

Network 패널 ⭐

- HTTP 요청/응답 확인
- 로딩 시간 분석
- 캐시 확인
- 상태 코드 확인

확인 항목:

Performance 패널 ⭐

성능 분석

1. 녹화 시작
2. 페이지 조작
3. 녹화 중지
4. 분석:
   - FPS (초당 프레임)
   - CPU 사용률
   - 스크린샷
   - 타이밍

Application 패널

- LocalStorage
- SessionStorage
- Cookies
- IndexedDB
- Service Workers
- Cache Storage

Lighthouse 패널 ⭐

웹 사이트 품질 측정

점수:
- Performance (성능)
- Accessibility (접근성)
- Best Practices (모범 사례)
- SEO (검색 엔진 최적화)

개선 사항 제안

🎯 성능 최적화 팁

1. 리플로우 최소화

// ❌ 나쁜 예
for (let i = 0; i < 100; i++) {
    const div = document.createElement('div');
    document.body.appendChild(div);  // 100번 리플로우!
}

// ✅ 좋은 예
const fragment = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
    const div = document.createElement('div');
    fragment.appendChild(div);
}
document.body.appendChild(fragment);  // 1번 리플로우!

2. 클래스 사용

// ❌ 나쁜 예
element.style.width = '100px';
element.style.height = '200px';
element.style.backgroundColor = 'red';

// ✅ 좋은 예
element.classList.add('styled');

3. transform 사용

/* ❌ 나쁜 예 (리플로우 발생) */
.box {
    left: 0;
    transition: left 1s;
}
.box:hover {
    left: 100px;
}

/* ✅ 좋은 예 (합성만 발생) */
.box {
    transform: translateX(0);
    transition: transform 1s;
}
.box:hover {
    transform: translateX(100px);
}

4. will-change 사용

/* 미리 레이어 생성 (애니메이션 전) */
.box {
    will-change: transform, opacity;
}

/* 애니메이션 후 제거 */
.box {
    will-change: auto;
}

5. 이미지 최적화

<!-- 반응형 이미지 -->
<img src="small.jpg"
     srcset="small.jpg 500w, medium.jpg 1000w, large.jpg 2000w"
     sizes="(max-width: 600px) 500px, (max-width: 1200px) 1000px, 2000px">

<!-- Lazy Loading -->
<img src="image.jpg" loading="lazy">

6. 스크립트 로딩 최적화

<!-- ❌ 나쁜 예 (렌더링 차단) -->
<head>
    <script src="app.js"></script>
</head>

<!-- ✅ 좋은 예 -->
<head>
    <script src="app.js" defer></script>      <!-- HTML 파싱 후 실행 -->
    <script src="ads.js" async></script>      <!-- 비동기 로드 -->
</head>

<!-- ✅ 또는 body 끝에 -->
<body>
    <!-- 내용 -->
    <script src="app.js"></script>
</body>

7. CSS 최적화

<!-- Critical CSS를 인라인으로 -->
<head>
    <style>
        /* 첫 화면에 필요한 최소한의 CSS */
        body { margin: 0; font-family: Arial; }
        .header { background: #333; color: white; }
    </style>
    
    <!-- 나머지 CSS는 비동기 로드 -->
    <link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
</head>

🎯 강의 진행 팁

1-2교시: 브라우저 구조와 렌더링 (2시간)

3-4교시: 리플로우와 최적화 (2시간)

5-6교시: 캐싱과 DevTools (2시간)


📝 종합 실습: 성능 최적화

// 최적화 전
function updateList(items) {
    const list = document.querySelector('#list');
    list.innerHTML = '';  // 리플로우
    
    items.forEach(item => {
        const li = document.createElement('li');
        li.textContent = item;
        list.appendChild(li);  // 매번 리플로우!
    });
}

// 최적화 후
function updateListOptimized(items) {
    const list = document.querySelector('#list');
    const fragment = document.createDocumentFragment();
    
    items.forEach(item => {
        const li = document.createElement('li');
        li.textContent = item;
        fragment.appendChild(li);  // 메모리에서만 작업
    });
    
    list.innerHTML = '';  // 1번 리플로우
    list.appendChild(fragment);  // 1번 리플로우
    // 총 2번의 리플로우만!
}

9장 웹 브라우저 동작 원리를 완료했습니다! 🎓


🎉 축하합니다!

전체 웹 기초 강의를 모두 완료했습니다!

이제 여러분은:

다음 단계: React, Vue, Node.js 등의 프레임워크로 발전하세요! 🚀