icon
3장 : CSS 기초와 레이아웃

박스 모델과 요소 배치


지난 장에서 우리는 CSS를 이용해 웹 페이지의 색상, 폰트, 텍스트 스타일을 섬세하게 조절하는 방법을 배웠습니다. 이제 HTML 요소들이 화면에 어떻게 배치되고 공간을 차지하는지에 대한 근본적인 원리인 CSS 박스 모델(Box Model) 을 이해할 차례입니다. 웹 페이지의 모든 HTML 요소는 기본적으로 사각형의 '박스(Box)' 형태로 존재하며, 이 박스들이 어떻게 상호작용하고 공간을 차지하는지를 이해하는 것은 웹 레이아웃을 정확하게 제어하는 데 필수적입니다.

이 장에서는 CSS 박스 모델의 구성 요소들을 자세히 살펴보고, 각 요소의 크기와 여백을 제어하는 다양한 CSS 속성들을 학습할 것입니다. 또한, HTML 요소들이 기본적으로 화면에 어떻게 배치되는지, 그리고 이 배치 방식을 제어하는 display 속성에 대해서도 알아보겠습니다. 이 지식은 복잡한 웹 레이아웃을 구현하기 위한 단단한 기반이 될 것입니다.


CSS 박스 모델: 모든 HTML 요소는 상자다!

웹 페이지의 모든 HTML 요소는 박스 모델이라는 개념을 기반으로 렌더링됩니다. 즉, 여러분이 본 모든 div, p, img, a 태그는 화면에서 보이지 않는 사각형 박스로 둘러싸여 있다고 생각할 수 있습니다. 이 박스 모델은 콘텐츠, 패딩, 테두리, 마진이라는 네 가지 주요 구성 요소로 이루어져 있습니다.

박스 모델의 구성 요소

콘텐츠(Content)

  • 텍스트, 이미지, 비디오 등 요소의 실제 내용이 들어가는 영역입니다.
  • widthheight 속성으로 이 콘텐츠 영역의 크기를 조절합니다.

패딩(Padding)

  • 콘텐츠 영역과 테두리(Border) 사이의 여백입니다. 마치 액자 속 그림 주변의 매트와 같습니다.
  • 패딩은 배경색(background-color)의 영향을 받습니다.
  • 속성:
    • padding-top, padding-right, padding-bottom, padding-left: 각 방향의 패딩을 개별적으로 설정합니다.
    • padding: 상하좌우 모든 방향의 패딩을 한 번에 설정하는 단축 속성입니다.
    • padding: 10px; (모든 방향 10px)
    • padding: 10px 20px; (상하 10px, 좌우 20px)
    • padding: 10px 20px 30px; (상 10px, 좌우 20px, 하 30px)
    • padding: 10px 20px 30px 40px; (상 10px, 우 20px, 하 30px, 좌 40px - 시계 방향)

테두리(Border)

  • 패딩과 마진(Margin) 사이의 선입니다. 콘텐츠와 패딩을 둘러싸는 경계선 역할을 합니다.
  • 속성:
    • border-width: 테두리의 두께
    • border-style: 테두리의 스타일 (solid, dotted, dashed, double 등)
    • border-color: 테두리의 색상
    • border: 위의 세 속성을 한 번에 설정하는 단축 속성입니다.
    • border: 1px solid black; (1px 두께, 실선, 검정색)
    • 각 방향별 속성도 있습니다. border-top, border-right, border-bottom, border-left

마진(Margin)

  • 테두리(Border) 바깥쪽의 여백입니다. 요소와 요소 사이의 간격을 조절하는 데 사용됩니다.
  • 마진은 배경색의 영향을 받지 않고 투명합니다.
  • 속성
    • margin-top, margin-right, margin-bottom, margin-left: 각 방향의 마진을 개별적으로 설정합니다.
    • margin: 상하좌우 모든 방향의 마진을 한 번에 설정하는 단축 속성입니다. (패딩과 동일한 방식)
    • margin: 20px; (모든 방향 20px)
    • margin: 0 auto; (좌우 마진을 자동으로 설정하여 블록 요소를 가로로 중앙 정렬할 때 사용, 상하 마진은 0)

box-sizing 속성: 계산 방식 변경

CSS 박스 모델의 기본 계산 방식은 widthheight가 콘텐츠 영역만을 의미합니다. 따라서 패딩과 테두리를 추가하면 요소의 실제 크기가 지정한 width/height보다 커집니다. 이는 레이아웃 계산을 어렵게 만들 수 있습니다.

box-sizing 속성은 이러한 계산 방식을 변경합니다.

  • content-box (기본값)

    • width, height콘텐츠 영역만을 의미합니다.
    • 실제 요소의 너비 = width + padding-left + padding-right + border-left-width + border-right-width
  • border-box

    • width, height패딩과 테두리를 포함한 영역을 의미합니다. 콘텐츠 영역은 이 값에서 패딩과 테두리를 뺀 나머지입니다.
    • 이 방식은 레이아웃을 만들 때 요소의 실제 크기를 예측하기 훨씬 쉬워 현대 웹 개발에서 널리 사용됩니다.
    • 강력 권장: 대부분의 CSS 프레임워크나 최신 프로젝트에서는 * { box-sizing: border-box; }를 사용하여 모든 요소의 박스 모델을 border-box로 설정하고 시작합니다.
    /* 모든 요소에 border-box 적용 */
    * {
        box-sizing: border-box;
    }
    
    .my-box {
        width: 200px;
        height: 100px;
        padding: 20px;
        border: 5px solid blue;
        /*
        content-box일 경우 실제 너비: 200 + 20*2 + 5*2 = 250px
        border-box일 경우 실제 너비: 200px (패딩과 보더가 200px 안에 포함됨)
        */
    }

display 속성: 요소의 기본 배치 방식

모든 HTML 요소는 기본적으로 display라는 속성을 가지고 있으며, 이 속성 값에 따라 웹 페이지에 어떻게 나타나고 공간을 차지하는지가 결정됩니다. CSS를 사용하여 이 display 속성 값을 변경함으로써 요소의 배치 방식을 제어할 수 있습니다.

블록(Block) 요소

  • 항상 새로운 줄에서 시작합니다.

  • 부모 요소의 가로 너비(100%)를 기본적으로 모두 차지합니다. (가능한 최대 너비)

  • width, height, margin, padding, border 속성을 모두 사용할 수 있습니다.

  • 예시: <div>, <h1>~<h6>, <p>, <ul>, <li>, <form>, <header>, <footer>, <section>, <article>, <aside>

    div {
        background-color: lightblue;
        width: 200px; /* 너비를 지정해도 새로운 줄에서 시작 */
        height: 100px;
        margin-bottom: 10px; /* 마진 적용 가능 */
    }

인라인(Inline) 요소

  • 새로운 줄에서 시작하지 않고, 콘텐츠의 흐름에 따라 이전 요소 바로 옆에 배치됩니다.

  • 콘텐츠의 너비만큼만 공간을 차지합니다.

  • width, height 속성은 적용되지 않습니다. (콘텐츠 크기에 따라 결정됨)

  • margin-top, margin-bottom, padding-top, padding-bottom은 적용되지만, 다른 인라인 요소에 영향을 주지 않으므로 시각적인 효과가 제한적입니다. (margin-left, margin-right, padding-left, padding-right는 정상 적용)

  • 예시: <span>, <a>, <strong>, <em>, <img>, <input>, <label>

    span {
        background-color: lightgreen;
        padding: 5px; /* 좌우 패딩은 적용 */
        margin-right: 5px; /* 좌우 마진은 적용 */
        /* width, height는 적용되지 않음 */
    }

    💡 주의: <img> 태그는 인라인 요소이지만 widthheight 속성이 적용됩니다. 이는 img가 콘텐츠 자체의 고유한 크기를 가지기 때문입니다. 하지만 기본적으로는 텍스트 흐름에 따라 배치됩니다.

인라인-블록(Inline-Block) 요소

  • 인라인 요소처럼 새로운 줄에서 시작하지 않고 콘텐츠 흐름에 따라 배치됩니다.

  • 블록 요소처럼 width, height, margin, padding, border 속성을 모두 자유롭게 적용할 수 있습니다.

  • 인라인과 블록의 장점을 결합한 형태입니다.

  • 적용 방법: display: inline-block;

    .card {
        display: inline-block; /* 옆으로 나열되면서 */
        width: 150px; /* 너비와 높이 지정 가능 */
        height: 180px;
        background-color: #f0f0f0;
        margin: 10px; /* 마진도 자유롭게 */
        padding: 15px;
        border: 1px solid #ddd;
    }

    💡 활용: 메뉴 항목 (<li>), 버튼, 작은 카드 형태의 UI 요소 등을 가로로 나열하면서도 개별적인 크기나 여백을 제어해야 할 때 매우 유용합니다.

display: none;

  • 요소를 완전히 숨기고, 공간도 차지하지 않도록 합니다. 화면에서 완전히 제거된 것처럼 동작합니다.

  • 스크린 리더 등 보조 기술에서도 이 요소를 읽지 않습니다.

  • 참고: visibility: hidden;은 요소를 숨기지만, 공간은 그대로 차지합니다.

    .hidden-element {
        display: none; /* 요소가 보이지 않고 공간도 차지하지 않음 */
    }
    .invisible-element {
        visibility: hidden; /* 요소는 보이지 않지만 공간은 차지함 */
    }

마진 상쇄(Margin Collapsing) 현상 (심화)

블록 요소의 수직 마진(top-margin, bottom-margin)은 때때로 흥미로운 방식으로 동작합니다. 인접한 두 블록 요소의 수직 마진이 겹칠 때, 두 마진 중 더 큰 값 하나만 적용되는 현상을 마진 상쇄(Margin Collapsing) 또는 마진 병합이라고 합니다.

  • 적용되는 경우

    형제 요소 간의 상하 마진: 위 요소의 margin-bottom과 아래 요소의 margin-top이 만날 때.

    부모-자식 요소 간의 상하 마진: 부모 요소의 margin-top과 첫 번째 자식 요소의 margin-top이 겹칠 때 (패딩이나 보더로 분리되지 않은 경우).

    빈 블록 요소의 상하 마진: 패딩, 보더, 콘텐츠가 없는 빈 블록 요소의 margin-topmargin-bottom이 겹칠 때.

  • 예시

    <div style="margin-bottom: 20px; background-color: lightcoral;">첫 번째 박스</div>
    <div style="margin-top: 30px; background-color: lightgreen;">두 번째 박스</div>

    마진 상쇄는 CSS 레이아웃을 예측하기 어렵게 만들 수 있지만, 의도된 디자인 패턴이며 특정 상황에서 요소 간의 불필요한 간격을 줄여줍니다. 마진 상쇄를 피하려면 padding이나 border를 추가하거나, display: flex 또는 display: grid와 같은 새로운 레이아웃 방식을 사용하면 됩니다.


실습: 박스 모델과 display 속성 활용

지금까지 배운 박스 모델과 display 속성들을 활용하여 간단한 제품 목록 페이지를 만들어 봅시다.

프로젝트 폴더 구조

products.html
product.css

products.html 파일 작성

products.html
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>박스 모델과 Display 실습 - 제품 목록</title>
    <link rel="stylesheet" href="css/product.css">
</head>
<body>
    <header>
        <h1>우리 가게 인기 상품</h1>
        <p>다양한 제품을 만나보세요!</p>
    </header>

    <main>
        <div class="product-grid">
            <div class="product-item">
                <img src="https://via.placeholder.com/150x150?text=Product+A" alt="제품 A 이미지">
                <h3>멋진 제품 A</h3>
                <p>이 제품은 정말 멋집니다. 한 번 사용해 보세요!</p>
                <span class="price">25,000원</span>
                <a href="#" class="buy-button">구매하기</a>
            </div>

            <div class="product-item">
                <img src="https://via.placeholder.com/150x150?text=Product+B" alt="제품 B 이미지">
                <h3>매력적인 제품 B</h3>
                <p>당신을 더욱 빛나게 할 아이템입니다.</p>
                <span class="price">40,000원</span>
                <a href="#" class="buy-button">구매하기</a>
            </div>

            <div class="product-item">
                <img src="https://via.placeholder.com/150x150?text=Product+C" alt="제품 C 이미지">
                <h3>실용적인 제품 C</h3>
                <p>일상에 편리함을 더해줄 제품!</p>
                <span class="price">15,000원</span>
                <a href="#" class="buy-button">구매하기</a>
            </div>
        </div>

        <div class="info-section">
            <p>더 많은 제품 정보는 <a href="#">여기</a>를 클릭하세요.</p>
            <span class="contact-info">문의: support@ourshop.com</span>
            <span class="notice-info">공지사항: 배송 지연 안내</span>
        </div>
    </main>

    <footer>
        <p>&copy; 2025 우리 가게. 모든 권리 보유.</p>
    </footer>
</body>
</html>

css/product.css 파일 작성

css/product.css
/* 모든 요소에 border-box 적용하여 박스 모델 계산 용이하게 함 (강력 권장) */
* {
    box-sizing: border-box;
}

body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    margin: 0;
    background-color: #f4f7f6;
    color: #333;
    line-height: 1.6;
}

/* 헤더 스타일 */
header {
    background-color: #4CAF50; /* 초록색 */
    color: white;
    text-align: center;
    padding: 30px 20px;
    margin-bottom: 30px; /* 헤더 아래 여백 */
    box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}

header h1 {
    font-size: 2.8em;
    margin-bottom: 10px; /* h1 아래 여백 */
}

header p {
    font-size: 1.2em;
    margin: 0; /* p 태그 기본 마진 제거 */
}

/* 메인 콘텐츠 영역 */
main {
    max-width: 1000px;
    margin: 0 auto 50px auto; /* 좌우 auto로 중앙 정렬 */
    padding: 20px;
}

/* 제품 그리드 (세로 정렬된 블록 요소들) */
.product-grid {
    display: flex; /* Flexbox는 다음 장에서 자세히 배우지만, 여기서는 요소들을 가로로 배치하는 데 사용 */
    flex-wrap: wrap; /* 요소들이 공간이 부족하면 다음 줄로 넘어가도록 함 */
    justify-content: center; /* 가로 중앙 정렬 */
    gap: 30px; /* 요소들 사이의 간격 */
    margin-bottom: 40px;
}

/* 각 제품 아이템 스타일 */
.product-item {
    width: 280px; /* 각 제품 아이템의 고정 너비 */
    background-color: white;
    border: 1px solid #ddd;
    border-radius: 8px;
    padding: 20px;
    text-align: center;
    box-shadow: 0 2px 10px rgba(0,0,0,0.08);
    transition: transform 0.2s ease-in-out; /* 호버 애니메이션 */
}

.product-item:hover {
    transform: translateY(-5px); /* 호버 시 살짝 위로 이동 */
}

.product-item img {
    max-width: 100%;
    height: auto;
    border-radius: 5px;
    margin-bottom: 15px; /* 이미지 아래 마진 */
}

.product-item h3 {
    font-size: 1.5em;
    color: #2c3e50;
    margin-bottom: 10px; /* 제목 아래 마진 */
}

.product-item p {
    font-size: 0.95em;
    color: #666;
    margin-bottom: 15px; /* 문단 아래 마진 */
}

/* 가격 (인라인 요소) */
.price {
    display: block; /* 인라인 요소였던 span을 블록 요소처럼 동작하게 함 */
    font-size: 1.3em;
    font-weight: bold;
    color: #e67e22; /* 주황색 */
    margin-bottom: 20px; /* 가격 아래 마진 */
}

/* 구매 버튼 (인라인 요소인 a 태그를 블록처럼 꾸밈) */
.buy-button {
    display: inline-block; /* 버튼이면서 가로 나열 가능 */
    background-color: #3498db; /* 파란색 */
    color: white;
    padding: 10px 25px;
    border-radius: 5px;
    text-decoration: none; /* 밑줄 제거 */
    font-weight: bold;
    transition: background-color 0.3s ease;
}

.buy-button:hover {
    background-color: #2980b9; /* 호버 시 색상 변경 */
}

/* 정보 섹션 */
.info-section {
    text-align: center;
    padding: 20px;
    background-color: #ecf0f1; /* 연한 회색 배경 */
    border-radius: 8px;
    margin-top: 40px;
    box-shadow: 0 2px 5px rgba(0,0,0,0.05);
}

.info-section p {
    margin-bottom: 10px;
}

.info-section a {
    color: #3498db;
    text-decoration: none;
    font-weight: bold;
}

.info-section a:hover {
    text-decoration: underline;
}

/* 인라인 요소들의 배치 (display: inline-block 활용) */
.contact-info, .notice-info {
    display: inline-block; /* 옆으로 나열되면서 패딩, 마진 적용 가능 */
    background-color: #fff;
    padding: 8px 15px;
    border: 1px solid #c9d9e4;
    border-radius: 20px;
    font-size: 0.9em;
    margin: 5px 10px; /* 요소들 간의 간격 */
}

/* 푸터 스타일 */
footer {
    background-color: #2c3e50;
    color: #ecf0f1;
    text-align: center;
    padding: 20px 0;
    margin-top: 30px; /* 푸터 위 여백 */
    font-size: 0.9em;
}

결과 확인

  • Live Server를 통해 products.html 파일을 열어보세요.
  • 각 제품 아이템이 사각형 박스 형태로 정돈되어 배치되고, 그 안의 콘텐츠, 패딩, 테두리, 마진이 어떻게 적용되었는지 확인해 보세요.
  • display: inline-block으로 변경된 가격(span.price)과 구매하기 버튼(a.buy-button)의 동작을 관찰해 보세요. 이들이 어떻게 블록처럼 크기를 가지면서도 인라인처럼 옆으로 나열되는지 확인하는 것이 중요합니다.
  • .contact-info.notice-info span 태그들이 옆으로 나란히 배치되는 것을 통해 display: inline-block의 효과를 다시 한번 이해할 수 있습니다.

이번 장에서는 CSS 레이아웃의 가장 근본적인 개념인 박스 모델(Box Model) 을 학습했습니다. 모든 HTML 요소가 콘텐츠, 패딩, 테두리, 마진으로 구성된 사각형 박스로 표현된다는 것을 이해하고, width, height, padding, border, margin 속성들을 사용하여 이 박스들의 크기와 공간을 제어하는 방법을 배웠습니다. 특히 box-sizing: border-box;의 중요성을 강조했습니다.

또한, 요소들이 화면에 어떻게 배치되는지를 결정하는 display 속성에 대해 알아보면서, 블록(block), 인라인(inline), 그리고 둘의 장점을 결합한 인라인-블록(inline-block) 요소의 특징과 활용법을 익혔습니다. 마진 상쇄 현상과 그 해결법에 대한 심화 내용도 다루어, 더 깊은 이해를 돕고자 했습니다.