티스토리 뷰
웹 브라우저의 자원 로딩 순서 (HTML, CSS, JavaScript)
웹 브라우저가 사용자에게 웹 페이지를 보여주기까지 HTML, CSS, JavaScript와 같은 자원(Resource)들을 정해진 순서와 규칙에 따라 불러오고 처리합니다. 이 과정을 이해하는 것은 웹 페이지의 성능 최적화에 매우 중요합니다.
기본 로딩 및 렌더링 순서 📜
브라우저는 HTML 문서를 위에서 아래로 한 줄씩 순차적으로 읽고(파싱, Parsing) 처리합니다. 이 과정에서 각 태그가 무엇을 의미하는지 해석하며 DOM(Document Object Model) 트리를 만들어나갑니다.
- HTML 파싱: 브라우저가 서버로부터 HTML 파일을 받아 한 줄씩 읽으며 DOM 트리를 구성합니다.
- CSS 로드 및 파싱:
<head>의<link>태그를 만나면, HTML 파싱을 멈추지 않고 CSS 파일 다운로드를 요청합니다. 다운로드가 완료되면 CSS를 파싱하여 CSSOM(CSS Object Model) 트리를 만듭니다. - JavaScript 로드 및 실행:
<script>태그를 만나면, HTML 파싱을 즉시 중단하고 JavaScript 파일을 다운로드하여 실행합니다. 스크립트 실행이 완료될 때까지 뒤따르는 HTML의 파싱은 멈춥니다. (이를 '파서 블로킹'이라 합니다) - 렌더 트리(Render Tree) 생성: DOM 트리와 CSSOM 트리가 완성되면, 화면에 실제로 표시될 요소들로만 구성된 렌더 트리를 생성합니다. (
display: none;같은 요소는 제외됩니다) - 레이아웃(Layout/Reflow): 렌더 트리를 기반으로 각 요소가 화면의 어느 위치에 어떤 크기로 배치될지 정확히 계산합니다.
- 페인트(Paint): 레이아웃 계산이 끝난 요소들을 화면에 실제로 그립니다.
CSS와 JavaScript의 위치가 중요한 이유 💡
CSS를 <head>에 두는 이유
CSS는 렌더링 차단(Render-Blocking) 리소스입니다. 브라우저는 CSSOM 트리가 완성되지 않으면 렌더링을 시작하지 않습니다. 만약 CSS를 <body> 태그 중간이나 끝에 두면 다음과 같은 문제가 발생할 수 있습니다.
- 스타일 없는 콘텐츠 노출 (FOUC): 스타일이 적용되지 않은 HTML이 먼저 보인 후, CSS가 적용되면서 화면이 번쩍거리는 현상이 발생합니다.
- 불필요한 재렌더링: 이미 그려진 페이지에 새로운 CSS 규칙이 적용되면서 레이아웃을 재계산(리플로우)하고 다시 그리는(리페인트) 과정이 발생하여 성능이 저하됩니다.
JavaScript를 <body> 끝에 두거나 속성을 사용하는 이유
일반적인 <script> 태그는 HTML 파싱을 차단하여, 사용자가 첫 화면을 보기까지의 시간을 지연시킵니다. 이를 해결하기 위한 방법은 다음과 같습니다.
1. <script>를 <body> 태그가 닫히기 직전에 배치
- 장점: HTML 파싱이 모두 끝난 후에 스크립트를 로드하므로, 파싱 차단 문제가 발생하지 않아 사용자가 페이지 콘텐츠를 더 빨리 볼 수 있습니다.
- 단점: 페이지가 전부 표시된 후에야 스크립트 다운로드가 시작되므로, 스크립트에 의존하는 기능(이미지 슬라이더 등)의 시작이 늦어질 수 있습니다.
2. <script async> 속성 사용
- HTML 파싱과 동시에 비동기적으로 스크립트를 다운로드합니다.
- 다운로드가 완료되면 HTML 파싱을 즉시 중단하고 스크립트를 실행합니다.
- 실행 순서가 보장되지 않아 다른 스크립트와 의존성이 없는 독립적인 스크립트(광고, 분석 스크립트 등)에 적합합니다.
3. <script defer> 속성 사용 (⭐ 권장)
- HTML 파싱과 동시에 비동기적으로 스크립트를 다운로드합니다.
- 다운로드가 완료되어도 즉시 실행하지 않고, HTML 파싱이 모두 끝난 후에 스크립트를 실행합니다.
- 여러
defer스크립트는 HTML에 명시된 순서대로 실행이 보장됩니다. - DOM을 조작하는 등 페이지 콘텐츠 전체가 필요한 스크립트에 가장 이상적입니다.
시각적 요약 📊
| 태그 위치 / 속성 | HTML 파싱 중단 (스크립트 다운로드 시) |
HTML 파싱 중단 (스크립트 실행 시) |
스크립트 실행 시점 | 실행 순서 보장 |
|---|---|---|---|---|
<head> 내 <script> |
예 | 예 | 다운로드 직후 | 예 |
<body> 끝 <script> |
아니요 | 예 | HTML 파싱 완료 후 | 예 |
<script async> |
아니요 | 예 | 다운로드 직후 | 아니요 |
<script defer> |
아니요 | 아니요 | HTML 파싱 완료 후 | 예 |
결론: 최적의 배치 전략 ✨
CSS는
<head> 안에, JavaScript는 <body>가 닫히기 직전에 defer 속성과 함께 배치하는 것이 현대 웹 개발의 가장 일반적이고 효율적인 방법입니다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>최적의 로딩 순서</title>
<!-- 1. CSS: 렌더링 차단을 최소화하기 위해 head에 배치 -->
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- 2. HTML: 위에서 아래로 순차적으로 파싱되며 DOM 생성 -->
<header>
<h1>웹페이지 제목</h1>
</header>
<main>
<p>페이지의 주요 콘텐츠입니다.</p>
</main>
<!-- 3. JavaScript: defer를 사용하여 HTML 파싱을 막지 않고,
DOM 생성이 완료된 후 순서대로 스크립트를 실행. -->
<script src="library.js" defer></script>
<script src="main.js" defer></script>
</body>
</html>
'DEV > SCRIPT' 카테고리의 다른 글
| JS : 호이스팅(Hoisting) (0) | 2025.06.09 |
|---|---|
| [JS] COPY (0) | 2024.02.22 |
| [JS] 화면 PRINT (2) | 2023.12.08 |
| [JS] 배열 - 두 배열 합치기, 배열 평탄화, 배열 분할 (3) | 2023.12.08 |
| [JS] 소수점 (0) | 2023.12.08 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- table
- 로스터리
- Eclipse
- JavaScript
- 커피
- LILI COFFEE
- oracle
- Coffee
- 스페셜티
- 단위변환
- handdrip
- JSP
- MySQL
- SQL
- partition
- GitHub
- db
- BAT
- backup
- VBS
- SEQUENCE
- 리리 커피
- Powershell
- Between
- popup
- MariaDB
- dbeaver
- date
- Filter
- diff
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 | 31 |
글 보관함
