티스토리 뷰
웹 개발을 하다 보면 내 컴퓨터에선 멀쩡한데, 특정 사용자의 컴퓨터에서만 이미지가 아예 렌더링되지 않는 현상을 마주하곤 합니다.
실제 경험 중 React + WebView2(EXE) 환경에서 발생한 이미지 증발 사건이 있는데 이를 통해, GPU 합성(Compositing)과 레이아웃 타이밍 문제를 파헤쳐 봅니다.
해당 문제는 React 환경에서 발생하는 것이 아닌, css 페인팅 및 합성 과정에서 발생하는 문제입니다.
용어 정리
우선 문제를 정의 전에 알아두고 가면 좋을 용어들을 정리합니다. 아래 용어를 달달 외울필요는 없지만, 아 이런게 있구나 정도만 알면 될 듯 합니다.
1. Stacking Context (쌓임 맥락)
정의: HTML 요소들이 사용자 눈에 보이는 '앞-뒤 순서(Z축)'를 결정하는 가상의 그룹입니다.
- 비유: 포토샵의 '레이어 그룹(Group)'과 같습니다.
- 특징: 특정 속성(opacity, transform, z-index, overflow: hidden 등)을 주면 브라우저는 새로운 그룹을 만듭니다. 이 그룹 안에 갇힌 자식들은 부모라는 '그룹' 안에서만 순서를 바꿀 수 있고, 부모를 넘어서 앞으로 나올 수 없습니다.
- 이번 이슈와의 연관: 부모가 overflow: hidden으로 새로운 맥락을 만들면서, 자식(SVG)을 관리하는 '기준점'이 생성된 것입니다.
2. Composited Layer (합성 레이어)
정의: 성능 최적화를 위해 브라우저가 일반적인 문서 흐름(2D)에서 떼어내어 GPU 메모리에 직접 올린 독립된 레이어입니다.
- 비유: 투명한 '아크릴판'입니다.
- 특징: absolute, transform, will-change 등이 적용된 요소는 브라우저가 "이건 따로 관리하는 게 빠르겠다"라고 판단하여 별도의 아크릴판에 그려버립니다.
- 이번 이슈와의 연관: absolute로 띄운 SVG가 바로 이 '독립된 아크릴판'이 되어 공중에 붕 떠 있는 상태가 된 것입니다.
3. Layer Promotion (레이어 격상)
정의: 일반 요소가 CPU가 그리는 방식에서 벗어나 GPU가 관리하는 '합성 레이어'로 승격되는 과정을 말합니다.
- 발생 조건: 3D 변환(translateZ), 애니메이션, 혹은 복잡한 absolute 배치가 있을 때 브라우저가 판단하여 격상시킵니다.
- 문제점: 격상된 레이어는 성능은 좋지만, 부모(일반 레이어)와의 물리적 거리가 생기기 때문에 둘을 합치는 연산이 추가로 필요합니다.
4. GPU Compositing (GPU 합성)
정의: 쪼개진 여러 개의 레이어(아크릴판)들을 순서에 맞게 겹쳐서 하나의 최종 화면으로 만드는 작업입니다.
- 역할: 이 단계에서 GPU는 부모 레이어의 overflow: hidden 경계선을 계산해서, 그 밖에 삐져나온 자식 레이어 부분을 잘라냅니다(Clipping).
- 이번 이슈의 핵심: 특정 PC의 GPU 드라이버가 "2D 종이(부모)의 구멍에 맞춰 3D 아크릴판(자식)을 자르는 계산"에 실패하여 이미지를 투명하게 날려버린 단계입니다.
5. Rasterization (래스터화)
정의: 벡터 데이터(SVG의 점과 선)를 브라우저가 실제 화면에 뿌릴 수 있는 픽셀(점) 데이터로 변환하는 과정입니다.
- 참고: 메모리가 부족하거나 GPU 가속에 문제가 생기면, 이 래스터화 과정이 생략되거나 오류가 나면서 이미지가 깨지거나 안 보일 수 있습니다.
그렇다면 어떤 구조였는가?
<div style="position: relative; overflow: hidden; height: auto;">
<div style="position: absolute; top: 0; left: 0;">
<svg>...</svg>
</div>
</div>
위 구조를 가지고 아래와 같은 이슈가 발생합니다.
Layer 1 (부모): overflow: hidden으로 인해 새로운 Stacking Context 형성. 일반적인 2D 렌더링 층에 머무름.
Layer 2 (자식): absolute + SVG 조합. 브라우저가 성능을 위해 이를 GPU 합성 레이어(Composited Layer)로 격상시켜 공중에 띄움 (3D 아크릴판 상태).
The Conflict (합성 단계): GPU는 Layer 1(부모)의 경계선에 맞춰 Layer 2(자식)를 잘라내야 함.
- 특정 저사양 GPU/구형 드라이버는 이 "2D-3D 교차 클리핑" 연산을 수행하다가 오류(Artifact) 발생.
- 결과: 계산에 실패한 GPU는 안전을 위해 자식 레이어를 투명(Transparent) 처리함.
왜 "하필" 그 컴퓨터에서만 발생할까?
사용자의 RAM이 16GB로 충분하더라도 문제는 발생할 수 있습니다. 이는 하드웨어 용량보다는 '환경의 조합' 문제이기 때문입니다.
- GPU 드라이버 버전: 최신 WebView2 엔진을 쓰더라도, 실제 그림을 그리는 GPU 드라이버가 구형이면 브라우저의 최신 합성 명령을 이해하지 못합니다.
- 하드웨어 가속(Hardware Acceleration): 하드웨어 가속이 켜져 있으면 GPU가 무리하게 계산을 시도하다 오류가 나고, 꺼져 있으면 CPU가 처리하느라 속도가 느려집니다.
- 내장 그래픽의 한계: 인텔 내장 그래픽(iGPU)은 VRAM을 시스템 RAM과 공유합니다. 다른 프로그램이 메모리를 많이 점유하면 GPU가 쓸 여유 공간이 줄어들어 복잡한 레이어 합성(Compositing)을 가장 먼저 포기하게 됩니다.
그렇다면 어떻게 해결해야 하는가?
이런 문제는 논리적인 문제보다는 보통 브라우저, 하드웨어간의 통신 문제로 인한 오류가 더 많습니다.
그렇기 때문에 명시적으로 동기화를 해준다거나, 렌더링 범위를 한정적으로 가져가면 됩니다.
.parent {
transform: translateZ(0); /* 부모도 3D 레이어로 격상 */
overflow: hidden;
}
.parent {
contain: paint; /* 이 영역 밖은 절대 안 그리니 안심하고 계산해! */
}
이러한 문제는 많이 만나볼 수 없는 문제이고 보통 엔진 업데이트를 진행하면 자동으로 해결되는 경우가 많아 참고 바랍니다.
'개발.. > React' 카테고리의 다른 글
| React 에서 데이터 패칭 / 코드 스플리팅 최적화 (0) | 2025.09.10 |
|---|---|
| Zustand 상태 접근 방식 비교 (0) | 2025.04.15 |
| React v19 + AWS S3 + github actions 를 이용한 프로젝트 배포 (0) | 2025.04.07 |
| React 에서 FullCalendar 사용하기 (0) | 2024.08.16 |
| vitest + React Testing Library 사용하여 테스트 케이스 만들기 (0) | 2024.08.11 |
- Total
- Today
- Yesterday
- vscode
- 티스토리챌린지
- nuxt2
- 모노레포
- claude code
- nextjs13
- seo
- ChatGPT
- nextjs14
- claude
- nodejs
- React
- Zustand
- svelte
- vue composition api
- AWS
- 오블완
- github
- NextJS
- Vite
- openAI
- Git
- Github Actions
- nextjs15
- NUXT
- 깃허브
- 타입스크립트
- 서버 to 서버
- Ai
- cors
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
