에러 처리
이론 정리
기능 구현

이미지 리플로우 문제를 브라우저 렌더링 과정과 함께 이해하기

이미지 리플로우 문제를 브라우저 렌더링 과정과 함께 이해하기

카드몽키 프로젝트 구현 중 이미지 렌더링과 관련한 문제가 발생했고, 적용했던 해결방법을 정리해보았습니다.

⚠️ 문제 정의: 이미지가 UI를 망친다?

카드 UI를 구현하던 중, 가로/세로 비율이 제각각인 카드 이미지들 때문에 난감한 문제가 발생했습니다.

✅ 증상

  • 이미지가 로드되기 전과 후의 레이아웃이 달라지며 전체 UI가 순간적으로 밀림

  • 특히 지연 로딩(loading="lazy")이 작동하는 경우, 스크롤 중 깜빡임 발생

  • 결국 사용자 입장에서 불안정하고 깨져 보이는 인터페이스가 되어버림

원인 분석 : 브라우저는 레이아웃을 미리 알 수 없다.

브라우저가 HTML, CSS, JS를 받아 화면에 그릴 때 다음과 같은 단계를 거칩니다:

  1. HTML 파싱 → DOM 생성

  2. CSS 파싱 → CSSOM 생성

  3. DOM + CSSOM → Render Tree 구성

  4. Layout (Reflow)

    • 각 요소의 위치와 크기 계산

  5. Paint

    • 실제 픽셀 단위로 색상, 텍스트, 이미지 등을 그리는 과정

  6. Composite

    • 여러 레이어를 합성해서 최종 화면을 구성

👉 이 중에서 리플로우는 4번 단계인 Layout과 직접 관련이 있습니다.


⚠️ 리플로우는 왜 발생하나?

리플로우는 다음 상황에서 발생합니다:

  • 요소의 크기나 위치가 변경되었을 때

  • 이미지 등 비동기 콘텐츠가 로드되며 크기가 확정될 때

  • 스크립트나 스타일이 DOM에 영향을 줄 때

즉, 화면에 그려야 할 요소의 레이아웃 정보를 브라우저가 다시 계산해야 하는 상황이 오면 리플로우가 발생합니다. 이건 가볍게 말해도 비싼 작업입니다.


이미지 리플로우의 구체적 시나리오

다음은 실제로 이미지 리플로우가 어떻게 발생하는지를 렌더링 흐름과 함께 설명한 예시입니다:

  1. HTML 파싱 시 <img src="..."> 태그 발견

  2. 하지만 width, height 속성이 없어서 크기를 알 수 없음

  3. Layout 단계에서 이미지 영역은 크기 '0 or auto' 처리, 공간 할당 안 됨

  4. 브라우저는 나머지 요소로 Layout 계산 → Paint 진행

  5. 나중에 이미지가 로드됨

  6. naturalWidth, naturalHeight 값이 들어오며 요소의 크기가 바뀜

  7. 브라우저는 이 변경을 감지하고 Layout 재계산 (Reflow) 발생

  8. 결과적으로 나머지 요소들도 위치가 바뀌고, Paint & Composite 재실행

→ 즉, 이미지 하나로 인해 전체 페이지가 리플로우를 겪는 _비효율적인 상황_이 발생합니다.


✅ 해결방법 : 이미지가 로딩되기 전에 자리를 확보하자

렌더링 과정 중 Layout 단계에서 미리 사이즈를 알려주는 것이 핵심입니다.

1. 이미지 크기 명시하기

HTML에서 width, height 속성을 직접 지정하거나, CSS에서 고정 비율을 지정해야 합니다. 이를 통해 브라우저는 초기 Layout 단계에서 공간을 확보할 수 있습니다.

<img src="..." width="320" height="180" />

2. 비율 기반 컨테이너

이미지의 크기가 불확실하다면, padding-top 트릭을 사용해 비율 기반의 공간 확보를 합니다. 예를 들어서, 이미지의 비율이 16:9 비율이라면, padding-top: 56.25% 를 사용한다.

.image-container { aspect-ratio: 16 / 9; }

또는 JS에서 img.onload 시점에 비율을 계산해서 상태로 반영하는 방식도 있습니다.


📌 결론

  • 리플로우는 브라우저가 Layout을 다시 계산하는 비싼 작업입니다.

  • 이미지가 로딩되며 공간을 바꾸면 이 과정을 불필요하게 반복하게 됩니다.

  • 초기 렌더링 단계에서 이미지의 예상 크기를 확보하는 것만으로도 → 깜빡임 없이 안정적인 UI를 구현할 수 있습니다.


실전에서 내가 했던 것

  • 이미지 로딩 이후 naturalWidth 기반으로 비율 계산

  • 커스텀 훅으로 비율 상태를 추적

  • 이 비율을 기반으로 padding-top 방식의 비율 박스 구현

  • 결과적으로 레이아웃 쉬프트 없이 부드러운 초기 렌더링 구현