Paint
픽셀 채우기
레이아웃으로 정해진 영역에 색상·테두리·그림자·텍스트 같은 시각 요소를 실제 픽셀로 그린다.
페인트(Paint)는 레이아웃으로 확정된 각 박스를 실제 픽셀로 바꾸기 위한 '그리기 명령'을 만드는 단계로, 여기서 바로 픽셀이 채워지는 것이 아니라 배경·테두리·텍스트·그림자 등을 어떻게 그릴지 기록한 페인트 레코드(paint record) 즉 디스플레이 리스트(display list)를 생성한다. 이 명령들은 반드시 올바른 순서로 쌓여야 하는데, 그 순서는 스태킹 컨텍스트(stacking context)와 z-index로 결정되며 배경/보더 → 음수 z-index → 블록 → float → 인라인 → (z-index가 auto/0인) 위치 지정 요소 → 양수 z-index 순의 페인트 순서를 따른다. 실제로 픽셀을 채우는 작업은 래스터화(rasterization)라 하며, 디스플레이 리스트를 비트맵으로 변환하는 이 과정은 종종 GPU에서 뒤이은 컴포지트 단계와 함께 수행된다. 어떤 요소의 시각적 속성(색, 배경, 그림자 등 기하와 무관한 속성)만 바뀌면 레이아웃 없이 해당 영역만 다시 그리는 리페인트(repaint)가 일어나며, 이때 브라우저는 화면을 타일 단위로 잘라 바뀐 타일만 다시 래스터화해 비용을 줄인다.
내부 구성
핵심 포인트
- 페인트는 픽셀을 바로 칠하지 않고 '그리기 명령'(paint record / display list)을 기록하는 단계
- 디스플레이 리스트: 배경·보더·텍스트·그림자 등을 그리는 순서가 있는 명령 목록
- 페인트 순서는 스태킹 컨텍스트와 z-index가 결정 (겹침 순서)
- 스태킹 컨텍스트는 z-index만이 아니라 opacity<1, transform, filter, will-change 등으로도 생성
- 래스터화(rasterization): 디스플레이 리스트를 실제 비트맵 픽셀로 변환하는 과정
- 레이어: 독립적으로 그려질 수 있는 콘텐츠 묶음. 리페인트 범위를 격리
- 리페인트(repaint): 기하 변경 없는 시각 속성 변경 시 해당 타일만 다시 래스터화
심화
성능 관점의 핵심은 '무엇이 리페인트를 유발하고, 리페인트가 레이아웃(리플로우)보다 왜 싼가'이다. color, background-color, visibility, box-shadow 같은 속성은 기하를 바꾸지 않으므로 레이아웃을 건너뛰고 페인트부터 다시 하지만, width, top, font-size 같은 속성은 레이아웃→페인트→컴포지트 전체를 유발한다. 더 나아가 transform과 opacity는 (레이어로 승격되어 있으면) 페인트조차 건너뛰고 컴포지트 단계에서만 처리되어 가장 싸다. 이 'layout → paint → composite' 3단 비용 사다리를 이해하고, 애니메이션은 가능하면 transform/opacity로 표현하라는 것이 web.dev의 표준 조언이다. 면접에서 깊이를 보여줄 포인트: z-index가 왜 안 먹히는지를 스태킹 컨텍스트로 설명하는 것이다. 부모가 새 스태킹 컨텍스트를 만들면(opacity<1, transform, filter, will-change, position+z-index, isolation:isolate 등) 자식의 z-index는 그 컨텍스트 내부에서만 유효해서, 아무리 큰 값을 줘도 다른 컨텍스트의 요소 위로 못 올라간다. Chrome DevTools의 'Paint flashing'과 Layers 패널로 어떤 영역이 리페인트되고 어떤 레이어가 생성됐는지 시각적으로 확인할 수 있어 실무 디버깅의 출발점이 된다.
쉽게 말하면 정해진 위치에 물감으로 실제 그림을 칠하는 단계.