들어가며
웹 개발을 하면서 가장 많이 알아야 되지만 항상 미묘하게 알고 있었던 게 브라우저에 대한 내용인 것 같습니다. 스터디 준비하면서 한번 정리를 해둬야 겠다 싶어서 전체적인 내용을 짚어가면서 정리를 해보려고 합니다.
1. 브라우저란?
1.1. 브라우저의 탄생과 발전

웹의 시작과 초창기 브라우저
웹은 1990년 팀 버너스 리(Tim Berners-Lee) 박사에 의해 개발된 월드 와이드 웹(WWW)에서 시작되었습니다. 초창기 웹페이지는 단순한 정적 HTML 문서로 구성되었으며, 1993년 최초의 그래픽 기반 웹 브라우저인 모자이크(Mosaic)가 등장하면서 대중들이 웹을 쉽게 접할 수 있는 계기가 되었습니다. 이후 1994년 넷스케이프 내비게이터(Netscape Navigator)가 출시되면서 브라우저 기술이 본격적으로 발전하였습니다.
브라우저의 발전 과정
- 정적 웹페이지 시대 (1990년대 초반)
- HTML 기반의 정적인 웹 문서가 주를 이루었으며, 웹 브라우저는 단순히 HTML을 해석하여 화면에 표시하는 역할을 하였습니다.
- 동적 웹페이지 시대 (1990년대 후반 ~ 2000년대 초반)
- JavaScript와 CSS의 도입으로 보다 동적인 UI 구현이 가능해졌으며, DOM(Document Object Model)이 도입되면서 JavaScript를 활용한 HTML 조작이 가능해졌습니다.
- AJAX와 웹 애플리케이션 시대 (2000년대 중반 ~ 2010년대 초반)
- AJAX(Asynchronous JavaScript and XML) 기술이 등장하면서 비동기 통신이 가능해졌고, 전체 페이지를 새로고침하지 않고도 특정 데이터만 갱신할 수 있게 되었습니다. 이로 인해 웹 애플리케이션의 인터랙티브한 기능이 향상되었습니다.
- 현대 웹 (2010년대 이후)
- HTML5, CSS3, 최신 JavaScript(ES6+)이 도입되면서 브라우저의 기능이 더욱 강력해졌으며, React, Vue, Angular 등의 프레임워크가 등장하면서 가상 DOM(Virtual DOM)과 렌더링 최적화 기술이 발전하였습니다. 또한, WebAssembly 및 PWA(Progressive Web App)와 같은 새로운 기술이 도입되면서 브라우저가 단순한 HTML 해석기를 넘어 강력한 애플리케이션 실행 환경으로 진화하였습니다.
2. 브라우저의 렌더링 과정
2.1. 웹페이지 요청부터 화면 출력까지
- 사용자가 주소창에 URL 입력 후 요청
- 브라우저는 DNS(Domain Name System)를 통해 도메인의 IP 주소를 조회합니다.
- 서버와 TCP 연결을 설정한 후, HTTP(S) 요청을 보냅니다.
- 서버 응답 및 HTML 파일 다운로드
- 브라우저는 서버로부터 HTML, CSS, JavaScript, 이미지 등 필요한 리소스를 다운로드하여 화면을 구성합니다.
- HTML 파싱 및 DOM 트리 생성
- 브라우저는 HTML 문서를 한 줄씩 해석하여 DOM(Document Object Model) 트리를 생성합니다.
- 브라우저는 HTML을 해석하는 중 <script> 태그를 만나면, 해당 JavaScript를 다운로드하고 실행합니다. defer 또는 async 속성이 없는 경우, JavaScript 실행이 끝날 때까지 HTML 파싱이 중단됩니다. 이로 인해 웹페이지의 로딩 속도가 저하될 수 있으며, 이를 방지하기 위해 defer 또는 async 속성을 활용할 수 있습니다.
- CSS 파싱 및 CSSOM 생성
- CSS 파일을 해석하여 CSSOM(CSS Object Model)을 생성합니다. CSSOM은 단독으로 화면을 렌더링하지 않으며, DOM과 결합하여 Render Tree를 생성한 후 화면에 표시됩니다..
- 레이아웃(Layout, Reflow) 단계
- 모든 요소의 크기와 위치를 계산하여 화면 배치를 결정합니다.
- 페인팅(Painting, Repaint) 단계
- Render Tree를 기반으로 픽셀을 화면에 칠하는 작업을 수행합니다.
- JavaScript 실행 및 최종 렌더링
- JavaScript가 실행되면서 DOM을 조작하면 Reflow & Repaint가 발생하여 화면이 다시 그려질 수 있습니다.
3. DOM (Document Object Model)
3.1. DOM의 정의 및 역사적 배경
DOM은 HTML 및 XML 문서를 객체 기반으로 표현한 계층적 트리 구조입니다. JavaScript를 통해 문서를 동적으로 조작할 수 있도록 설계되었습니다.
DOM의 발전 과정
- 1990년대: JavaScript 도입으로 동적인 웹페이지 구현이 가능해짐
- 1998년~2000년대 초반: W3C(World Wide Web Consortium)가 DOM을 표준화하여 크로스 브라우저 호환성이 개선됨
- 2010년대 이후: 가상 DOM(Virtual DOM)과 Shadow DOM 같은 최적화 기술 등장
초창기 웹(1990년대 초반)에서는 HTML 문서는 단순한 정적인 구조를 가지며, 한 번 로드된 후에는 사용자가 웹페이지를 동적으로 변경할 방법이 없었습니다. 하지만 JavaScript의 등장(1995년)과 함께 웹페이지의 내용을 동적으로 수정할 필요성이 커졌고, 이를 위해 DOM (Document Object Model)이 탄생했습니다.
3.2. DOM의 구조 및 역할
DOM은 HTML을 기반으로 계층적인 트리 구조를 형성합니다. JavaScript는 DOM API를 사용하여 문서 구조를 동적으로 변경할 수 있습니다.
렌더링 과정에서 DOM이 하는 역할
- HTML 파싱 후 DOM 트리 생성
- CSS 적용을 위한 CSSOM과 결합하여 Render Tree 구성
- JavaScript가 DOM을 조작하면 Reflow & Repaint 발생
- 렌더링 최적화를 위해 Virtual DOM 또는 Shadow DOM 같은 최신 기술 활용 가능
3.3 DOM의 동작 과정
웹페이지가 로드될 때, 브라우저는 다음 과정을 거쳐 DOM을 생성합니다.
- HTML 파싱
- HTML 파일을 한 줄씩 읽으면서 태그를 해석합니다.
- 태그를 만나면 DOM 노드를 생성하여 트리 구조를 만듭니다.
- DOM 트리 생성
- 각 HTML 태그는 노드(Node)로 변환됩니다.
- <html>이 루트(root) 노드가 되며, <head>, <body> 등이 자식 노드로 추가됩니다.
- CSS 파싱 및 적용 (CSSOM)
- CSS가 로드되면 CSSOM (CSS Object Model)이 생성됩니다.
- DOM과 CSSOM을 결합하여 Render Tree를 만듭니다.
- JavaScript 실행 및 DOM 조작
- JavaScript는 document 객체를 통해 DOM을 조작할 수 있습니다.
- 예: document.getElementById("myId").innerText = "변경된 텍스트";
3.4 DOM의 한계와 해결 방법
DOM의 문제점
- 속도가 느림: DOM을 직접 조작할 경우 브라우저는 Reflow & Repaint를 반복해야 하므로 성능이 저하될 수 있다.
- 비효율적인 업데이트: 특정 요소만 변경해도 전체 페이지가 다시 렌더링될 수 있음.
해결 방법
- Virtual DOM (React에서 사용)
- DOM을 가상으로 메모리에 저장하고, 변경이 발생했을 때만 실제 DOM을 업데이트하여 성능을 향상.
- Shadow DOM (웹 컴포넌트에서 사용)
- DOM의 일부를 격리시켜 스타일과 스크립트 충돌을 방지.
4. Reflow와 Repaint
4.1. Reflow와 Repaint의 개념 및 차이점
1) Reflow (레이아웃 재계산)
Reflow는 DOM 요소의 레이아웃(위치, 크기, 정렬 등)이 변경될 때 발생하는 과정이다.
브라우저가 요소의 크기와 위치를 다시 계산하는 과정으로, 레이아웃 변경이 발생하는 경우 실행됩니다. 비용이 크기 때문에 최적화가 중요합니다.
✅ Reflow가 발생하는 경우
- 요소의 크기(width, height), 위치(top, left, bottom, right) 변경
- display 속성 변경 (ex: display: none → block)
- margin, padding, border 값 변경
- font-size 또는 font-family 변경
- 새로운 요소가 추가되거나 삭제될 때
- 브라우저 창 크기(resize) 변경
- clientWidth, clientHeight, offsetWidth, offsetHeight 등의 속성을 참조할 때 (이 값을 가져오려면 브라우저가 최신 레이아웃을 계산해야 하기 때문)
2) Repaint (화면 다시 그리기)
Repaint는 요소의 스타일(색상, 배경, 그림자 등)이 변경될 때 발생하는 과정이다.
Repaint는 레이아웃을 다시 계산하지 않고, 화면에 다시 그리는 작업만 수행하므로 Reflow보다 성능 부담이 적다.
✅ Repaint가 발생하는 경우
- color, background-color 변경
- visibility 속성 변경 (visibility: hidden → visible) → display: none은 Reflow를 발생시키지만, visibility: hidden은 Repaint만 발생
- box-shadow, outline 변경
- text-shadow, opacity 변경
4.2. Reflow와 Repaint가 실행되는 시점
✅ Reflow 발생 조건: width, height, margin, padding, position 변경, 새로운 요소 추가 등 ✅ Repaint 발생 조건: color, background-color, visibility, box-shadow 변경 등
4.3. Reflow & Repaint 최적화 방법
- display: none 대신 visibility: hidden 사용 → Reflow 방지
- 스타일을 개별 변경하는 대신 클래스 추가/제거 방식 활용
- 애니메이션 최적화: Reflow는 요소의 크기와 위치를 재계산하는 과정이며, Repaint는 시각적 속성(색상, 배경 등)이 변경될 때 발생합니다. 애니메이션을 적용할 때 transform, opacity 속성을 사용하면 Reflow 없이 GPU 가속을 활용할 수 있어 성능을 향상시킬 수 있습니다. 그러나 top, left, width, height 등의 속성을 변경하는 경우 Reflow가 발생하여 성능 저하가 발생할 수 있습니다.
5. 브라우저 저장소와 상태 관리
5.1. 브라우저 저장소 개요
웹 애플리케이션은 클라이언트 측에서 데이터를 저장하기 위해 여러 가지 저장소를 제공합니다. 브라우저 저장소는 데이터의 유지 기간, 보안 수준, 사용 목적에 따라 선택해야 합니다.
5.2. 브라우저 저장소의 종류 및 비교
저장소 종류 | 특징 | 유효 범위 | 용량 제한 | 보안 고려 사항 |
Cookie | 서버와 자동으로 데이터를 주고받을 수 있음. | 모든 요청에서 자동 전송됨. | 약 4KB | XSS 공격에 취약, HttpOnly, Secure, SameSite 설정 필요 |
LocalStorage | 영구 저장 가능, 서버와 자동 전송 없음. | 동일한 도메인 내에서 유지됨. | 5MB 이상 | XSS 공격에 취약, 민감한 데이터 저장 금지 |
SessionStorage | 세션(탭) 종료 시 데이터 삭제됨. | 탭(윈도우) 별로 분리됨. | 5MB 이상 | XSS 공격에 취약, 탭 단위 데이터 관리 가능 |
IndexedDB | 비동기 방식의 대용량 데이터 저장 가능 | 동일한 도메인 내에서 유지됨. | 수백 MB 이상 가능 | 강력한 보안 모델 적용, 데이터 인덱싱 지원 |
5.3. 각 저장소의 활용 방법
✅ Cookie 사용 할 때
- 사용자 인증 정보(예: 세션 토큰) 저장 및 전송
- HttpOnly, Secure, SameSite 속성을 활용하여 보안 강화
✅ LocalStorage 사용 할 때
- 브라우저에 영구적으로 유지해야 하는 데이터(예: 다크 모드 설정, 사용자 환경설정) 저장
- 클라이언트 측에서 빠르게 접근할 필요가 있는 데이터 저장
✅ SessionStorage 사용 할 때
- 로그인 페이지에서 입력한 데이터 유지 (새로고침 시 데이터 보존)
- 단기적인 상태 데이터 저장 (예: 임시 폼 데이터)
✅ IndexedDB 사용 할 때, 유의할 점
- 대량의 구조화된 데이터 저장 (예: 오프라인 캐시, 로컬 데이터베이스)
- 웹 애플리케이션에서 대량의 데이터를 효율적으로 검색 및 조작
- IndexedDB는 NoSQL 기반의 비동기 API를 제공하며, 대량의 데이터를 클라이언트 측에서 저장할 수 있습니다. 트랜잭션을 지원하며, 구조화된 데이터를 효율적으로 인덱싱할 수 있기 때문에 로컬 데이터베이스 저장소로 활용됩니다. 다만, IndexedDB는 상대적으로 속도가 느리므로 단순한 키-값 저장이 필요할 경우 LocalStorage가 더 적합할 수 있습니다.
5.4. 브라우저 저장소 보안 고려 사항
- XSS(Cross-Site Scripting) 공격 방지: LocalStorage, SessionStorage는 클라이언트 측에서 접근 가능하므로, XSS 공격에 취약합니다. 민감한 정보를 저장하지 말고, 쿠키의 HttpOnly 옵션을 활용해야 합니다.
- CORS(Cross-Origin Resource Sharing) 정책: LocalStorage와 SessionStorage는 동일한 도메인에서만 접근할 수 있으므로, 보안적으로 안전하지만 다른 사이트에서 데이터를 공유하려면 쿠키 기반 인증이 필요합니다.
- Storage Quota 제한: LocalStorage 및 SessionStorage는 브라우저마다 저장 용량이 다를 수 있으며, IndexedDB는 용량이 크지만 사용자의 승인 요청이 필요할 수 있습니다.
✅ 셀프 체크
💬 Q1. DOM이 뭘까요?
👉 DOM (Document Object Model)은 브라우저가 HTML을 트리(Tree) 구조로 해석하여 관리하고, JavaScript가 해당 구조를 조작할 수 있도록 만든 객체 모델입니다. DOM은 계층적인 노드(Node)로 구성되며, 브라우저는 이를 기반으로 렌더링을 수행합니다. JavaScript는 DOM API를 통해 문서를 동적으로 변경할 수 있으며, DOM 변경 시 브라우저는 Reflow와 Repaint 과정을 거쳐 화면을 다시 렌더링합니다. 이러한 성능 문제를 해결하기 위해 Virtual DOM, Shadow DOM 등의 최적화 기법이 활용됩니다.
💬 Q2. Reflow와 Repaint가 실행되는 시점에 대해서 설명해주세요
👉 Reflow와 Repaint는 브라우저 렌더링 과정에서 발생하는 주요 과정입니다. 브라우저는 먼저 HTML을 파싱하여 DOM을 생성하고, CSS를 파싱하여 CSSOM을 만든 후, 이를 결합하여 Render Tree를 구성합니다.
이후, 레이아웃을 계산하는 과정인 Reflow가 발생하며, 이때 요소들의 크기와 위치가 결정됩니다. 레이아웃이 결정된 후, 브라우저는 색상, 테두리, 그림자 등을 칠하는 과정인 Repaint를 수행하여 최종적으로 화면에 표시합니다.
Reflow는 width, height, margin, padding, display 등의 변경 시 발생하며, 성능 비용이 크므로 최적화가 필요합니다. 반면, color, background-color, visibility 등의 변경은 Repaint만 유발하여 비교적 가벼운 연산이 수행됩니다.
💬 Q3. Reflow와 Repaint의 차이에 대해서 설명해주세요
👉 Reflow와 Repaint는 브라우저의 렌더링 과정에서 발생하는 중요한 개념입니다.
- Reflow: DOM과 CSSOM을 결합하여 Render Tree를 생성한 후, 요소들의 크기와 위치를 계산하는 과정입니다. 요소의 너비, 높이, 마진, 패딩, 위치 등의 변경이 발생하면 브라우저는 전체 레이아웃을 다시 계산해야 하므로 성능 비용이 큽니다.
- Repaint: Reflow가 완료된 후, 색상, 테두리, 그림자 등의 스타일을 변경하는 과정으로, 레이아웃 재계산 없이 화면을 다시 그리는 작업만 수행하므로 비교적 가벼운 연산입니다.
브라우저 성능을 최적화하기 위해 애니메이션과 변형 효과를 적용할 때는 가속을 활용할 수 있는 속성을 사용하고, 불필요한 Reflow를 줄이는 것이 중요합니다.
💬 Q4. 스크립트를 HTML에서 body 끝에 배치하는 이유는?
👉 <script> 태그를 <body> 끝에 배치하는 이유는 JavaScript가 실행되는 동안 HTML 렌더링이 차단될 수 있기 때문입니다.
브라우저는 HTML을 해석하는 과정에서 <script> 태그를 만나면 먼저 JavaScript를 실행한 후 다시 HTML을 파싱하므로, 중간에 script가 있으면 렌더링 속도가 느려질 수 있습니다.
이를 방지하기 위해 script를 <body> 끝에 배치하거나, defer 속성을 사용하여 HTML 파싱이 끝난 후 실행되도록 최적화할 수 있습니다.
💬 Q5. HTML 렌더링 중에 Script 태그를 만나게 되면 멈추는 이유는?
👉 HTML이 렌더링되는 동안 브라우저가 <script> 태그를 만나면, 해당 JavaScript를 실행하기 위해 HTML 파싱이 일시적으로 중단됩니다. 이는 브라우저의 싱글 스레드(Single Thread) 환경과 렌더링 파이프라인(Rendering Pipeline) 구조 때문입니다.
브라우저는 HTML을 위에서 아래로 파싱하며 DOM 트리를 구성하지만, <script> 태그는 DOM을 조작할 가능성이 있기 때문에 먼저 실행한 후 다시 HTML 파싱을 진행해야 합니다.
이 과정에서 JavaScript의 실행 시간이 길어지면 렌더링이 지연되므로, 최적화를 위해 <script> 태그에 defer 또는 async 속성을 사용할 수 있습니다.
- defer: HTML 파싱이 완료된 후 JavaScript를 실행하며, 실행 순서가 유지됩니다.
- async: JavaScript를 비동기적으로 다운로드 및 실행하지만, 실행 순서는 보장되지 않습니다.
이러한 최적화 기법을 활용하면 HTML 렌더링 차단 문제를 해결하고 웹 성능을 향상시킬 수 있습니다.
💬 Q6. defer와 async의 차이점은 무엇인가요?
👉 defer는 HTML 파싱이 끝난 후 JavaScript가 실행되며, 실행 순서가 보장됩니다. 반면 async는 HTML을 파싱하는 동안 JavaScript를 비동기적으로 다운로드하고 즉시 실행하지만, 실행 순서는 보장되지 않습니다.
💬 Q7. <script> 태그를 <body> 끝에 배치하는 이유는 무엇인가요?
👉 <script> 태그를 <body> 끝에 배치하면 브라우저가 먼저 HTML을 파싱하여 DOM을 완전히 구성한 후 JavaScript를 실행할 수 있으므로, 렌더링 차단을 방지하고 사용자 경험을 향상시킬 수 있습니다.
💬 Q8. JavaScript가 실행 중일 때 브라우저가 멈출 수 있는 경우는 무엇인가요?
👉 JavaScript가 무한 루프에 빠지거나 CPU 연산이 많은 작업(예: 대량의 DOM 조작, 동기적인 데이터 처리 등)을 수행할 경우 브라우저의 메인 스레드가 차단되면서 사용자 인터페이스(UI) 업데이트가 멈출 수 있습니다. 이를 해결하기 위해 Web Worker를 사용하거나, requestAnimationFrame()을 활용하여 UI 업데이트를 최적화할 수 있습니다.
💬 Q9. 브라우저에서 CSS 적용이 완료되기 전에 화면을 먼저 그릴 수도 있나요?
👉 네, 브라우저는 일반적으로 CSS 파일을 다운로드하고 적용한 후 화면을 그립니다. 그러나 CSS가 적용되지 않은 상태에서 먼저 HTML을 표시하는 FOUC(Flash of Unstyled Content) 현상이 발생할 수 있습니다. 이를 방지하기 위해 CSS를 HTML의 <head>에 배치하는 것이 일반적입니다.
💬 Q10. 브라우저에서 CSS 적용이 완료되기 전에 화면을 먼저 그릴 수도 있나요?
👉 네, 브라우저는 기본적으로 HTML을 먼저 파싱하여 DOM을 생성하고, CSS를 비동기적으로 로드합니다. 이 과정에서 CSS 로드가 완료되기 전에 HTML이 먼저 표시되면 FOUC(Flash of Unstyled Content) 현상이 발생할 수 있습니다. 이를 방지하기 위해 CSS를 <head> 태그 내부에 배치하고, critical CSS를 우선 로드하는 방식을 사용할 수 있습니다.
💬 Q11. Cookie, LocalStorage, SessionStorage의 차이점은 무엇인가요?
- Cookie: 클라이언트와 서버 간에 자동으로 전송되며, 용량 제한(약 4KB)이 있습니다.
- LocalStorage: 도메인 단위로 데이터를 영구 저장할 수 있으며, 약 5MB 이상의 용량을 지원합니다.
- SessionStorage: 탭 단위로 데이터를 저장하며, 브라우저를 닫으면 데이터가 삭제됩니다.
💬 Q12. 브라우저 저장소의 보안 이슈와 해결 방법은 무엇인가요?
- Cookie에는 민감한 정보를 저장하지 않고, HttpOnly, Secure, SameSite 속성을 활용하여 보안을 강화해야 합니다.
- LocalStorage 및 SessionStorage는 클라이언트에서 쉽게 접근할 수 있으므로, 토큰 저장 시 XSS(Cross-Site Scripting) 공격에 취약할 수 있습니다.
- 민감한 데이터는 쿠키에 저장하고, 서버에서 인증하는 방식을 사용하는 것이 안전합니다.
💬 Q13. 서버와의 데이터 저장 방식에 따라 어떤 저장소를 선택해야 하나요?
- 클라이언트에서만 데이터가 필요할 경우: LocalStorage 또는 SessionStorage 사용
- 서버와 데이터를 주고받아야 하는 경우: Cookie 사용
- 보안이 중요한 경우: 브라우저 저장소에 민감한 정보를 저장하지 않고, 서버에서 인증
'DEV > FE' 카테고리의 다른 글
Tanstack Table 쓰기 전에 공식문서 읽어보기(번역과 함께) (0) | 2025.04.04 |
---|---|
[FE] this 정리하기 (0) | 2025.02.04 |
[FE] 자바스크립트 비동기 개념 정리 하기 (0) | 2025.01.30 |
[FE] 쉽게 이해하는 Vitest 주요 기능 완성 가이드 (0) | 2024.11.17 |