스프레이 인터랙션을 만들기 전에 브라우저 내비게이션부터 정리해 보려 했다. 그런데 URL을 입력한 뒤 무슨 일이 일어나는지 따라가다 보니, 그보다 먼저 답해야 할 질문이 있었다.
브라우저는 누가 실행하고, 누가 화면을 그릴까?
마우스를 움직일 때마다 이미지가 나타나는 작은 인터랙션도 결국 CPU가 이벤트를 처리하고, 브라우저가 렌더링 작업을 준비하며, GPU가 화면 합성을 돕는 흐름 위에서 동작한다. 이번 글에서는 스프레이 효과를 구현하기 전에 알아 두면 좋은 브라우저의 기본 구조를 정리한다.
인터랙션을 만들 때 가장 먼저 눈에 보이는 것은 CSS와 JavaScript다. 하지만 “포인터가 움직이면 이미지를 보여 준다”는 코드 한 줄 뒤에는 생각보다 많은 역할이 나뉘어 있다.
이 역할을 한 덩어리로 이해하면 성능 문제도 한 덩어리로 보인다. 반대로 각 역할을 나눠 보면, 스프레이 효과에서 무엇을 JavaScript에 맡기고 무엇을 브라우저의 렌더링 과정에 맡겨야 할지 조금 더 구체적으로 판단할 수 있다.

그림 1. 스프레이 인터랙션도 하드웨어·운영체제·애플리케이션이 이어지는 환경 위에서 실행된다. 출처: NAVER D2
오늘날 브라우저는 일반적으로 하나의 프로그램처럼 보이지만, 내부에서는 여러 프로세스가 협력한다. 대표적으로 브라우저 프로세스와 렌더러 프로세스를 구분해 생각할 수 있다.
브라우저 프로세스는 탭, 주소창, 창 표시, 권한 요청처럼 브라우저 전체와 관계된 일을 담당한다. 사용자가 URL을 입력하거나 새 탭을 열었을 때, 어떤 페이지를 어디에서 열지 조율하는 역할도 여기에 가깝다.
렌더러 프로세스는 실제 웹페이지를 해석하고 보여 주는 쪽에 가깝다. HTML·CSS·JavaScript를 처리하고, 페이지의 레이아웃과 시각 요소를 준비한다.
스프레이 인터랙션의 포인터 이벤트 처리와 DOM 업데이트도 이 흐름 안에서 일어난다. 즉, 내가 작성하는 React 컴포넌트와 CSS 애니메이션은 독립적으로 화면을 바꾸는 것이 아니라 렌더러가 해석하고 그려 가는 작업의 일부다.

그림 2. 브라우저·네트워크·GPU·렌더러 프로세스는 역할을 나누고 서로 통신한다. 출처: NAVER D2
CPU는 복잡한 판단과 순서가 중요한 작업에 적합하다. JavaScript 실행, 이벤트 처리, 상태 계산처럼 “다음에 무엇을 할지”를 결정하는 일은 CPU의 성격과 잘 맞는다.

그림 3. CPU는 복잡하고 순서가 중요한 작업을 처리하는 데 적합하다. 출처: NAVER D2
GPU는 많은 픽셀과 그래픽 작업을 동시에 처리하는 데 강점이 있다. 화면에 여러 레이어를 합성하거나 이미지를 변형해 보여 줄 때, 브라우저는 GPU가 잘 처리할 수 있는 작업을 활용할 수 있다.

그림 4. GPU는 많은 단순 작업을 병렬로 처리하는 데 강점이 있다. 출처: NAVER D2
이 차이를 단순하게 정리하면 다음과 같다.
| 역할 | 주로 떠올릴 수 있는 작업 |
|---|---|
| CPU | 포인터 이벤트 처리, JavaScript 실행, 상태 계산 |
| GPU | 이미지·레이어 합성, 화면에 보이는 픽셀 처리 |
물론 “CSS를 쓰면 자동으로 GPU가 처리한다”거나 “GPU를 쓰면 무조건 빠르다”는 식으로 이해하면 안 된다. 어떤 속성을 바꾸는지, 이미지가 얼마나 큰지, 동시에 몇 개의 요소가 존재하는지에 따라 비용은 달라진다.
중요한 점은 인터랙션을 구현할 때, 매번 문서 전체의 구조를 다시 계산하게 만들기보다 화면에 보이는 변화의 범위를 의식해야 한다는 것이다.
웹페이지는 항상 신뢰할 수 있는 코드만 실행하지 않는다. 어떤 탭의 스크립트가 오래 걸리거나 오류가 나더라도, 주소창과 다른 탭까지 함께 멈추면 브라우저를 사용할 수 없다.
그래서 브라우저는 역할을 나누고, 가능한 한 페이지 단위의 문제를 분리하려 한다. 이 구조는 보안에도 도움이 된다. 웹페이지가 운영체제나 다른 탭의 정보에 직접 접근하지 못하도록 경계를 만들기 때문이다.

그림 5. 브라우저 프로세스는 렌더러·GPU 등 여러 프로세스와 협력해 하나의 페이지를 표시한다. 출처: NAVER D2
인터랙션을 구현하는 입장에서는 이 구조가 보이지 않을 수 있다. 하지만 “한 페이지가 무거워져도 브라우저 전체가 멈추지 않게” 만들기 위한 환경 위에서 우리가 코드를 실행하고 있다는 점은 기억할 만하다.
스프레이 효과는 포인터 위치를 읽고, 그 위치를 바탕으로 시각 요소를 만든다. 이때 다음 질문이 자연스럽게 생긴다.
이 질문은 다음 글에서 다룰 브라우저 내비게이션과도 연결된다. 페이지를 열기 위해 브라우저 프로세스와 렌더러 프로세스가 어떻게 협력하는지 이해하고 나면, 사용자의 입력이 실제 화면 변화로 이어지는 과정도 더 선명하게 볼 수 있을 것 같다.
스프레이 인터랙션은 단순히 이미지를 포인터 근처에 배치하는 작업이 아니었다. 입력을 처리하는 CPU, 웹페이지를 해석하는 렌더러, 화면을 합성하는 GPU가 이어지는 구조 위에서 작은 시각 반응을 설계하는 일이었다.
다음 글에서는 URL 입력부터 네트워크 요청, 응답, 렌더러 전달까지 이어지는 브라우저 내비게이션 과정을 정리해 보려고 한다. 그다음에는 실제 인터랙션 구현에서 requestAnimationFrame, transform, 잔상 관리가 왜 필요한지 이어서 기록할 계획이다.