Skip to content

중괄호에서 픽셀로

URL에서 상호작용으로’ 시리즈 세 번째인 이번 글은 브라우저가 CSS를 이용해 중괄호를 픽셀로 만드는 방법을 살펴본다. 나아가 최종 사용자의 상호작용이 이 처리 과정에 어떻게 영향을 미치는지 간단히 다룰 것이다. 다룰 범위가 넓다. 그러니 <좋아하는 음료 이름을 넣으시오>를 한 잔 준비하고 시작하자.

해석

시리즈 두 번째 글 ‘태그에서 DOM으로’에서 배운 것과 비슷하게 브라우저가 CSS를 다운로드하고 나면, 발견되는 모든 CSS로 그림을 그리기 위해 CSS 해석기를 준비한다. 해석 대상은 개별 문서에 있는 CSS나 <style> 태그 안, DOM 요소의 인라인inline style 속성에 있는 CSS가 될 수도 있다. 모든 CSS는 문법 명세에 따라 해석되고 토큰으로 변환된다. 다 처리하고 나면 모든 선택자와 속성, 각 속성 값으로 이뤄진 데이터 구조가 생성된다.

예컨대 다음과 같은 CSS가 있다고 하자.


이 코드는 나중에 활용하기 좋게 다음과 같은 데이터 구조를 만든다.

선택자 속성
.fancy-button background-color rgb(0,255,0)
.fancy-button border-width 3px
.fancy-button border-style solid
.fancy-button border-color rgb(255,0,0)
.fancy-button font-size 1em

주목할 만한 것은 브라우저가 background와 border 축약 문법을 긴 문법의 변형태로 풀었다는 것이다. 축약 문법은 주로 개발자를 위한 것이다. 이때부터 브라우저는 풀어 쓴 긴 형태만 다룬다.

이어서 엔진은 DOM 트리를 구축한다. 트래비스 릿헤드Travis Leithead가 ‘태그에서 DOM으로’에서 다룬 내용이다. 아직 읽지 않았다면 그것부터 읽기 바란다. 기다리겠다.

계산

마주한 콘텐츠에 있는 모든 스타일을 해석했으므로 이제 스타일 계산을 할 시간이다. 모든 값에는 변환할 수 있는 표준화한 계산 값이 있다. 계산 단계를 끝내고 나면 크기에 관한 모든 값이 auto, 퍼센트, 픽셀 셋 중 하나로 줄어든다. 명확히 하기 위해 웹 개발자가 작성한 값이 다음 계산에서 어떤 값이 되는지 몇 가지 예를 살펴보자.

웹 개발자 계산 값
font-size: 1em font-size: 16px
width: 50% width: 50%
height: auto height: auto
width: 506.4567894321568px width: 506.46px
line-height: calc(10px + 2em) line-height: 42px
border-color: currentColor border-color: rgb(0,0,0)
height: 50vh height: 540px
display: grid display: grid

데이터 저장소에 있는 모든 값을 계산했다. 이제 캐스케이드를 다룰 차례다(캐스케이드는 ‘계단식 폭포’라는 뜻으로 CSSCascading Style Sheet의 C에 해당한다. 정의된 CSS 속성을 각 요소에 적용할 때 우선순위를 매기는 원리를 캐스케이드라고 부른다ㅡ역주).

캐스케이드

다양한 소스에서 CSS가 올 수 있으므로 브라우저에는 주어진 요소에 어떤 스타일을 적용할지 정하는 방법이 필요하다. 이를 위해 브라우저는 특정도specificity라는 공식을 사용한다. 특정도 공식은 선택자가 사용한 태그와 클래스, id, 속성 선택자, !important 선언 개수를 센다. 요소에 인라인 style 속성으로 매긴 스타일은 <style> 블록이나 외부 스타일 시트에 있는 것보다 우선 적용되고, 만약 웹 개발자가 값에 !important를 이용했다면 그 값은 위치와 상관없이 모든 CSS에 우선 적용된다. 물론 인라인 속성에 있는 !important는 다른 곳에 있는 !important에 우선한다.

Graphic showing a hierarchy for determining CSS priority

이를 명확하게 하기 위해 선택자를 몇 개 살펴보고 특정도 점수가 어떻게 되는지 보자.

선택자 특정도 점수
li 0 0 0 0 1
li.foo 0 0 0 1 1
#comment li.foo.bar 0 0 1 2 1
<li style="color: red"> 0 1 0 0 0
color: red !important 1 0 0 0 0

그렇다면 특정도가 같을 때 브라우저 엔진은 어떻게 할까? 주어진 선택자가 두 개 이상이고 특정도가 같다면 승자는 문서의 마지막에 나타나는 선택자다. 다음 예에서 div의 배경은 파란색이 된다.


.fancy-button 예를 조금 더 확장해보자.


CSS는 다음과 같은 데이터 구조를 만든다. 이 글 내내 이 코드를 계속 작성해나갈 것이다.

선택자 속성 특정도 점수 문서에 등장하는 순서
.fancy-button background-color rgb(0,255,0) 0 0 0 1 0 0
.fancy-button border-width 3px 0 0 0 1 0 1
.fancy-button border-style solid 0 0 0 1 0 2
.fancy-button border-color rgb(255,0,0) 0 0 0 1 0 3
.fancy-button font-size 16px 0 0 0 1 0 4
div .fancy-button background-color rgb(255,255,0) 0 0 0 1 1 5

원천 이해하기

시리즈 첫 번째 글인 ‘서버에서 클라이언트로’에서 알리 알라바스Ali Alabbas는 원천origin을 브라우저 탐색과 연관해 검토했다. CSS 역시 원천이 있으나 목적이 다르다.

  • 사용자: 사용자가 유저 에이전트 전체 영역에 설정한 모든 스타일
  • 작성자: 웹 개발자의 스타일
  • 유저 에이전트: CSS를 이용하고 렌더링할 수 있는 모든 것(예: 웹 브라우저)

각 원천 캐스케이드는 사용자, 작성자, 유저 에이전트의 순서로 강력한 힘을 발휘한다. 데이터 세트를 좀 더 확장하고 사용자가 자기 브라우저의 최소 글자 크기를 2em으로 맞췄을 때 무슨 일이 벌어지는지 보자.

원천 선택자 속성 특정도 점수 문서에서 등장하는 순서
Author .fancy-button background-color rgb(0,255,0) 0 0 0 1 0 0
Author .fancy-button border-width 3px 0 0 0 1 0 1
Author .fancy-button border-style solid 0 0 0 1 0 2
Author .fancy-button border-color rgb(255,0,0) 0 0 0 1 0 3
Author .fancy-button font-size 16px 0 0 0 1 0 4
Author div .fancy-button background-color rgb(255,255,0) 0 0 0 1 1 5
User * font-size 32px 0 0 0 0 1 0

캐스케이드 계산하기

브라우저는 모든 원천에서 선언 전체에 걸쳐 데이터 구조를 만든 다음 특정도에 따라 정렬한다. 우선 원천에 따르고 그다음 특정도에 따르며 마지막으로 문서에 등장한 순서에 따라 정렬한다.

원천 ⬆ 선택자 속성 특정도 점수 ⬆ 문서에 등장하는 순서 ⬇
User * font-size 32px 0 0 0 0 1 0
Author div .fancy-button background-color rgb(255,255,0) 0 0 0 1 1 5
Author .fancy-button background-color rgb(0,255,0) 0 0 0 1 0 0
Author .fancy-button border-width 3px 0 0 0 1 0 1
Author .fancy-button border-style solid 0 0 0 1 0 2
Author .fancy-button border-color rgb(255,0,0) 0 0 0 1 0 3
Author .fancy-button font-size 16px 0 0 0 1 0 4

이것은 .fancy-button에서 ‘승리한’ 속성과 값의 결과다(표 위쪽이 우선한다). 위의 표를 예로 들면 사용자의 브라우저 설정이 웹 개발자의 스타일보다 우선한다는 것을 알 수 있다. 마지막으로 브라우저는 표시된 선택자에 맞는 모든 DOM 요소를 찾아서 일치하는 요소에 계산된 스타일을 적용한다. 이 경우에는 .fancy-button이 있는 div다.

속성
font-size 32px
background-color rgb(255,255,0)
border-width 3px
border-color rgb(255,0,0)
border-style solid

캐스케이드 작동 방법을 더 알고 싶다면 공식 명세를 살펴보자.

CSS 객체 모델

많은 것을 했지만 아직 하지 않은 게 있다. 바로 CSS 객체 모델(CSSOM) 갱신이다. CSSOM은 document.stylesheets에 있다. 우리는 CSSOM을 갱신해서 지금까지 해석하고 계산한 모든 것을 CSSOM이 나타내도록 해야 한다.

웹 개발자는 아마 이 정보가 무엇인지도 모른 채 활용하고 있을 것이다. 예컨대 getComputedStyle()을 호출할 때 필요하다면 위에서 말한 처리 과정이 벌어진다.

레이아웃

이제 스타일을 적용한 DOM 트리tree가 생겼다. 시각적인 표시를 위해 트리를 쌓아 올리는 처리 과정을 시작할 차례다. 모든 최신 브라우저 엔진에는 박스 트리로 불리는 이 트리가 있다. 박스 트리를 구성하기 위해 우리는 DOM 트리를 따라 내려가면서 CSS 박스를 생성한다. CSS 박스 각각에는 바깥 여백margin, 외곽선border, 안 여백padding과 내용 박스가 있다.

여기서는 다음과 같은 CSS 레이아웃 개념을 검토할 것이다.

  • 양식화 문맥Formatting context, FC: 다양한 양식화 문맥이 있다. 대부분은 웹 개발자가 요소의 display 값을 변경해서 발동한다. 가장 일반적인 양식화 문맥은 블록(블록 양식화 문맥 Block Formatting Context, BFC), 플렉스flex, 그리드grid, 테이블 셀table-cells과 인라인inline이다. 다른 CSS도 새로운 양식화 문맥을 강제로 설정할 수 있다. position: absolute나 float 혹은 다단을 활용해서 그렇게 할 수 있다.
  • 포함 블록Containing block: 현재 요소의 스타일에 영향을 주는 조상ancestor 블록이다.
  • 인라인 방향Inline direction: 요소의 쓰기 방식에 좌우되는 텍스트 배치 방향이다. 라틴 기반 언어에서는 가로축이고 한중일CJK 언어에서는 세로축이다(라틴 기반 언어는 알파벳이라고 생각하면 이해하기 쉽다. 한중일 인라인 방향은 라틴 기반 언어처럼 가로축이다. 여기서 한중일 언어의 인라인 방향이 세로축이라는 것은 예전 방식으로 세로쓰기를 할 때 그렇다는 것이다ㅡ역주).
  • 블록 방향Block direction: 인라인 방향과 완전히 똑같이 작동하지만 인라인 방향 축과 수직을 이룬다. 따라서 라틴 기반 언어에서는 세로축이고 한중일 언어에서는 가로축이다(위와 마찬가지로 한중일 언어는 예전 방식으로 세로쓰기를 할 때를 말하는 것이다ㅡ역주).

AUTO 결정

계산 단계에서 크기 값이 auto, 퍼센트, 픽셀 세 값 중 하나가 될 수 있다고 한 것을 기억해보자. 레이아웃의 목적은 모든 박스의 크기와 위치를 가늠해서 채색을 할 수 있도록 박스 트리에 배치하는 것이다. 나는 시각에 민감한 사람으로서 박스 트리가 어떻게 구축되는지 쉽게 이해할 수 있는 예제를 찾았다. 따라오기 쉽게끔 CSS 박스 전부가 아니라 주요 박스principal box(요소에 지정된 스타일을 구현하고 자식 요소와 내용을 담는 박스. 여기서는 바깥 여백, 외곽선, 안 여백, 내용 박스를 생략하겠다는 뜻으로 주요 박스라는 용어를 사용했다ㅡ역주)만 보여줄 것이다. 다음 코드를 사용한 기본적인 ‘Hello world’ 레이아웃을 보자.


Diagram showing an HTML body, a CSS box, and a property of width with a value of 50 pixels
브라우저는 body 요소에서 시작한다. 우리는 너비가 50px이고 기본 높이가 auto인 주요 박스를 만들었다.
Diagram showing a tree with a CSS box for the body and a CSS box for a paragraph
이제 브라우저는 문단(<p> 태그가 생성한 요소를 그냥 문단paragraph이라 부른다ㅡ역주)으로 이동해 문단의 주요 박스를 만들었다. 그리고 문단에는 기본적으로 바깥 여백이 있기 때문에 보디body 높이에 영향을 미쳐 모양에 반영된다.
Diagram showing a tree with a CSS box for the body and a CSS box for a paragraph, and now a line box appended to the end, which has an arrow pointing back to the paragraph CSS box
이제 브라우저는 ‘Hello world’ 텍스트로 이동한다. 이것은 DOM에서 텍스트 노드node다. 이걸로 우리는 레이아웃 안쪽에 라인 박스를 만든다. 텍스트가 보디를 벗어났다는 점을 주목하라. 다음 단계에서 이 부분을 다룰 것이다.
Diagram showing a tree with a CSS box for the body and a CSS box for a paragraph, and now a line box appended to the end, which has an arrow pointing back to the paragraph CSS box
‘world’가 영역을 벗어났고 우리는 overflow 속성을 기본값에서 변경하지 않았다. 그렇기 때문에 브라우저 엔진은  부모 요소에 되돌아가 영역을 벗어난 텍스트가 있음을 알린다.
Diagram showing a tree with a CSS box for the body and a CSS box for a paragraph, and now two line boxes appended to the end
자식 요소가 전체 내용의 레이아웃을 완료하지 못했다는 소식을 들은 부모 요소는 스타일이 완전히 똑같은 라인 박스를 복제하고 레이아웃 생성을 완료하는 데 필요한 정보를 전달한다. 레이아웃이 완료되면 브라우저는 박스 트리의 상단으로 올라가면서 아직 결정하지 않은 auto나 퍼센트 기반 값을 결정한다. 그림을 보면 보디와 문단이 이제 ‘Hello World’ 전체를 감싸고 있는 것을 볼 수 있다. height가 auto로 설정돼 있기 때문이다.

플롯 다루기

이제 좀 더 복잡한 곳으로 가보자. ‘Share It’ 버튼이 있는 일반적인 레이아웃을 다룰 것이다. 그리고 그 버튼을 라틴 문장(로렘 입숨)의 왼쪽으로 플롯float할 것이다. 플롯 자체는 ‘나눠서 맞춤shrink-to-fit’문맥으로 여겨진다. 그 이유는 크기 값이 auto인 경우 박스가 내용을 나눠서 다음 줄로 내릴 것이기 때문이다. 플롯된 박스는 이 레이아웃 유형에 해당하는 박스 유형 중 하나다. 하지만 이 유형에 해당하는 다른 박스도 많다. 예를 들면 절대적absolute으로 위치를 잡은 박스(position: fixed 요소 포함)나 auto 기반으로 크기를 잡은 표의 칸table cell이 있다. 버튼 시나리오 코드를 보자.


Diagram of a box tree with a CSS box for an article, a CSS box for a button floated left, and a line box
‘Hello world’ 예제와 같은 방식으로 처리 과정이 시작되므로 플롯된 버튼을 다루기 시작하는 부분까지는 건너뛰겠다.
Diagram of a box tree with a CSS box and a line box that calculates the maximum and minimum width for the button
플롯이 새로운 블록 양식화 문맥BFC을 만들어내고 BFC가 ‘나눠서 맞춤’ 문맥이기 때문에, 브라우저는 내용 측정content measure으로 불리는 특정 유형의 레이아웃을 수행한다. 이 방법은 무한한 공간에서 수행된다는 한 가지만 제외하면 다른 레이아웃과 동일하게 보인다. 이 단계에서 브라우저는 최대 너비와 최소 너비에 BFC 트리를 놓는 역할을 한다. 텍스트가 있는 버튼의 최소 크기는 다른 CSS 박스(바깥 여백, 외곽선, 안 여백, 내용 박스ㅡ역주)를 포함해 가장 긴 단어의 크기다. CSS 박스들을 더해서 텍스트가 한 줄에 모두 들어간 것 버튼의 최대 너비다.  (주의: 여기서 버튼의 색깔은 코드와 무관하다. 그저 보기 좋으라고 한 것이다.)
Diagram of a box tree with a CSS box for an article, a CSS box for a button floated left, and a line box, with the CSS box for the button now communicating the min and max width back up to the CSS box for the article
이제 최소 너비가 86px이고 최대 너비가 115px이라는 것을 알게 됐다. 이 정보를 부모 박스에 전달해 적절하게 너비를 결정하고 위치를 정할 수 있게 한다. 이 시나리오에서는 최대 너비일 때의 플롯이 들어갈 수 있는 공간이 있으므로 버튼은 최대 너비로 설정한다.
Diagram of a box tree with a CSS box for an article with two branches: a CSS box for a button floated left and a CSS box for a paragraph. The CSS box for the article is communicating the min and max width for the button to the paragraph.
브라우저가 표준을 지켜 콘텐츠가 플롯된 요소 주변을 감싸게 하기 위해 브라우저는 article BFC의 모양geometry(측정값)을 변경한다. 이 모양은 레이아웃을 그리는 동안 사용하기 위해 문단(<p> 태그 부분ㅡ역주)에 전달된다.
Diagram of a box tree with a CSS box for an article with two branches: a CSS box for a button floated left and a CSS box for a paragraph. The paragraph has not been parsed yet and is on one line overflowing the parent container.
여기부터는 브라우저가 첫 번째 예제에서 본 것과 같은 레이아웃 처리를 따른다. 하지만 모든 인라인 내용의 인라인, 블록 시작 위치는 플롯된 요소가 차지한 제한 구역의 바깥이다.
Diagram of a box tree with a CSS box for an article with two branches: a CSS box for a button floated left and a CSS box for a paragraph. The paragraph has now been parsed and broken into four lines, and there are four line boxes in the diagram to show this.
브라우저는 계속 트리를 훑어 내려가고 노드를 복제하면서 방금 전 제한 구역의 블록 위치로 이동한다. 이것은 텍스트의 마지막 줄이(직전 줄처럼) 콘텐츠 박스의 맨 앞에서 인라인 방향으로 갈 수 있도록 해준다. 그러고 나서 브라우저는 필요하면 auto와 퍼센트 값을 결정하면서 트리를 거슬러 올라간다.

나누기 이해하기

레이아웃 동작 방식에서 마지막으로 다룰 것은 나누기fragmentation다. 웹 페이지를 출력해본 일이 있거나 CSS 다단multi-column을 사용해본 적이 있다면 나누기 개념을 이해하는 데 유리할 것이다. 나누기는 내용을 서로 다른 모양geometry에 맞춰 나누는 논리다(여러 페이지, 구역, 단으로 내용이 나뉠 때 CSS가 이를 처리하는 방법ㅡ역주). CSS 다단을 사용하는 예제를 살펴보자.


Diagram of a box tree showing a CSS box for a body and a multicol box for a div
브라우저가 다단 양식화 문맥 박스를 인식하면 설정된 숫자만큼 열이 있는 것으로 간주한다.
Diagram of a box tree showing a CSS box for a body and a multicol box for a div, now with a fragmentainer CSS box created under the div
브라우저는 앞선 복제 모델과 유사한 식으로 작동하는데 작성자가 설정한 열 개수에 맞춰 적절한 크기로 나눈 열을 생성한다.
Diagram of a box tree showing a CSS box for a body and a multicol box for a div, now with a CSS box for each column and a line box for each line within each column
그러고 나서 브라우저는 앞서 한 것처럼 가능한 한 많은 행을 배치한다. 이후 또 다른 열을 만들고 계속해서 레이아웃을 생성한다.

채색

자, 이제 어디까지 왔는지 살펴보자. 모든 CSS 코드를 찾아서 해석했고 캐스케이드를 비교해 DOM 트리에 적용했으며 레이아웃을 생성했다. 하지만 색, 외곽선, 그림자 등 레이아웃 디자인은 적용하지 않았다. 이것을 채색painting이라고 한다.

채색은 CSS에 대략적으로만 표준화돼 있는데 순서는 다음과  같이 간단하다(전체 내용을 CSS 2.2 Appendix E에서 볼 수 있다).

  • 배경
  • 외곽선
  • 그리고 내용

그래서 앞의 ‘SHARE IT’ 버튼으로 이 처리 과정을 따른다면 이렇게 보일 것이다.

Graphic showing progressive passes of a box: first the background, then the border, the the content

완료하고 나면 비트맵으로 변환된다. 맞다. 궁극적으로 모든 레이아웃 요소는 (심지어 텍스트도) 내부적으로는 이미지가 된다.

Z-INDEX 관해

오늘날 웹사이트 대부분은 단일 요소로 이뤄져 있지 않다. 더군다나 우리는 때때로 특정 요소를 다른 요소 앞에 나타나게 하고 싶어 한다. 그렇게 하려면 z-index의 힘을 이용해 한 요소를 또 다른 요소 위에 겹쳐 놓으면 된다. 이것은 마치 디자인 소프트웨어에서 레이어로 작업하는 것과 비슷하다. 하지만 레이어가 있는 곳은 오직 브라우저의 컴포지터Compositor(최신 브라우저에서 레이어를 합성해서 화면을 그리는 역할을 하는 부분ㅡ역주) 안이다. 마치 z-index로 새 레이어를 만드는 것처럼 보이지만 그렇지 않다. 그렇다면 우리가 하는 건 뭘까?

우리는 새로운 쌓임 맥락stacking context을 만든다. 예시를 보자.



z-index를 사용하지 않으면 위 문서는 나온 순서대로 ‘Item 1’ 위에 ‘Item 2’를 그릴 것이다. 하지만 z-index 때문에 그리는 순서가 달라진다. 앞서 레이아웃에서 한 것처럼 각 단계를 밟아보자.

Diagram of a box tree with a basic layout representing a root stacking context. One box has a z-index of one, another box has a z-index of 2.
브라우저는 최상위root 박스에서 시작한다. 우리는 배경을 그린다.
The same layout, but the box with the z-index of 1 is now rendering.
이후 브라우저는 문서상의 순서를 벗어나 더 낮은 등급의 쌓임 맥락으로 이동한다(Item 2). 그리고 위에서 본 대로 같은 규칙을 따라 요소를 그리기 시작한다.
The same layout, but the box with the z-index of 2 is now rendering on top of the previous box
그러고 나서 다음 최상위 쌓임 맥락(Item 1)으로 이동해서 CSS 2.2에 정의된 순서를 따라 그린다.

z-index는 색상과 관련이 없고 어떤 요소가 사용자에게 표시될지와 관련 있다. 따라서 어떤 텍스트와 색상이 보일지에 관한 작업에 사용한다.

합성

채색 단계에서 컴포지터로 전달된 가장 작은 단일 비트맵이 있다(컴포지터는 합성기로 번역할 수 있을 테지만 일반적으로 컴포지터라고 하므로 따로 번역하지 않는다ㅡ역주). 컴포지터의 역할은 하나 이상의 레이어를 생성하고 사용자가 볼 수 있도록 화면에 비트맵을 표시하는 것이다.

여기서 나올 법한 질문은 ‘비트맵이나 컴포지터 레이어가 여러 개 필요한 사이트가 있는 이유는 뭔가?’이다. 그동안 본 예제에서는 그렇지 않았지만 조금 더 복잡한 사례를 보자. MS 오피스 개발팀이 클리피Clippy(MS 오피스 2000부터 2003까지 도움말 제공 용도로 화면 구석에 튀어나왔던 캐릭터다. 별 도움은 안 되고 방해만 됐기 때문에 놀림거리가 됐다ㅡ역주)를 온라인에 다시 데려오려 한다고 가정해보자. 그리고 CSS transform을 이용해 클리피가 통통 튀어 주의를 끌게 하려 한다고 해보자.

클리피를 움직이게 하는 코드는 대략 이렇다.


웹 개발자가 클리피를 무한히 움직이기 원한다는 것을 브라우저가 이해하면 두 가지 선택지가 생긴다.

  • 모든 애니메이션 프레임마다 다시 그리는 단계로 돌아가서 새로운 비트맵을 생성해 컴포지터로 돌려보낸다.
  • 두 가지 다른 비트맵을 생성하고 컴포지터가 애니메이션이 적용된 레이어만 움직이도록 한다.

대부분의 환경에서 브라우저는 두 번째 옵션을 선택하고 다음을 생성할 것이다(예제에서는 워드 온라인Word Online이 생성하는 레이어의 양을 의도적으로 단순화했다).

Diagram showing a root composite layer with Clippy on his own layer

그러고 나서 브라우저는 클리피 비트맵을 적절한 위치에 재합성해 주기적으로 움직이는 애니메이션을 만들 것이다. 이것은 성능 면에서 매우 유리하다. 많은 브라우저 엔진에서 컴포지터는 자신만의 스레드를 다룸으로써 메인 스레드가 멈추지 않게 해준다. 만약 브라우저가 첫 번째 선택지를 고른다면 같은 결과를 얻기 위해 모든 프레임마다 멈춰야할 것이다. 그러면 최종 사용자의 성능과 반응성 측면에 부정적인 영향을 미칠 것이다.

A diagram showing a layout with Clippy, with a chart of the process of rendering. The Compose step is looping.

상호작용한다는 환상 만들어내기

여기까지 배웠듯이 우리는 모든 스타일과 DOM으로 생성한 이미지를 최종 사용자에게 표시했다. 그러면 브라우저는 상호작용한다는 환상을 어떻게 만들까? 이미 알 거라고 생각하지만 ‘SHARE IT’ 버튼을 상호작용하는 예제로 살펴보자.


추가한 것은 사용자가 버튼 위에 마우스를 올려놨을 때 버튼의 배경과 글자색을 바꾸도록 브라우저에 알려주는 가상 클래스밖에 없다. 그렇다면 브라우저는 이것을 어떻게 다룰지 의문이 생긴다.

브라우저는 다양한 입력을 지속적으로 추적한다. 그리고 그 입력이 움직이는 동안 브라우저는 히트 테스팅hit testing으로 불리는 처리 과정을 수행한다. 이 예제에서 처리 과정은 다음과 같다.

A diagram showing the process for hit testing. The process is detailed below.

  1. 사용자가 버튼 위로 마우스를 움직인다.
  2. 브라우저는 마우스가 움직였다는 이벤트를 발생하고 히트 테스팅 알고리즘으로 진입한다. 이 알고리즘은 근본으로 들어가면 ‘마우스가 건드린 박스(들)는 무엇인가?’라고 묻는다.
  3. 히트 테스팅 알고리즘은 ‘SHARE IT’ 버튼과 연결된 박스를 돌려주는 것으로 답한다.
  4. 브라우저는 ‘마우스가 네 위에 떠 있을 때 해야 하는 게 있니?’라고 질문한다.
  5. 이 박스와 자식들에 대한 스타일과 캐스케이드가 재빨리 실행되고 결론이 나온다. 답은 ’그렇다’이다. 선언된 블록 안에 채색에만 적용되는 :hover 가상 클래스가 있다.
  6. 해당 스타일을 앞 단계에서 배운 것처럼 DOM 요소에 적용한다. 이 경우 DOM 요소는 button이다.
  7. 옛 레이아웃을 건너뛰고 바로 새 비트맵을 그린다.
  8. 새 비트맵이 컴포지터에 전달되고 사용자에게 표시된다.

이 과정은 상호작용한다는 느낌을 효과적으로 사용자에게 전한다. 브라우저는 단지 오렌지색 이미지를 초록색 이미지로 교체한 것 뿐인데 말이다.

이제 됐다!

연재한 ‘중괄호를 CSS가 처리하는 방법’부터 ‘브라우저가 픽셀을 표시하는 방법’까지 미스터리의 일부가 해소됐기를 바란다. 이 과정에서 CSS가 어떻게 해석되는지, 값이 어떻게 계산되는지, 캐스케이드가 실제로 어떻게 작동하는지 다뤘다. 그리고 레이아웃, 채색, 컴포지터의 작동까지 깊게 파고들었다.

시리즈의 마지막 연재까지 지켜봐주길 바란다. 마지막 연재는 자바스크립트 언어의 설계자 중 하나가 브라우저의 자바스크립트를 컴파일하고 실행하는 방법을 다룰 것이다.

도서 소개

레이철 앤드루의 신간 『새로운 CSS 레이아웃』
그리드를 사용한 레이아웃을 기존 레이아웃과 비교해서 살펴볼 수 있습니다. 예제를 통해 그리드 레이아웃이 어떻게 활용되는지 확인해보세요. 레이아웃만을 다룬 ‘그리드 레이아웃’ 전문서 『새로운 CSS 레이아웃』입니다. 본질의 웹 디자인 시대 흐름에 뒤처지지 않으려면 이 책을 꼭 읽어야 합니다!!
저작권 정보이 글은 A List Apart 기사를 번역한 것입니다. 저작권자의 정당한 허락을 받은 저작물로 한국어판 저작권은 웹액츄얼리에 있습니다. 웹액츄얼리의 서면 동의 없이 무단 전재, 복제를 금합니다. 원문은 Braces to Pixels에서 확인할 수 있습니다.
참여를 기다립니다!국내 웹 디자인계 발전에 도움 주실 분을 찾습니다. 최신 웹 기술에 관심 많은 프론트엔드 개발자이면서, 영어를 우리말로 옮기는 데 어려움 없는 분의 연락을 기다립니다. 번역물에 대한 소정의 번역료를 지급합니다. 메일로 연락주시면 안내드리겠습니다.
books@webactually.com


맨위로