30. CSS 레이아웃 모델 – 박스, 보더, 마진, 패딩

소개

얼핏 보면 CSS 레이아웃 모델은 직관적이다. 박스, 보더 그리고 마진은 꽤 간단한 오브젝트들이고, CSS 문법은 그들의 속성을 간단하게 표기할 수 있는 방법을 제공하고 있다.

하지만 브라우저 렌더링 엔진은 CSS 2.1 권고안에 적혀있는 긴 규칙 리스트 뿐만 아니라 브라우저 자체의 규칙도 함께 따른다. 이러한 이유로 고급 기술들이 스타일리스트의 레퍼토리에 더해지기 이전에 우리가 이해해야 할 구체적인 사항은 아주 많다.

이 글에서는 border와 margin과 같이 HTML의 레이아웃 속성들을 다루는 CSS의 속성들을 소개한다. 여기에서는 위에서 언급한 몇 가지 규칙에 대해서도 소개 할 것이다. 고급 칼럼 레이아웃과 그리드-중심 테크닉은 나중에 폼 레이아웃, 플로트(float), 클리어링(claer)과 포지션을 설명하는 다른 글에서 소개할 것이다. 이 글과 관련된 예제 코드들이 글 전체에 걸쳐 링크되어 있지만, 만약 여러분의 컴퓨터에서 직접 실습하고 싶다면, 여기에서 예제 코드를 다운로드 받을 수 있다.

이 글의 목차는 다음과 같다:

작성법 바꾸기: CSS margins, borders, and padding

div와 heading과 같은 많은 HTML 요소들은 기본적으로 캔버스의 너비 전체만큼을 차지하고 행 바꿈을 하도록 되어있어, 이와 같은 요소들을 차례로 사용할 경우에는 캔버스의 위에서 아래로 줄줄히 나열되는 형태로 표시된다.

하지만 이를 위한 HTML 요소들과 브라우저 스타일이 대게는 광범위한 이용에는 부적절하며, 따라서 개발자들은 그들의 일 안에서 방법을 모색하길 바란다. CSS와 HTML이 사용되는 방식은 “서로 부족한 부분을 채우는” 방식으로 바뀌어져 왔다. 따라서 class와 id가 의미를 가지는 동시에 스타일 시트의 룰이 자로 잰 듯 정확하게 컨텐츠의 레이아웃 및 표현 방법을 바꿀 수 있었다. 심지어는 브라우저 기본값으로 정해진 많은 부분을 초기화시키면서까지 말이다.

공백에 대한 세심한 컨트롤은 디자이너의 중요한 도구들 중에서도 가장 중요한 요소이다. 내 생각도 그러하다. 사이트 디자인을 높은 수준으로 이끌 공백에 대한 컨트롤은 기본적인 브라우저 스타일시트에서는 빠져있다. 이것은 일반적으로 이 글에서 설명하고 있는 margin, border, padding 그리고 다른 CSS 레이아웃 속성들을 스타일리스트들이 자주 사용한다는 것을 의미한다.

Figure 1은 margin과 border, 그리고 padding을 함께 보여준다.

Figure 1: 여러가지 종류의 엘러먼트 박스와 관련된 CSS 속성들이 명시적으로 나타나있다.

오브젝트 주변에 여백주기: margin-top, margin-right, margin-bottom, margin-left, 그리고 margin 속성들

마진은 하나씩 따로 표기할 수도 있고, 혹은 축약된 표현으로 나타낼 수 있다. 축약된 규칙을 사용하더라도 여전히 오브젝트에 대한 각각의 보더들을 컨트롤할 수 있다. 값은 대게 px(픽셀)이나 em 단위로 표기된다. 프린트를 위한 스타일시트에서는 in(인치), cm(센티미터) 혹은 pt(포인트) 단위가 사용될 수도 있다.

% (퍼센티지) 값을 사용할 경우, 신중하게 사용해야 한다. 왜냐하면 그런 % 값들은 부모 요소의 너비를 기준으로 한 비율값으로 계산이 되기 때문에, 부주의하게 값을 선정했다가는 의도치 않은 결과가 나올수도 있기 때문이다. 이것의 어려움에 대해서는 나중에 CSS 박스 모델에 대해 설명할 때 좀 더 자세히 다루겠다.

이미지를 제외한 모든 인라인 요소들은 기본적으로 마진 속성을 가지지 않고 있고, 때문에 마진 값도 가질 수 없다. 이러한 요소들에 대한 설명은 아래의 테이블 2에 잘 나타나 있다.

자동 마진 (auto margins)

상황에 따라서, auto값에 대한 해석은 브라우저 자체의 스타일시트에 따라 보여지도록 규정하고 있다. 하지만 그러한 마진이 auto 대신 의미 있는 너비 값을 가진 요소로 표기되었을 경우, 화면안의 모든 사용 가능한 공간은 공백으로 보여진다.

다음과 같은 룰이 주어졌을 경우:

.narrowWaisted {
  width: 16.667em;
  margin: 1em auto 1em auto;
}

narrowWaisted라는 클래스로 지정된 블락 요소는 사용 가능한 캔버스 공간의 한 가운데에 자리잡는다.

…혹은 적용 가능한 요소의 우측 마진은 상대적으로 적은 값으로 세팅이 되고, 좌측마진은 auto 값으로 세팅이 된다.

이렇게 했을 때, 이것은 거의 우측정렬로 보여질 것이다.

음수 마진 (Negative margins)

모든 마진 속성을 음수값으로 정할 수 있다. 이 경우에 인접한 마진은 효과적으로 어느 정도 는 “상쇄”될 수 있다. 충분히 큰 값의 음수 마진이 충분히 큰 요소에 적용이 되었을 때에는, 영향을 받는 인접한 요소들이 서로 겹쳐질 수 있다.

예를 들어, 다음의 간단한 div 요소를 보자 (예제 파일 negativemargin1.html에서 발췌함.)

<div id="header"><h1>Lovely header</h1></div> <div id="content"><p>Overlapping text is entirely unreadable</p></div>

다음 CSS와 같이 스타일링되었을 경우

body {background-color:white; font-family:Geneva, Arial, Helvetica, sans-serif;}
#header { background-color:yellow; } h1 { color:red;; font-size:2em; }

그림 2와 같은 결과가 나온다:

Figure 2: The two elements from our simple example. Nothing special to see here.

Here comes the interesting part. Now we’ll add a fairly sizeable negative margin to the top of the bottom element, using the following rule:

#content {margin-top:-3em;}

이 문장은 아래 요소를 위로 올리는 시각적 효과를 주어, 그림 3에 보이는 것 처럼 헤딩 부분과 겹쳐지게 한다. (negativemargins2.html 예제 파일을 참조 하길 바란다)

Figure 3: With a negative margin applied, the bottom element shifts upwards and overlaps the heading.

통합된 마진 (Collapsing margins)

두 개의 비슷한 블락 요소들이 인접하게 붙어 있으면서 0보다 큰 값로 지정된 마진을 공유하고 있을 때, 두 개의 마진 중 큰 마진값만이 사용이 된다. 예를 들어, 다음 문장을 보자:

p {
  margin: 1em auto 1.5em auto;
}

만약 이 스타일 법칙을 포함한 문서가 문법 그대로 보여진다면, 연속된 두 개의 문단 사이의 마진은 2.5em이 될 것이다. 이것은 첫 번째 문단의 하단 마진(1.5em)과 두 번째 문단의 상단 마진(1em)을 합친 값이다. 하지만 통합된 마진이 적용되었기 때문에, 두 문단 사이의 마진은 1.5em 밖에 되지 않는다.

리스트와 헤딩은 블럭 요소들 중에서도 특별한 경우로, 이들의 마진은 다른 블럭 요소들의 마진으로 통합되지 않는다.

Demonstration 1

앞서 나온 텍스트 스타일링에 관한 글 에서 F.Scott Fitzgerald의 글의 도입부를 꾸미기 위해 CSS로 할 수 있는 많은 방법들이 사용되었다. 이 글의 데모에서도 같은 글을 사용하며, 다만 거기에 약간의 변형을 가하는 식(주로 컨테이너 엘러먼트를 더하는 것이 될 것이다)으로 진행할 것이다. 텍스트 스타일링은 이전과 같지만, 이전 데모에서 적용되었던 몇 가지 레이아웃 스타일은 제거되었다.

우선, 필요한 몇몇 엘러먼트에 대해 마진을 설정한다.

Links:
새로운 규칙들:
body { margin: 0; }
#main { margin: 0 auto 0 auto; }
h1 { margin: 0 0 1em 0; }
.pullQuote { margin: auto 0 1em 1em; }
p { margin: 0; }
.attribution { margin: 0 0 1.5em 0; }

오브젝트에 테두리 더하기: border 속성

border의 축약 속성이 존재하긴 하지만, 그것은 당신이 엘러먼트의 네 테두리(border)에 대해 완벽하고 일관적인 테두리를 사용하고자 할 경우에만 유용하다. 다음에 나오는 속성들을 의미있게 조합함으로서, 엘러먼트가 가진 네 개의 사용 가능한 테두리에 가중치(넓이), 스타일, 색상을 지정하는 것이 가능하다:

  • border-width
  • border-style
  • border-color
  • border-top
  • border-top-width
  • border-top-style
  • border-top-color
  • border-right
  • border-right-width
  • border-right-style
  • border-right-color
  • border-bottom
  • border-bottom-width
  • border-bottom-style
  • border-bottom-color
  • border-left
  • border-left-width
  • border-left-style
  • border-left-color

border-width 속성

이름 그대로이다. 명시된 가중치(넓이)를 하나 혹은 그 이상의 테두리의 속성값으로 할당한다.

축약된 형태의 border-width 속성은 margin 의 축약된 형태와 같은 방식으로 값을 할당한다. 하지만 퍼센티지 값은 사용할 수 없다. 이 속성은 다음과 같이 사용될 수 있다:

td {
	border-width: 1px 0 0 1px;
}

border-style 속성

Figure 4: the eight common border styles in action.

border-style 속성은 보통 아래의 값 중 하나를 그 속성값으로 받아들인다:

dashed 파선
대쉬 선의 길이와 선 사이의 공백은 브라우저에 의해 결정된다.
dotted 점선
점 사이의 공백은 브라우저에 의해 결정된다. 여기에서 점선은 선과 공백의 비율이 1:1인 점선을 뜻하는 경우도 있다.
double 이중 실선
주어진 너비를 3등분 한 후, 그 공간을 채워짐-빈공간-채워짐의 순서로 그린 선이다.
groove 입체 오목선
outset 이 안쪽에 그려진 후, inset이 그려지는 모양이다.
inset 뒤로 밀어 넣은 면
마치 엘레멘트가 캔버스 안쪽으로 눌려진 것처럼, 테두리에 그림자가 져 있다.
none 없음
-width가 제로인 경우와 같다.
outset 앞으로 빼놓은 면
마치 엘레멘트가 캔버스 바깥쪽으로 튀어나온 것처럼, 테두리에 그림자가 져 있다.
ridge 입체 볼록선
inset이 안쪽에 그려진 후, outset이 그려지는 모양이다.
solid 실선
테두리가 그림자 없이 쭉 이어진 모양이다.

축약된 형태로 border-style을 사용할 경우 최대 4개의 값을 지정할 수 있는데, 이것은 축약된 형태로margin 속성을 지정하는 형태와 같다.

-color속성을 이용해 테두리를 흐릿하게(없애는 대신) 하는 효과를 줄 수 있다.

border-color 속성

드디어 각각의 테두리에 색상을 더할 수 있는 방법에 대해 알아보겠다. 위에 나열된 속성들처럼 하나의 특정한 테두리에만 색상을 적용할 수도 있고, border-color라는 축약된 형태를 사용하여 색상을 적용할 수 있다. 축약형에서 넷보다 적은 개수의 값을 넣었을 때 어떤 결과가 나오는지에 대해서는 margin의 축약형에 대해 설명하는 부분을 참고하라.

background-color와 마찬가지로, border-color도 transparent값을 가질 수 있다. 이것은 테두리들이 붙어 있지만 일관되게 사용되지는 않는 경우를 다룰 때 유용하게 사용될 수 있다.

축약된 형태의 border 속성과, 그의 네 가지 사촌들

-width-style-color 와 같은 속성들과는 달리, 이들 5가지 속성은 오브젝트가 가진 어떤 한 면의 테두리 혹은 4개의 테두리에 대해 동시에 3가지 속성을 지정할 수 있도록 한다. border가 붙는 속성들의 유효값은 하나 또는 전체 테두리에 대한 너비, 스타일, 색상을 지정한다. 여기서 주의해야 할 점은, 속성을 하나의 테두리에 대해서만 정의하거나, 아니면 전체 테두리(4개)에 대해서 동일하게 정의하거나 둘 중 한 가지만을 택해야 한다는 점이다.

다음와 같은 border 규칙을 보자:

#borderShorthandExample {
	border: 2px outset rgb(160,0,0);
	padding: .857em;
	background-color: rgb(255,224,224);
}

위와 같은 규칙이 적용된 엘러먼트는 여러분이 지금 보고 있는 이 문단과 똑같은 형태로 보여질 것이다.

축약된 border 형태에서 어떤 값이 생략되었다면, 엘러먼트는 다음과 같은 기본값으로 처리되어 보여질 것이다:

  • 테두리 넓이(Border width) 는 브라우저에 의해 결정 될 것이다.
  • 테두리 스타일(Border style) 은 solid가 될 것이다.
  • 테두리 색상(Border color) 은 해당 엘러먼트와 같은 color 값을 갖게 될 것이다.

규칙 만들기: 한 가지가 아닌, 5가지의 축약형 속성들이 존재하는 이유

여기서 논의되고 있는 “규칙들”은 따라야 할 지시어가 아니라, 레이아웃 전반에 걸쳐 그려지는 선들에 관한 것이다. 이러한 선들은 엘러먼트와 그것의 인접 공간 사이에 대비 효과를 주고, 많은 경우에 그 선들은 레이아웃에 깊이가 있는 듯한 효과를 줄 수 있다. inset과 outset 의 테두리 스타일이 이것의 좋은 예가 된다.

엘러먼트가 가진 4개의 모든 테두리에 동일한 효과를 줄 수 있긴 하지만, 레이아웃 안에서 세밀하게 정의된 선들을 그릴 수 있는 방법을 제공함으로써 디자이너들에게 구체적인 레이아웃 디자인에 대한 상당한 제어권을 주게된다.

…그렇다면 왜 그렇게 많은 속성들이 있는 것인가? 단지 테두리일 뿐인데…?

레이아웃을 만드는 데에 스타일리스트의 뛰어난 실력을 요구한다면, 특별한 케이스(edge case)들에 대한 고려가 있어야 할 것이다 — 이것은 margin에 대한 논의에서 나왔던 이야기이다.

사이트 디자인이 만들어지는 방식 때문에, 여러분은 한 문서내에 속한 엘러먼트들이 비슷한 구조적 속성을 가지지만 표현은 달라야 하는 경우를 많이 접하게 될 것이다. 이러한 상황에서는 가장 상식적인 하나의 규칙을 쓰고, 특별한 케이스들에 대해서는 각각의 규칙을 하나씩 더해가는 것이 말이 된다고 할 수 있겠다. 이것이 바로auto 와 inherit가 존재하는 이유라 할 수 있겠다: 특별한 케이스의 경우에 디폴트 스타일을 사용할 것.

테두리의 경우, 특별한 케이스라 함은 엘러먼트의 어느 한 테두리에 대해 한 가지 특성을 다른 어떤 것으로 변경하는 것일 수 있다 — 그리고 현명하게 KISS 법칙을 따르고 있을 때, 대게의 경우 최선의 방법은 바뀌어야 할 그 부분만 바꾸는 것이다.

데모 2

선과 border의 형태를 사용해서 문서의 특정 부분을 꾸며라.

링크:
새로운 규칙:
h1 { border-bottom: 1px solid rgb(153,153,153); } .pullQuote { border: 1px solid rgb(153,153,153); }

마진만으로 충분하지 않을 경우: 패딩(padding) 속성

엘러먼트가 백그라운드 색을 가지고 있고, 보조 혹은 엑센트 색상도 사용되어 컨텐츠와 마진 사이에 공간이 필요한 경우가 있을 수 있다. 또 다른 경우에, 보더들과 보더 가까이에 있는 것들 사이에 공간이 필요할 것이다.

이러한 경우 및 또 다른 많은 경우에, paddingpadding-toppadding-rightpadding-bottom,padding-left 속성들을 고려할 수 있다. 이러한 속성들은 엘러먼트의 마진 혹은 보더와 컨텐츠 사이에 negative 공간을 만든다. 위의 Figure 1 에 보면 마진, 보더, 패딩 사이의 관계에 대해 명확하게 보여주고 있다.

이러한 속성들은 다음과 같은 예외를 제외하고선 마진 속성과 정확하게 같은 방식으로 작동한다:

  • auto 값은 패딩 속성과 관련해서는 기능적으로 쓸모가 없다.
  • 음수의 패딩 값은 무효이다.
  • 패딩은 통합될 수 없다.
  • 마진 값은 인라인 엘러먼트에 적용되지 않으나, 패딩값은 적용이 된다.

데모 3

앞서 보더가 더해진 엘러먼트에 대해 패딩을 더하라.

링크:
새로운 규칙:
body { padding: 0; }
h1 { padding: .5em 0 .5em 0; }
.pullQuote { padding: .5em; }

엘러먼트의 너비와 높이

대부분의 엘러먼트들의 크기를 바꿀 수 있는 건 당연한 일이다. 여러분은 이것의 예를 이 글의 앞 부분에서auto마진에 대해서 이야기하면서 살펴보았다.

엘러먼트의 크기를 조정하는 CSS 속성으로는 widthheightmin-widthmax-widthmin-height,max-height가 있다. 이 속성들은 overflow 속성을 이용하면 엘러먼트 콘텐츠와 분리(혹은 연결)될 수 있다.

또, clip 속성이 있는데 이것은 엘러먼트의 일부를 그것의 마진 안에다가 숨긴다. 하지만 이 속성은 많이 사용되지 않기 때문에 이 글에서는 설명하지 않는다.

너비와 높이의 기본(width and height basics)

규칙에 따라서 사용할 경우, width 와 height는 정확히 기대하는 결과를 나타낸다. 하지만 실제로 사용함에 있어 아래의 사항들을 숙지해 두어야 한다.

  • width 와 height 는 인라인(inline) 엘러먼트에 적용될 수 없다… 일반적인 경우에 span,strongem 과 같은 몇 개의 엘러먼트는 width 와 height값을 무시한다. 이에 대한 자세한 설명은 이 글의 후반부에서 다룰 것이다.
  • …하지만 이미지는 예외인데, 이미지는 인라인 엘러먼트로 삽입되는 경우에도 width 와 height 를 정할 수 있다. CSS 2.1 권고안은 이미지를 “교체된” 엘러먼트라고 나타내는데, 이것은 브라우저가 이미지를 언제나 정적인 크기를 가지는 것으로 간주해야 한다는 의미이다. 이러한 이유로 이미지의 크기는 임의로 바뀔 수 있다.
  • 엘러먼트의 기능적인 크기에 영향을 줄 수 있는 속성은 width 와 height, 이 둘 뿐이다. 때문에, 엘러먼트의 크기가 너무 작아서(대부분의 경우에, 너무 좁아서) 컨텐츠를 다 담을 수 없을 수 없는 나머지 깨지는 경우를 만나기가 쉽다. 아래의 CSS 박스 모델에 대한 논의에서 이 문제를 다룬다.
  • 마이크로소프트 인터넷 익스플로러(IE)의 렌더링 버그 때문에, 몇 가지의 엘러먼트에 대해서는 반드시 width 혹은 height 속성/값을 명시해주어야 한다. IE의 렌더링 엔진은 강제적으로 해결해야만 하는 몇 가지 특성이 있다. 대부분은 이런 특성들은 이미 널리 알려진 상태이고 IE 8 버전에서 제거될 예정이지만, IE 8 버전이 출시되어 그 이전 버전들을 대체할 때까지는 여전히 피할 수 없는 테스트 케이스로 남아있을 수 밖에 없다. PositionIsEverything.net 와 CSS-Discuss Wiki 는 이것과 관련된 문제들과 해결 방법에 대한 풍부한 정보를 다루고 있으니 참조하길 바란다.
  • 이따금씩 라운딩 알고리즘(Rounding algorithms) 때문에, LCD, LED 혹은 CRT (type="screen") 디스플레이 장치에서 레이아웃이 브라우저에 따라 약간 다르게 보이는 경우가 있는데, 이는 스펙에는 명시되지 않은 차이점이다 screen 미디어 타입은 궁극적으로 모든 단위들을 픽셀 단위로 변환하여 렌더링 처리를 하는데, 여기에서 브라우저별로 약간의 차이가 생길 수 있다.

min-width, max-width, min-height, max-height

당신은 이따금씩 엘러먼트의 사이즈에 제한을 줘야 할 경우와 맞닥뜨리게 될 것이다. 대게의 경우 이는 비율 값으로 정해진 칼럼 안의 엘러먼트가 제대로 표시되게 만들기 위함이다. 이를 위해 min- 또는 max- 로 시작하는 다양한 속성들이 사용된다. width 와 height 속성과 함께 사용되는 경우에 나오게 될 결과는 비교적 쉽게 예측할 수 있다.

하지만 본인의 경험에 비추어 볼 때, 이 속성들을 사용하는데에 한계가 있었다(물론 이 말에 반대하는 사람도 있다). 일반적인 width 와 height 와 같이 이 속성들도 에러에 대해 라운딩 처리가 되는데, 이 때문에 이 속성들이 전혀 예상치 못한 결과를 가져올 수도 있다. 더 중요한 문제는, 2008년 7월 현재 아직까지 상당한 시장 점유율을 보여주는 IE6 브라우저가 이 속성을 지원하지 않는다는 사실이다.

데모 4

페이지 컨테이너의 왼쪽과 오른쪽에 auto로 마진값이 설정되어 있다. 이제 이 마진값들이 의미가 있도록 적당한 width 값을 줄 필요가 있다. 그리고 pullQuote에 float 값을 줄 것이기 때문에 이 엘러먼트에도 너비값을 주어야 한다.

링크:
새로운 규칙:
#main { width: 42em; }
.pullQuote { width: 14em; }

Overflow: 컨텐츠를 감싸거나, 혹은 그냥 놔두거나…

엘러먼트의 width 혹은 height 값이 정할 때 고려해야 할 또 한가지는 엘러먼트의 컨텐츠가 사용가능한 공간보다 더 많은 공간을 차지할 경우 결과 화면이 어떻게 보여지게 할 것인가 하는 점이다. 이것은 특히 웹사이트가 사이즈가 세밀하게 정해진 레이아웃을 가지면서 컨텐츠는 사용자가 제공하도록 하는 경우에 더욱 그러하다.

overflow 속성과 이 속성이 가질 수 있는 4가지 유효한 값 — visiblehiddenautoscroll — 은 이러한 상황을 해결하기 위해 만들어졌다. 여기 엘러멘트가 있는데 이 엘러먼트의 컨텐츠가 엘러먼트의 테두리 밖으로 삐져나오고 있다. Figure 5는 각각의 속성값이 이 엘러멘트에 적용되었을 때 어떻게 되는지 보여준다.

Figure 5: CSS overflow 속성의 효과.

4 가지 overflow 속성값의 결과

visible (기본값)
엘러먼트의 크기를 벗어나는 컨텐츠가 그대로 모두 화면에 표시되는데, 이 때 오버플로우 된 컨텐츠가 인접 엘러먼트의 배치나 마진에 영향을 주진 않는다. 따라서 한 엘러먼트의 컨텐츠가 마치 이웃 엘러먼트의 컨텐츠와 충돌하는것처럼 보일수도 있다. 이 글의 후반부에서 이러한 경우를 피하기 위한 테크닉들과 IE 브라우저의 렌더링 이슈로 인해 야기되는 특별한 경우들에 대해서는 다시 논하겠다.
hidden
엘러먼트의 테두리 밖으로 삐져나가는 컨텐츠들은 보여지지 않는다.
auto
엘러먼트의 크기는 hidden 값의 경우에서처럼 제한된다. 하지만 필요한 경우 스크롤바가 생겨 사용자가 감춰진 컨텐츠에 접근할 수 있게 한다.
scroll
수직, 수평 스크롤바가 엘러먼트에 적용이 된다. 굳이 스크롤바가 필요없는 경우에도 적용이 된다.

CSS 박스 모델: 모든 것들을 함께 넣기

자 이제 기본적인 레이아웃 속성들에 대한 이야기는 끝났다. 이제는 엘러먼트의 너비가 CSS 속성에 통해 브라우저에서 보여지는지, 그리고 어떻게 하면 제대로 보여줄 수 있을지에 대해 알아볼 시간이다. 어떤 결과들은 아주 당연하게 느껴질 것이고, 반면 다른 어떤 결과들은 아주 말도 안되는 것처럼 느껴질 수도 있을 것이다. 조금 어렵게 말하자면, 두 가지의 레이아웃 알고리즘을 살펴볼 필요가 있다: 월드 와이드 웹 컨소시움(W3C)에 의해 만들어진 CSS 2.1 권고안에 있는 모델과, 구 버전의 IE 브라우저에서 사용되는 모델이 그것이다.

레이아웃에 적합한 단위 고르기

텍스트의 경우, % 나 em과 같은 비례 단위(proportional units)나 px와 같은 정적인 단위(static unit)를 사용하여 엘러먼트의 사이즈를 정할 수 있다. 여기서 또 한가지 고려해야 할 점은 브라우저 캔버스의 크기는 항상 정적인 값으로 정해져 있으며 이 값은 클라이언트 사이드 스크립트(이는 접근성, 사용성, 미디어 이식성을 위해서는 적합하지 않은 기술이다)를 사용하지 않고서는 그 크기를 안다던가 윈도우 크기를 재조정할 수 없게끔 되어있다.

엘러먼트의 크기에 대한 기본 규칙: 비례 단위(proportional unit)와 정적인 단위(static unit)를 신중하게 섞어서 사용하거나, 혹은 둘 다 쓰지 않거나

width 와 height 의 기본값은 auto인데, 이는 표준 영어로 해석하면 “사용가능한 공간을 사용하라”라는 의미이다. 이 값을 블럭 엘러먼트에 적용했을 때, width는 가로로 모든 공간을 차지해버리는 너비값을 가지게 되고, height는 컨텐츠를 포함할 수 있는 만큼의 높이값을 가지게 된다.

width 와 height 의 값을 변경할 경우, 당신이 지정하는 width값이 엘러먼트의 컨텐츠(마진, 보더, 패딩값도 모두 포함)를 충분히 포함할만큼 큰 값을 갖도록 해야한다. 이를 위한 가장 쉬운 방법은 아래의 프로세스를 따르는 것이다:

  1. 일반적인 디스플레이 해상도와(혹은) 일반적인 크기의 타입을 가진다는 전제하에, 당신의 레이아웃에 쓸 수 있는 가장 큰 너비를 생각해보라. 이 글을 쓰는 현재, 이 방법으로 얻을 수 있는 일반적인 값은 800 혹은 1024 픽셀 정도가 될 것이다. 당신의 사이트의 예상 사용자층이 다양하면 다양할수록, 작은 너비값을 고르는 것이 낫다.
  2. 문서내의 모든 엘러먼트를 포함할 컨테이너 엘러먼트를 만들라. 단, 이 컨테이너 엘러먼트의 너비는 스텝 #1에서 나온 너비값보다 작게 한다.
  3. 스텝 #2에서 만든 컨테이너 엘러먼트 안에 들어가는 엘러먼트들이 속성값을 지정할 때, 컨테이너 엘러먼트와 같은 단위를 사용하라.

레이아웃에 적합한 단위 고르기: 장점과 단점

단위 장점 단점
em
  • 아주 세밀한 2차원의 레이아웃 그리드를 만드는 데 가장 적합함
  • 문서 컨테이너에 대해 사용될 경우, body 부분의 사이즈가 확대/축소됨에 따라 레이아웃의 크기도 확대/축소되게 만들 수 있음
  • 화면에 보여질 엘러먼트의 크기를 쉽게 예측할 수 있음
  • 비례 단위(Fractional unit)을 사용하면 레이아웃이 브라우저에 따라서 약간씩 늘어나거나 줄어드는 차이가 있음
  • 최적의 결과를 얻기 위해서는, 문서내의 모든font-size와 line-height 속성에 대해 명시적이고 예측 가능한 값을 정해주어야 함
percentage
  • 완전히 유동적인 레이아웃에 가장 적합함
  • 같은 크기의 칼럼을 만들기에 가장 쉬움
  • 레이아웃이 망가지는것을 막기 위해서 추가적으로 컨테이너 엘러먼트가 더 필요함
  • 용납할 수 없을 정도로 넓거나 좁은 엘러먼트가 생길 수 있음
  • 문맥에 따라 레이아웃 결과가 좌우됨 (아래의 박스모델에 대한 글을 보라)
px
  • 레이아웃에 대한 제어권을 가장 많이 가질 수 있음
  • 레이아웃에 대한 대부분의 브라우저간의 차이(브라우저에 따라 다르게 보이는 현상)를 없앰
  • 접근성과 크로스-미디어 지원을 위해서는 가장 적합하지 못함
  • 레이아웃이 날라갈 여지가 가장 많음

Table 1: 레이아웃 속성에 페센티지, em, 픽셀 단위를 사용할 경우의 각각의 장점과 단점들.

박스 모델 요소

박스 모델은 엘러먼트의 다양한 레이아웃 명세들이 서로 상호작용하는 방법을 정의하는 지시어들을 나열한 것일 뿐이다. 박스 모델에서 사용되는 구성 요소들은 다음과 같다:

  1. 문서 캔버스
  2. 마진
  3. 보더
  4. 패딩
  5. 엘러먼트의 너비와 높이
  6. 엘러먼트 속성의 자식요소

마지막 요소는 결국 다시 다른 5 가지 요소들을 포함한다. 하지만 이 단락에서는 간단한 부모-자식 엘러먼트 관계에만 초점을 맞추고, 다단계 박스 모델 상호작용에 대해서는 추후에 페이지 레이아웃을 좀 더 심도있게 다루는 글에서 다시 논의할 것이다.

W3C 박스 모델: 모든 것은 더해질 수 있다

기본적인 규칙은 엘러먼트의 너비 혹은 높이는 다음과 같이 계산된다는 것이다:

margin + border + padding + (width|height)

마진 + 보더 + 패딩 + (너비 혹은 높이)

많은 경우에 width 그리고/혹은 height 값은 기본적으로 auto로 정해져있는데, 이는 컨텐츠를 위해 마련되는 캔버스 공간이 다음과 같이 계산된다는 뜻이다:

available_canvas − margin − padding − border

사용가능한_캔버스 – 마진 – 패딩 – 보더

이 식에서, 사용가능한_캔버스 값 자체는 이산값이다. 이 숫자는 엘러먼트의 너비(width)를 계산함에 있어 가장 중요한데, 왜냐하면 디자이너가 width값을 잘못 계산할 경우 브라우저 윈도우에 수평 스크롤바가 나타나는등의 원치않는 결과를 가져올 수 있기 때문이다. 그리고 브라우저들은 별 다른 지시가 없으면, 항상 엘러먼트를 브라우저 캔버스의 왼쪽 마진에 위치시키는데, 이렇게 하지 않으면 엘러먼트가 브라우저 윈도우의 오른쪽 마진 너머로 오버플로우되어 보여질 수도 있다.

다음과 같은 스타일 시트 규칙을 생각해보자:

#myLayoutColumn {
  width: 50em;
  margin: 1.5em auto 1.5em auto;
  border: .1em;
  padding: .9em;
}

위에서 margin 속성에서 설명할 때 언급했듯이, #myLayoutColumn가 컨테이너 엘러먼트(이것이 body이든, 아니면 생산팀에서 만든 다른 엘러먼트이든 상관없이) 안에서 한 가운데에 자리잡았으면 한다.

게다가 만약 (적절한 !DOCTYPE 선언에 따른) “strict mode”로 보여질 때 이것은 W3C 박스모델을 사용하게 하고, non-marginal 너비는 다음과 같이 예상할 수 있다:

.1em + .9em + 50em + .9em + .1em = 52em

screen 미디어에서 브라우저는 이 값을 받아들이고, 모든 개별값들을 가장 가까운 pixel로 반올림시켜 변환시킨다음, 이에 따른 결과 값을 보여주게 된다.

W3C 박스 모델에서 비례 단위의 margin과 padding

W3C 박스 모델을 사용할 때 비례 단위로 지정된 마진과 패딩값은 자신을 포함하는 엘러먼트의 유효한width값에 비례하여 계산된다. 예를 들어서, 800픽셀 너비를 가진 엘러먼트 안에 엘러먼트가 있는데, 그 내부의 엘러먼트에 margin: 20%의 속성을 주었을 경우, 그 내부의 엘러먼트는 사방에 각각 160픽셀(800의 20%이므로 160)의 마진을 갖게 될 것이다.

만약 똑같은 엘러먼트가 padding: 5%값을 갖게 된다면, 유효한 컨텐츠 너비는 400 픽셀이 될 것이다:

20% + 5% + 5% + 20% = 50% 0.50 × 800 = 400 800 − 400 = 400

문서 흐름(document flow)에 대하여

다음의 튜토리얼은 멀티-칼럼 레이아웃을 만드는 방법에 대해 이야기하고 있다. 이 문서에서 마지막으로 소개할 세 가지의 CSS 속성은 다음과 같다: displayfloatclear.

엘러먼트 타입과 display 속성

htmlbody, and table 속성을 제외한 HTML 4.01 권고안에 있는 나머지 속성들은, 각각의 속성의 컨텐츠가 inline 혹은 block 타입을 가지게 되어있다. 각각의 타입은 디폴트 레이아웃을 결정하는 방식이 다음과 같이 다르다:

inline 인라인
  • 인라인 엘러먼트의 앞 그리고(혹은) 뒤에 위치한 텍스트와 이미지들은 기본적으로 인라인 엘러먼트의 컨텐츠와 공통된 베이스라인 상에서 렌더링 된다. 텍스트나 이미지가 아주 길어서 인라인 엘러먼트와 오버랩이 되게 생긴 경우 줄바꿈이 생기고, 인라인 컨텐츠는 아래줄로 내려가 위치하게 된다.
  • 인라인 엘러먼트 내의 텍스트는 필요에 따라(혹은 허가 하에) 가벼운 줄바꿈을 동반한다. 단, white-space속성이 사용되는 경우는 예외이다.
  • 모든 엘러먼트에 적용가능한 marginwidthheightfloat 스타일 시트 속성들이 무시된다. 단,img와 object는 제외.
  • 인라인 엘러먼트는 텍스트와 다른 인라인 엘러먼트만 포함할 수 있다.
block 블락
  • 이 엘러먼트들은 컨테이너 안에서 각각의 블락들로 나타난다.
  • float 속성값으로 left 혹은 right을 가지지 않는 이상, 엘러먼트 앞뒤로 줄바꿈을 가진다.
  • 컨텐츠를 가지지 않은 엘러먼트들이 중첩된 경우 엘러먼트 사이에 줄바꿈이 생기지 않는다.
  • 너비값으로 auto (기본값)을 가지는 블락 엘리먼트는 사용가능한 전체의 너비를 그것의 너비값으로 사용한다.

display 속성은 일반적으로 3개의 값 — blockinlinenone — 중 하나를 가지게 되는데, 그 중 두 가지는 해당 엘러먼트의 타입을 지정하기 위한 값이다. 엘러먼트의 display 값을 바꿈으로서, 인라인 엘러먼트가 블락 엘러먼트처럼 행동하게 할 수 있고, 블락 엘러먼트를 인라인 엘러먼트처럼 행동하게 할 수 있고, 혹은 마치 엘러먼트(그리고 그 엘러먼트의 컨텐츠)가 전혀 존재하지 않았던 것처럼 문서의 렌더링을 변경시킬 수도 있다.

말할 것도 없이, 어떤 엘러먼트가 기본값으로 어떤 타입을 사용하고 있는지에 대해 아는 것은 대단히 중요하다. 이러한 관계가 Table 2에 간략하게 나와있다:

Element Type Subtype Notes
a inline special
abbr inline phrase
acronym inline phrase
address block 관행적으로 p 와 비슷하게 동작함
blockquote block !DOCTYPE이 Strict으로 선언된 경우, 적어도 하나의 블락 엘러먼트를 포함해야 한다
body 전체 문서 캔버스를 아우른다; 일반적으로 screen 미디어 에서는10px의 마진(IE, Firefox, Safari의 경우) 혹은 패딩(오페라)을 가진다.
cite inline phrase
div block
em inline phrase
fieldset block 일반적으로 border: 1px black;의 기본값과 함께 렌더링된다
form block
h1 … h6 block heading
input inline formctrl
img inline special
label inline formctrl
li block Document Type Definition에는 언급되어 있지 않지만, 이 엘러먼트는 블락 혹은 인라인 엘러먼트를 포함할 수 있다; 완성된 CSS 2.1 권고안은 리스트 아이템의 엘러먼트 타입으로 display 값을 지정하고 있다
ol block list
p block 인라인 엘러먼트만 포함할 수 있다; 일반적으로 상단과 하단 마진값만이 렌더링에 사용된다
span inline special
strong inline phrase
table block
ul block list

Table 2: 사용 빈도가 높은 HTML 엘러먼트와 그들의 타입. 같은 subtype을 가진 두 개의 인접한 블락 엘러먼트 사이의 마진은 하나로 합쳐질 것이다.

데모 5

타이틀에서 “Prologue” 주석을 없애보는 건 어떨까요?

링크:
새로운 규칙:
.sectionNote { display: none; }

엘러먼트가 다른 엘러먼트 위에 떠나니게 하는 속성: float 속성

이 단락의 왼쪽에 사진이 삽입되어 있다. 몇 몇 분들은 왜 유명한 공상과학 소설가가 그의 고양이의 몸에 베이컨을 붙여놨는지 – 심지어 그는 한가한 하루를 보내고 있었다 – 에 대한 궁금증부터 생기겠지만, 어쨌든 보시다시피 여러분 모두는 다음의 카피 플로우가 자연스럽게 그림을 둘러싸고 있다는 사실을 알게 될 것이다. HTML 속성을 사용해도 이런 레이아웃을 만들 수 있지만, 여기에서는 CSS로 이와 같은 효과를 만들었다.

이러한 마술을 부리게 한 속성/값의 쌍(pair)은 float: left;이다. float와 관련된 좀 더 자세한 사항은 추후에 다른 글에서 다루겠지만, 기본적인 사항은 여기서 짚고 넘어갈 필요가 있다. float: right 또한 완벽하게 사용가능한 속성/값의 쌍이며, 만약 float 속성을 사용하게 하는 class 선언에 반대하여 사용해야 할 경우에는 float: none을 사용할 수 있다.

float 속성은 다음의 몇 가지 사용 지침을 가지고 있다:

  • float 는 명시적인 width값을 가진 블럭 엘러먼트에만 사용될 수 있다.
  • floatclearmargin 속성 모두가 함께 스타일 시트 규칙으로 사용된다는 것은 레이아웃 내에 칼럼을 만든다는 뜻이다.
  • float이 적용된 엘러먼트의 높이를 그것을 담고 있는 컨테이너의 밑바닥까지 늘어나게 하는 것은 까다롭긴 하지만 불가능 한 것은 아니다. 이것을 가능하게 하는 일반적인 방법을 faux-columns라고 한다.

데모 6

pullquote에 float을 사용하는 것에 대해 이야기했으므로, 이제는 우리가 실제로 해보고 결과를 살펴보자. 이것을 하면서 배경에 색상을 추가해서 pullquote 클래스가 메인 컨텐츠와 구별되어 보일 수 있도록 해보자.

링크:
새로운 규칙:
.pullQuote { float: right;
background-color: rgb(204,204,204); }

float 속성을 가진 엘러먼트의 아래에 엘러먼트를 두기: clear 속성

float 속성과 마찬가지로, clear 속성에도 leftrightnone 값을 할당할 수 있다. both 값도 사용될 수 있다.

float속성이 이후의 엘러먼트들의 컨텐츠가 어떻게 해당 엘러먼트 주변에 배치 되는지에 관한 것이라면,clear 속성은 엘러먼트가 어떻게 그의 모든 이웃 엘러먼트(실제로 많은 경우에 이웃이 없다) 주변에 배치되는지에 관한 것이다.

Figure 6 은 clear: left;의 어떻게 사용되는지를 보여준다. 여기에서는 두 개의 초기의 연속된 엘러먼트가 동일한 height을 가지고 있고, float 값으로 각각 left 와 right값을 가진다:

Figure 6: 두 칼럼이 같은 높이값을 가지는 경우, clear:left 를 사용함으로써 이 두 칼럼을 없앨 수 있다.

앞의 예에서, #cLeftWidget의 기본적인(default) 배치는 라틴 텍스트의 바로 아래 ( #fLeftWidget 와#fRightWidget 사이)가 될 것이다.

자 이제 Figure 7에서 처럼, 같은 조건에서 단지 왼쪽 칼럼의 높이만 오른쪽 칼럼의 높이보다 짧아졌다고 가정해보자.

Figure 7: 오른쪽 칼럼이 왼쪽 칼럼보다 길 경우, clear:left 는 두 칼럼 모두를 없애지 않기 때문에,clear:both 가 사용되어야 한다.

첫 번째 예제에서, 원하는 결과를 얻기 위해 우리는 뒤따라오는 엘러먼트의 clear 값을 left로 정해주었다. 여기서 float속성을 가진 두 엘러먼트들이 같은 높이값을 가지고 있었기 때문에 clear속성을 가진 엘러먼트가 아래의 공간을 온전히 확보할 수 있었다. 하지만 두 번째 예제에서 볼 수 있듯이, float속성을 가진 엘러먼트들이 다른 높이를 가질때에 첫번째 예제와 같은 결과를 얻기 위해서는 clear: both; 를 사용해야만 한다.

clear 속성에 대한 논의는 그 효과에 대한 간단한 소개 정도로 마치고, 추후의 다른 글에서 이것의 사용에 대한 좀 더 자세한 기술에 대해 논의하겠다.

요약

각기 다른 렌더링 엔진들의 특성, 전통적으로 정의되어져왔던 기본적인 것들에 대한 요구, 그리고 예측 불가능한 브라우저 윈도우의 크기 가운데서도 웹 문서의 레이아웃이야말로 가장 혼란스럽고 말이 많은 부분이다. 하지만 일반적인 수준의 CSS에 대한 지원은 웹문서가 각기 다른 여러 브라우저에서도 괜찮은 결과를 나타낼 정도로 발전했다.

더 읽을거리

연습문제

  1. 축약된 형태의 margin 값을 쓰는 것이 좋은 경우는 언제이고, margin-top와 같은 단독의 마진 속성을 사용하는 것이 좋은 경우는 언제인가?
  2. 축약형의 marginpaddingborder-width 속성이 네 값을 모두 가지는 경우, 어떤 순서로 이 값들이 엘러먼트의 네 테두리에 적용 되는가?
  3. 당신이 만약에 문서 안에 있는 각각의 헤딩 텍스트에 대한 어떤 규칙을 만들고 싶다면, 어떤 속성을 사용하겠는가?
  4. 엘러먼트를 인터페이스 버튼과 같은 형태로 만들고 싶다면, border-style 속성에 어떤 값을 주어야 할까?
  5. 예/아니오 문제: 엘러먼트의 보더를 설정하면 컨텐츠 주변의 패딩(padding)도 기본적으로 설정이 되는가?
  6. 생성하는 엘러먼트의 너비가 엘러먼트를 포함하는 컨테이너의 너비만큼 넓지 않은 경우, 엘러먼트를 컨테이너의 가로-중앙에 위치하게 하려면 어떤 속성/값을 사용해야 하는가?
  7. 예/아니오 문제: 컨테이너 엘러먼트를 body 안에 넣고 그것의 width 값으로 100% 가 넘는 값을 주었을 때, 다큐먼트 캔버스가 다른 방식으로 작동될까?
  8. 만약 이미지가 그것을 포함하는 컨테이너 엘러먼트보다 훨씬 클 경우, 페이지 레이아웃을 망가뜨리지 않기 위해서 어떤 속성/값을 사용해야 하는가? 왜 그런가?
  9. 만약 a(링크) 엘러먼트의 display속성에 block이란 값을 주고, 엘러먼트에 의미있는 높이와 너비값을 준다면, screen 디스플레이 미디어에서 링크에 마우스오버를 했을 때 어떻게 변하게 될까?
  10. 일반적인 상황에서, 블락 엘러먼트는 자신을 포함하고 있는 컨테이너의 너비를 채우기 위해 확장된다. 만약 엘러먼트가 float된 엘러먼트의 다음에 올 경우에, 기본적으로 이 블락 엘러먼트가 일반적인 상황에서처럼 변할까? 아니면 큰 변화가 없을까?
  11. 만약 엘러먼트에 float 값을 적용시키려 한다면, 엘러먼트의 어떤 속성을 함께 지정해줘야 하는가?
  12. 만약 엘러먼트가 자신의 포함하는 컨테이너의 너비만큼 항상 확장되길 확실히 원한다면, 어떤 속성/값을 지정해야 하는가?

저자에 관하여

Ben Henick은 1995년 교내 자원봉사로 하게 된 웹 프로젝트를 시작으로 지금까지 주로 프리랜서 개발자로 일하면서 크고 작은 웹사이트를 제작해왔다.

Ben은 만능 재주꾼으로서, CSS와 HTML에서부터 디자인 및 카피라이팅, PHP/MySQL 그리고 JavaScript/Ajax에 이르기까지, 사이트 디자인 및 개발에 관련된 대부분의 일을 할 수가 있다.

그는 현재 미국 캔자스주에 위치한 로렌스에서 3대의 컴퓨터와 0대의 텔레비전을 가지고 살고 있다. 그와 그의 일에 대해 더 알고 싶다면 henick.net을 방문하라.

이 글을 다 읽어주셨다면, 댓글을 남겨주세요. 좋았다라는 격려도 좋고, 잘못된 부분을 지적해 주시는 것도 좋습니다. 마음에 드셨다면 아래 Like 버튼을 눌러서 페이스북과 트위터로 소개해 주시면 더욱 좋겠습니다.