
1일 1질문으로 개발자가 되어보자. (One Day One Question)
분야: 네트워크
주제: 주소창에 URL을 입력하면 일어나는 과정
주소창에 URL을 입력하면 일어나는 과정
잘 알고 있는지
- 동아리 테크톡으로 발표했었던 주제이다. 복습 기념이기도 하고, 네트워크 공부하는 주간에 프론트 쪽으로 하나 해두면 비교적 오래 기억할 수 있을 것 같다.
내가 아는 만큼 설명
- 브라우저는 Document Object Model과 CSSOM을 통해 Render Tree를 그린다. 이때 display none은 그리지 않고, visiblity - 비슷한 속성은 그리지만 나타내지는 않는 것으로 알고있다. 렌더 트리를 그리고 나면, 우선 이런 순서로 진행된다. 먼저 배치를 하고, 그 다음에 나타낸다. 그 다음은 Reflow, Repaint, 마지막으로는 Composite. Reflow는 렉이 걸린다. 그러니 없애야 한다~ 이런 것이 아니라, 반응형 디자인을 위해선 반드시 존재해야 한다. 최소화 해야 한다. Composite는 그래픽 카드를 이용하기 때문에 병렬로 처리한다. CPU에 비해 좋은 점, 그것 이야기. transform 같은 것이 그 예시. 여기까지 아는 만큼 오늘은 단계에 대해 자세히 조사하고, 실제로 어떻게 개발을 해야한다 라는 결론까지 연결하는 것을 목표로 하자.
답을 본 뒤 알게 된 것
HTML
→ DOM Document Object Model 문서 객체 모델로 브라우저가 HTML문서를 이해하고 다루기 위해 만든 객체 형태의 문서 구조.
→ CSS Cascading Style Sheets로 HTML 요소가 화면에서 어떻게 보일지 정하는 규칙이다.
→ CSSOM CSS Object Model는 CSS 객체 모델로 브라우저가 CSS문서를 이해하고 다루기 위해 만든 객체 형태의 문서 구조.
→ (몰랐던 지점) JS가 개입한다. HTML의 Script를 만나면.
→ Render Tree는 브라우저가 실제로 보여줄 요소들만 모아놓은 트리. JavaScript 실행으로 변경된 현재 DOM과 CSSOM을 기준으로 만들어진다. (중요) JS가 없앤 요소는 렌더 트리에도 포함되지 않는다. + display:none은 포함X, visibility: hidden은 포함O. 그러므로 display는 렌더 트리에서 사라지고, 다시 나타날때 Reflow 과정을 거친다. 비싸다. visibility는 반대. 그리고 Composite까지 가면 opacity가.
→ Layout은 렌더 트리에 있는 각 요소의 '위치와 크기'를 계산하는 단계. 이 요소는 화면의 어디에 놓을까? 가로는 몇 px인가? 세로는 몇 px인가? 부모 안에서 어느 위치인가? 옆 요소와 얼마나 떨어져 있는가?. 아직 색칠은 하지 않는다. 보이지 않는다. 계산이다.
→ Paint는 Layout으로 계산된 영역에 실제 시각적 스타일을 그리는 단계다. 그 영역을 어떤 색, 테두리, 그림자, 텍스트로 그릴 것인가? color랑 background-color 등만 바뀐다면? (여기부터는 다음에)
→ Composite는 합성. Paint 된 여러 레이어를 최종 화면으로 합성하는 단계다. transform은 이미 그려진 레이어를 움직이고, opacity는 투명도만 조절한다.
→ Reflow는 요소의 크기나 위치에 영향을 주는 변경이 발생했을 때, 브라우저가 Layout을 다시 계산하는 과정이다. width, height, margin, padding, font-size, DOM 추가/삭제처럼 배치에 영향을 주는 변화가 Reflow를 유발할 수 있다.
→ Repaint는 Layout은 다시 하지 않고, 화면에 칠하는 작업만 다시 하는 것이다.
→ 화면
===
크기나 위치가 바뀐다 = Reflow
색만 바뀐다 = Repaint
transform/opacity = Composite
===
1. 리소스 로딩 순서 — 렌더링 언제 시작되냐를 가름
CSS는 렌더 블로킹. CSSOM 다 만들어질 때까지 브라우저가 화면을 못 그려. 그래서 CSS는 <head>에 두고 최대한 빨리·작게 받게 해. 안 쓰는 CSS 크면 그만큼 첫 화면이 늦어짐.
JS는 파서 블로킹. <script> 만나면 HTML 파싱을 멈추고 JS부터 실행해(DOM 만들다 말고). 그래서 위치·속성이 중요해:
defer: 파싱은 안 막고 백그라운드로 받아뒀다가, HTML 다 파싱된 뒤 순서대로 실행. 일반적으로 이거 기본값처럼 써.
async: 받는 즉시 실행(파싱 막음). 순서 보장 안 됨. 독립적인 스크립트(애널리틱스 같은 거)에만.
아무것도 없으면: 만나는 즉시 멈추고 실행. 제일 안 좋음.
2. 애니메이션은 싼 속성으로 — reflow 피하기의 실전
/* ❌ reflow: 매 프레임 Layout 재계산 → 버벅임 */
.box {
position: absolute;
left: 0;
transition: left 0.3s;
}
.box:hover {
left: 200px;
}
/* ✅ composite: GPU가 처리 → 부드러움 */
.box {
transition: transform 0.3s;
}
.box:hover {
transform: translateX(200px);
}
움직임 줄 때 left/top/width/margin으로 하면 매 프레임 reflow라 버벅여.
transform: translate() / scale() 이랑 opacity로 하면 composite만 타서 GPU가 처리 → 부드러움.
규칙 하나로: "움직이고 투명하게 만드는 건 transform/opacity로." 위치를 left로 옮기고 싶은 유혹이 그 반대 예시야.
3. Layout Thrashing 피하기 — 전에 낸 꼬리질문 답
// ❌ 읽기-쓰기 반복 → 매번 강제 reflow
boxes.forEach((box) => {
const w = box.offsetWidth; // 읽기 (강제 reflow)
box.style.width = w + 10 + "px"; // 쓰기
});
// ✅ 읽기 모아서 → 쓰기 모아서
const widths = boxes.map((box) => box.offsetWidth); // 읽기 전부 먼저
boxes.forEach((box, i) => {
box.style.width = widths[i] + 10 + "px"; // 쓰기 전부 나중
});
브라우저는 reflow를 모아서 한 번에 처리하려고 해(배치). 근데 네가 중간에 레이아웃 값을 읽으면(offsetHeight, getBoundingClientRect 등) "지금 당장 정확한 값 내놔" 하고 강제로 reflow가 즉시 터져.
그래서 반복문에서 읽기 → 쓰기 → 읽기 → 쓰기 섞으면 매번 reflow = 지옥(layout thrashing).
해법: 읽기 다 모아서 먼저 → 쓰기 다 모아서 나중. 이 분리가 핵심.
4. DOM 조작 최소화
// ❌ 반복마다 DOM 삽입 → reflow 여러 번
for (let i = 0; i < 100; i++) {
list.appendChild(document.createElement("li"));
}
// ✅ Fragment에 모아서 한 번에 → reflow 1회
const frag = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
frag.appendChild(document.createElement("li"));
}
list.appendChild(frag);
반복적으로 DOM에 하나씩 append하면 그때마다 reflow 가능. 한 번에 묶어서(DocumentFragment 쓰거나, 문자열로 만들어 한 방에) 넣으면 reflow 1회로 끝.
5. 레이아웃 시프트(CLS) 방지 — 인덕툰
<!-- ❌ 크기 없음 → 이미지 로드되면서 아래 콘텐츠 밀림 (CLS) -->
<img src="thumbnail.jpg" />
<!-- ✅ 크기 미리 지정 → 로드 전에도 자리 예약 -->
<img src="thumbnail.jpg" width="300" height="200" />
/* 반응형이라 width/height 직접 못 박을 때 */
.thumbnail {
aspect-ratio: 3 / 2; /* 비율로 자리 예약 */
width: 100%;
}
이미지·광고·늦게 뜨는 요소가 로드되면서 아래 콘텐츠를 밀면 = 레이아웃 시프트 = reflow + 사용자 경험 최악.
해법: 자리를 미리 예약. 이미지에 width/height(또는 aspect-ratio) 박아서 로드 전에도 공간 잡아두기. 네가 인덕툰에서 이미지 로딩 상태 훅으로 한 게 정확히 이 결론의 실전판이야.
틀렸거나 부족했던 부분
- 실제 적용 예시 설명하기
면접용 1분 답변
- CRP은 크리티컬 렌더링 패스로, 중요한 렌더링 과정이라는 뜻입니다. 브라우저는 먼저 DOM을 통해 HTML문서를 이해합니다. 그 다음 CSSOM을 통해 CSS 문서를 이해합니다. 이후 렌더 트리를 형성합니다. 렌더 트리에는 실제로 보이는 것만 기록됩니다. 이 과정에서 display none 등은 렌더 트리에서 실제로 누락되며, visibility hidden 등은 유지됩니다. 이후 Layout 과정을 거칩니다. 이때는 실제로 나타나지 않고 어디에 위치해야하는지 계산합니다. 이후 Paint 과정을 거칩니다. 이때 브라우저는 각 요소를 메모리 상의 레이어에 그려냅니다. 이후 Composite 과정을 통해 그려진 레이어들을 실제 브라우저 위에 나타나게 됩니다.
- 그러나 이때 페이지의 요소 크기가 변하거나 위치가 달라질 경우 Reflow 과정을 거칩니다. Layout을 다시 하는 과정으로, 비용이 꽤 비쌉니다. 그러나 색만 바뀔 경우 Repaint 과정을 거치는데 이는 비용이 상대적으로 적습니다. 또한 translate나 opacity 같은 속성을 건드릴 경우 Composite 단계를 반복하게(처리하게!) 되는데, 이의 경우 GPU가 하드웨어 가속 옵션으로 개입할 수 있어 앞의 두 과정에 비해 비용이 작습니다.
한 줄 요약
- DOM·CSSOM으로 렌더 트리 만들고 Layout→Paint→Composite로 그린다. 재렌더링은 Reflow>Repaint>Composite 순으로 비싸니, 애니메이션은 transform·opacity로.
'공부 > 1D1Q' 카테고리의 다른 글
| [1D1Q | Network] HTTP(Hypertext Transfer Protocol) (0) | 2026.07.10 |
|---|---|
| [1D1Q | Network] HTTP vs HTTPS (0) | 2026.07.09 |
| [1D1Q | Network] 주소창에 URL을 입력하면 일어나는 과정 (0) | 2026.07.09 |