16
10월
2007

CSS 박스 모델에 대해

CSS 에서 가장 중요한 개념 중 하나가 박스모델입니다. 박스모델의 개념을 이해함으로써 각각의 엘리먼트를 문서에 배치하는 원리를 알 수 있기 때문입니다. 그리고 이를 응용하여 전체 레이아웃을 정의할 수도 있고, 콘텐츠를 디자인할 수도 있기 때문에 CSS를 통한 디자인을 하려면 박스모델을 이해하는 것이 필수라고 할 수 있습니다.

우선… 첫번째로 이해해야 할 명제는 “모든 엘리먼트, 태그는 박스 모델이다” 라는 것입니다. <br>, <b> 같은 표현을 위한 태그를 제외하면, 자주 사용하는 <div>, <span>, <table>, <p> 등의 태그들은 기본적으로 사각형(박스) 형태로 되어 있습니다.

두번째는 “contents, padding, border, margin” 입니다. 모든 박스모델은 이러한 속성을 가지고 있고 이 순서대로 둘러싸여있다고 보시면 되겠네요. 또한 padding, border, margin이 각각 4가지 속성을 가지고 있는데, top, bottom, left, right 로 분리할 수 있어서 각 방향의 속성을 따로 지정해 줄 수 있습니다. 예를 들어 margin-right:2px; margin-left:2px; 등으로 이렇게 따로 지정해 줄 수 있으며, 각각의 속성은 임의대로 조합해서 사용할 수 있습니다.

  1. contents : 순수한 콘텐츠
  2. padding : 콘텐츠와 경계선 사이의 여백
  3. border : 경계선. 이 선 자체의 모양이나 두께도 바꿀 수 있다.
  4. margin : 경계선 밖에서 박스모델의 최종 경계선까지의 여백

원래 이론상 모든 태그에는 margin, padding, border의 초기값이 0으로 지정되어야 하는 것이 맞지만 각 브라우저의 설정에 따라 기본적으로 가지고 있는 간격이 존재할 수도 있습니다. 예를 들면 순서 없는 리스트를 의미하는 <UL> 내의 엘리먼트인 <LI> 태그의 경우 목록 모양을 만들어주기 위해 버튼 형태와 함께 기본적 패딩을 가지고 있습니다. 보통 CSS로 디자인하기 위해서 <LI> 속성에 list-style:none, padding:0 을 적용해주는 걸 많이 보셨을 거에요.

간단하게 <div>태그로 만든 박스에 패딩을 적용한 소스를 확인해 보겠습니다. 이 편이 박스모델을 이해하는 것이 훨씬 쉬울 것 같습니다.

<div style="width:400px;background:#f2cccc;">
<div style="width:300px;background:#f4f4f4; padding:10px 20px; border:solid 2px red; margin-right:10px; margin-left:10px;">
THIS IS BOX MODEL. THIS IS BOX MODEL. THIS IS BOX MODEL. THIS IS BOX MODEL. THIS IS BOX MODEL. THIS IS BOX MODEL. THIS IS BOX MODEL. THIS IS BOX MODEL. THIS IS BOX MODEL. THIS IS BOX MODEL. THIS IS BOX MODEL. THIS IS BOX MODEL. THIS IS BOX MODEL. 
</div>
</div>

이 모델을 분석하면 다음과 같이 됩니다.

첫번째 div 엘리먼트의 붉은색의 배경은 height를 지정하지 않고 width만 400px으로 지정하였습니다. 이 엘리먼트는 기본적으론 아무 것도 적용하지 않았기 때문에 padding과 margin은 모두 0입니다.

그 안의 두번째 div 엘리먼트는 width는 300px로 지정했으며, padding은 상하 10px, 좌우 20px이고 border는 상하좌우 모두 solid 형태의 2px, margin은 왼쪽과 오른쪽을 각각 10px로 정하였습니다.

즉 이 박스의 전체 width는 10(margin) + 2(border) + 20(padding) + 300(contents) + 20(padding) + 2(border) + 10(margin) = 364px 입니다.

참고로 background-color 속성도 적용되어있는데 background 속성은 contents + padding 영역에 적용이 됩니다.
height의 경우 콘텐츠에 따라 유동적으로 결정되도록 따로 height 를 주지 않아 일정한 높이는 없지만 2px 의 border가 상하에 적용되어 있고, padding이 상하에 10px 적용되어 있는 걸 확인할 수 있죠.

margin과 padding에서 쓸 단위는 px, em, % 등 상관없이 사용할 수 있습니다.
border의 경우 약간 틀린데 경계선의 모양과 색상을 따로 줄 수 있기 때문에 추가 속성이 있습니다. border-width 외에 border-style, border-color 속성 등이 있습니다. border-style 속성의 경우 경계선의 모양을 결정해주는데, 사용되는 밋밋한(?) 형태의 실선인 ‘solid’ 가 자주 사용됩니다.
border-color 속성은 보시다시피 색상을 지정하는데 RGB코드나 색상명으로 사용하구요. 이 세 속성을 연달아 사용할 수 있어서 border:solid 2px red; 등으로 지정할 수 있습니다.


1. margin 및 padding 의 간략한 표기

원래 margin-top, margin-bottom 등으로 따로 표기하는 것이 원칙이지만 이를 간단하게 margin 속성 하나로 제어할 수 있을 뿐만 아니라 일부의 값이 같으면 더 축약하여 쓸 수 있습니다.

줄여 쓸 때에는 margin:5px 10px 15px 20px; 등으로 네개의 값을 연달아 쓸 수 있는데 ‘상우하좌’ 순서입니다. 이는 위쪽부터 시작해서 시계방향으로 돌아가는 것과 같으니 시계방향이라는 것만 기억하셔도 됩니다.

  • 1개 – margin:5px; → 상하 좌우에 모두 똑같이 5px 의 마진이 적용됩니다.
  • 2개 – margin:5px 10px; → 상하에는 5px, 좌우에는 10px 의 마진이 적용됩니다.
  • 3개 – margin:5px 10px 15px; → 상 5px 좌우 10px, 하 15px 의 마진이 적용됩니다.
  • 4개 – margin:5px 10px 15px 20px; → ‘상좌하우’ 방향에 모두 별도의 마진이 적용됩니다.

다만 이렇게 줄여서 쓸 경우엔 한가지 속성만 지정했을 때와 달리, 네가지 값을 한꺼번에 지정하는 효과가 있기 때문에 주의해야 합니다.

만약 초기 마진이 모두 0으로 지정되어 있는 상황에서 margin:9px 0 0 0; 과 margin-top:9px; 는 보이는 것은 같지만 의미가 같지는 않습니다. 전자는 이전 속성에서 지정된 margin-left나 margin-right 값이 다시 0으로 설정되지만, 후자는 따로 지정하지 않았기 때문에 이전 값에 변화가 없습니다.

2. 여러 margin 사이의 충돌

화면 상에서 세로방향(상하)에 연달아 있는 엘리먼트의 경우 margin 속성이 맞닿게 되면 작은 쪽이 없어져 병합되는 현상이 발생합니다.

예를 들어 첫번째 div 엘리먼트가 margin:10px 0;으로 설정되어 있고, 두번째 div 엘리먼트가 margin:20px 0 55px;로 설정되어 있다면 첫번째의 아래 마진 10px와 두번째의 위 마진 20px가 더해져서 총 30px의 마진이 들어가야 원래 의도에 맞습니다만, 이때 마진이 병합되어 작은 마진은 사라지고 20px의 마진이 적용되는 것입니다. 이를 피하기 위해서는 경계선이 없는 엘리먼트의 경우 한쪽에는 마진 대신 패딩을 적용해주면 됩니다. 경계선(border)이 있는 경우는… 코딩을 바꿔야겠지요. ^^

하지만, 이러한 병합은 가로방향(왼쪽, 오른쪽) 마진과 float가 적용된 엘리먼트의 마진의 경우엔 적용되지 않기 때문에 이럴 때에는 걱정하지 않으셔도 됩니다.

3. 음수값의 margin, padding 사용 가능

원래 마진과 패딩 값은 양수 값을 사용하는 것이 원칙이지만 음수를 사용해서 특이한 효과를 줄 수 있습니다. 주로 겹치는 효과 등을 연출할 수 있습니다.

이 문구는 아래 special effect라는 문구가 있는 div 엘리먼트에 margin-top:-10px; 를 준 것입니다. 다만 주의하실 점은 원래 엘리먼트에 링크가 있을 경우에 아래 엘리먼트의 마진을 조정하여 원래 엘리먼트의 영역를 덮을 경우 링크가 적용되지 않는 현상이 발생할 수도 있습니다.

Update. padding property에는 음수는 적용되지 않습니다.

4. 인라인 태그와 블록 태그의 margin, padding 적용의 차이

표현을 위한 태그를 제외한 엘리먼트들은 보통 블록 속성을 가진 태그와 인라인 속성을 가진 태그가 존재합니다. 블록 속성 태그는 <div>로 대표되며 이와 비교되는 인라인 태그가 <span>태그입니다.

블록 속성 태그는 위 아래로 분리된 영역을 가지기 때문에 옆으로 별도의 콘텐츠를 배치할 수 없습니다. 하지만 인라인 속성 태그는 블록을 생성하지 않기 때문에 양 옆으로도 콘텐츠를 배치하는 것이 가능합니다.

이 인라인 태그들에 margin이나 padding 속성을 적용할 때에는 좌우 방향의 값은 적용되지만, 상하 값은 적용되지 않는 것을 유의하셔야 합니다.

CSS 속성 중 display 속성을 지정하여 원래의 인라인 태그나 블록 태그들도 역할을 서로 바꾸는 것이 가능하긴 하지만 display:inline; 등으로 강제적으로 인라인 속성으로 변경한 <div>엘리먼트도 역시 상하 방향의 마진과 패딩이 적용되지 않기 때문에 주의해주세요~

5. 테두리 넣기 (border속성)

경계선은 세가지 속성을 별도로 가지고 있습니다. 어떤 모양인지 보여줄 style과 두께를 말하는 width, 색상을 말하는 color 속성입니다. 이 속성이 상하좌우에 적용되어 border에 관련된 속성은 총 12개의 조합이 있을 수 있습니다. (물론 이와 별도로 구분되는 속성도 있습니다. border-collapse 같은…)

style의 경우 border-top-style, border-bottom-style, … , border-style 속성이 있을 수 있는데 경계선의 모양을 결정합니다. 가장 많이 사용하는 실선의 경우 ‘solid’를 사용합니다. solid, dashed, dotted, double, groove, inset, outset, ridge 등의 속성이 존재합니다만 각각의 모양은 직접 만들어보세요~ (우리나라 특성상 화려한 그래픽을 자랑하는 국내 웹사이트 특성상 이 속성들을 다 사용할 일은 없을 것 같습니다만-_-) width는 말 그대로 두께를 말하고, color 역시 RGB코드 또는 색상명을 사용할 수 있습니다.

border-right:solid 2px red; 등으로 한 방향의 경계선 스타일을 간략하게 지정할 수도 있고 네 방향이 다 같을 경우 border:solid 2px red; 같은 식으로 더 간단하게 통합할 수 있습니다. 속성의 순서는 상관없이 사용할 수 있으며 생략할 수도 있지만, 생략할 경우에는 기본값으로 처리되게 되죠.

6. IE6 Quirks 모드 이하에서의 적용 이상

국내에서 가장 높은 점유율을 자랑하는 IE6의 경우, DTD를 별도로 지정하지 않고 Quirks모드로 돌릴 경우에는 박스 모델의 해석이 약간 틀려집니다. 또한 5.5 이하 버전에서는 상관없이 발생하는 현상인데요.

원래 width 속성으로 지정된 길이는 박스모델 내에서는 contents에 대해 적용되고 margin, border, padding과 별도로 적용되는 것이 맞습니다만, IE6의 Quirks모드와 IE5.5 버전 이하에서는 contents와 함께 padding, border 를 합한 것으로 계산하는 버그가 있습니다.

이를 해결하기 위해서는 표준 모드로 동작할 수 있도록 정확한 DTD를 지정해주는 방법이 1차적인 대책입니다만 IE5.5 이하 버전에서는 이것도 적용되지 않기 때문에 컨디션 코드 또는 CSS 핵을 사용해주어야 합니다. 즉 IE구버전에만 적용되는 CSS핵을 사용하셔서 여기에만 적용되는 width를 직접 계산하셔서 넣어주셔야 하죠.

References: https://www.456bereastreet.com/archive/200612/internet_explorer_and_the_css_box_model/

7. IE6 에서 float속성 적용된 div의 좌우 마진 두배 현상

이 현상은 박스 모델과는 크게 관련은 없지만, 레이아웃/콘텐츠 구성 시 div 엘리먼트의 마진을 조정하면서 이유없이 일어나는 버그이기 때문에 다루어 봅니다.

블록 속성의 엘리먼트에 float 속성을 주면 블록 속성을 유지하면서도 가로로 배열하는 것이 가능합니다. 이 경우가 레이아웃을 잡을 때 많이 사용하는 형태입니다만, IE6의 경우 float된 엘리먼트의 경우 가로 방향의 마진이 적용되는 경우 이 마진이 두배씩 적용되는 현상이 발생합니다. 이것은 위의 경우와는 달리 명백한 버그라고 할 수 있겠네요.

예를 들어 가로 500픽셀의 div 엘리먼트 내에 두개의 div엘리먼트를 float속성을 주어 배열하는 경우를 생각해보죠. 첫번째 엘리먼트는 100픽셀의 가로길이를 가지고 두번째 엘리먼트가 왼쪽 마진을 50px를 가지고 350px의 길이를 가지게 되면 100 + 50 + 350 = 500 의 식에 의해 정확히 맞아 떨어지게 되는 것이 이론상 맞지만..

<div style="width:500px;">
    <div style="float:left;width:100px;">
    LAYER1
    </div>
    <div style="float:left;margin-left:50px;width:350px;">
    LAYER2
    </div>
</div>

타 브라우저에서는 의도한 대로 정확히 보이지만, IE6의 경우 버그 때문에 마진이 두배가 되어 100px 의 마진이 적용되죠. 이것은 전체 길이 500px 를 넘어서게 되어 두번째 엘리먼트는 첫번째 엘리먼트의 다음 줄로 넘어가게 되죠.

이 버그를 해결하려면 float된 두개의 div 엘리먼트에 display:inline; 속성을 주어서 교정할 수 있습니다만, 이 속성은 인라인으로 바뀌는 것이 아니고 단순히 IE의 버그를 해결하기 위해서 존재합니다. 여전히 이 div엘리먼트의 속성은 블록 속성입니다.

You may also like...

7 Responses

  1. freeism 댓글:

    사내 교육 자료로 박스 모델과 마진, 패딩등에 대한 자료를 찾고 있었는데…
    정말 체계적으로 정리가 잘 되어 있네요. ^ —^) 이걸로 설명하면 다 끝날 듯 합니다.
    수고를 덜었습니다. 크~ ^^;;;
    정말 감사합니다~~

  2. 아마티 댓글:

    감사해요 ^^ 도움이 되었다면 정말 다행입니다~
    저도 예전부터 한번 정리해야지~ 하면서 미루다 겨우 했답니다 흐흐…
    좋은 인연 되길 바래요~

  3. karazhan 댓글:

    박스모델에서 각 방향 순서가 기억이 안나 검색해 들어왔어요. 사이트도 예쁘고 내용도 최고네요 ㅎㅎ
    위쪽부터 반시계 방향!
    잘 듣고 갑니다.

  4. 아마티 댓글:

    도움이 되었다니 다행입니다. ^^ 스킨은 이만큼 이쁘게는 힘들겠지만, 나름 제 입맛에 맞게 다시 만들어볼까 생각은 하고 있어요 흐흐

  5. 밥먹자 댓글:

    위에 7번 문제 때문에 머리 뽀개지는 줄 알았는데, inline 적용하니까 바로 되네요~
    버그군요.. ㅎㅎ;;
    덕분에 잘 해결했어요. 정말 감사합니다~^^

  6. 미자 댓글:

    너무 좋은 내용이네요 ㅠㅠㅠㅠ! IE에서 이글루스킨이 제대로 안 보인다고 요청이 들어와서;ㅅ; 이걸 어찌 해결해야하나 하고 고민중이었던 차에 정말 좋은 글을 보고갑니다! 감사합니다!

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다

%d 블로거가 이것을 좋아합니다: