HTML&CSS/레이아웃 구성

실습: Flexbox로 카드형 레이아웃 만들기 완벽 가이드

코딩하는 패션이과생 2025. 5. 11. 17:26
반응형

카드형 레이아웃은 현대 웹 디자인에서 가장 널리 사용되는 UI 패턴 중 하나입니다. 제품 목록, 블로그 포스트, 팀원 소개 등 다양한 콘텐츠를 깔끔하고 일관된 방식으로 표시할 수 있어 사용자 경험을 크게 향상시킵니다. 이번 실습에서는 CSS Flexbox를 활용하여 반응형 카드 레이아웃을 처음부터 만드는 방법을 단계별로 알아보겠습니다.

완성 미리보기

우리가 이번 실습을 통해 만들 카드형 레이아웃의 최종 결과물은 다음과 같습니다:

  • 균일한 크기의 카드 컴포넌트
  • 그리드처럼 정렬된 카드들
  • 반응형(모바일, 태블릿, 데스크톱 지원)
  • 이미지, 제목, 설명, 버튼을 포함한 카드 디자인
  • 부드러운 호버 효과
  • 깔끔한 그림자 효과

모바일에서는 한 줄에 하나의 카드가, 태블릿에서는 두 개의 카드가, 데스크톱에서는 세 개 이상의 카드가 한 줄에 표시됩니다.

카드형 레이아웃의 장점

카드형 레이아웃이 인기 있는 이유는 여러 가지가 있습니다:

  1. 일관된 정보 구조: 모든 콘텐츠가 동일한 형식으로 표시되어 사용자가 정보를 쉽게 파악할 수 있습니다.
  2. 시각적 계층 구조: 각 카드는 독립적인 단위로 인식되어 정보의 구분이 명확합니다.
  3. 반응형 디자인에 적합: 화면 크기에 따라 카드의 배치를 쉽게 조정할 수 있습니다.
  4. 터치 친화적: 모바일 환경에서 카드는 터치하기 좋은 크기로 설계할 수 있습니다.
  5. 확장성: 콘텐츠가 추가되어도 레이아웃의 일관성을 유지할 수 있습니다.

HTML 구조 작성

먼저, 카드 레이아웃을 위한 기본 HTML 구조를 작성해보겠습니다. 이번 예제에서는 여행 목적지를 소개하는 카드 레이아웃을 만들어 보겠습니다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>여행 목적지 카드 레이아웃</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div class="container">
        <h1 class="page-title">인기 여행 목적지</h1>
        
        <div class="card-container">
            <!-- 카드 1 -->
            <div class="card">
                <div class="card-image">
                    <img src="https://blog.kakaocdn.net/dn/o1KIw/btqu9mflPY6/rGk1mM3iugV1c6jj9Z3E80/img.jpg" alt="제주도 풍경">
                </div>
                <div class="card-content">
                    <h2 class="card-title">제주도</h2>
                    <p class="card-description">
                        아름다운 자연 경관과 독특한 문화가 어우러진 한국의 대표 휴양지입니다.
                        화산섬 특유의 독특한 지형과 맑은 바다가 매력적입니다.
                    </p>
                    <div class="card-footer">
                        <span class="card-price">350,000원~</span>
                        <button class="card-button">자세히 보기</button>
                    </div>
                </div>
            </div>
            
            <!-- 카드 2 -->
            <div class="card">
                <div class="card-image">
                    <img src="https://i.namu.wiki/i/XO6E06_qrvaiZnbaLsHC-Ov1z4WI8vRqSn_R9IqHobEgHD2gYLLN3Ldi3zvnFLRYcLTQmWpRuAdsfH_2IrNNPQ.webp" alt="경주 불국사">
                </div>
                <div class="card-content">
                    <h2 class="card-title">경주</h2>
                    <p class="card-description">
                        천년 고도의 역사와 문화를 간직한 도시로, 불국사, 석굴암 등
                        유네스코 세계문화유산을 만나볼 수 있습니다.
                    </p>
                    <div class="card-footer">
                        <span class="card-price">150,000원~</span>
                        <button class="card-button">자세히 보기</button>
                    </div>
                </div>
            </div>
            
            <!-- 카드 3 -->
            <div class="card">
                <div class="card-image">
                    <img src="https://i.namu.wiki/i/hkDOgJHC40yiIFKQDRz7YjHpzWrL9vCTT7mve4TF6Lj-GpGsBpvT8WlXbwOT_To1Ndl1zKrVLQ-SiwaGNFOgQA.webp" alt="부산 해운대">
                </div>
                <div class="card-content">
                    <h2 class="card-title">부산</h2>
                    <p class="card-description">
                        아름다운 해변과 활기찬 시장, 현대적인 도시 경관이 어우러진
                        한국 제2의 도시입니다. 해운대와 광안리는 필수 방문지입니다.
                    </p>
                    <div class="card-footer">
                        <span class="card-price">200,000원~</span>
                        <button class="card-button">자세히 보기</button>
                    </div>
                </div>
            </div>
            
            <!-- 카드 4 -->
            <div class="card">
                <div class="card-image">
                    <img src="https://i2.wp.com/www.agoda.com/wp-content/uploads/2019/05/Gyeongbokgung-palace-Seoul-architecture-view.jpg" alt="서울 경복궁">
                </div>
                <div class="card-content">
                    <h2 class="card-title">서울</h2>
                    <p class="card-description">
                        전통과 현대가 공존하는 대한민국의 수도. 경복궁, 명동, 강남 등
                        다양한 매력의 장소들이 여러분을 기다립니다.
                    </p>
                    <div class="card-footer">
                        <span class="card-price">180,000원~</span>
                        <button class="card-button">자세히 보기</button>
                    </div>
                </div>
            </div>
            
            <!-- 카드 5 -->
            <div class="card">
                <div class="card-image">
                    <img src="https://www.travelnbike.com/news/photo/201710/46420_50343_3757.jpg" alt="속초 설악산">
                </div>
                <div class="card-content">
                    <h2 class="card-title">속초/설악산</h2>
                    <p class="card-description">
                        웅장한 설악산과 동해의 푸른 바다가 만나는 곳. 신선한 해산물과
                        아름다운 자연 경관을 동시에 즐길 수 있습니다.
                    </p>
                    <div class="card-footer">
                        <span class="card-price">220,000원~</span>
                        <button class="card-button">자세히 보기</button>
                    </div>
                </div>
            </div>
            
            <!-- 카드 6 -->
            <div class="card">
                <div class="card-image">
                    <img src="https://cdn.visitkorea.or.kr/img/call?cmd=VIEW&id=1a802bf2-2628-4d77-bfe5-19bef8d0ece2" alt="전주 한옥마을">
                </div>
                <div class="card-content">
                    <h2 class="card-title">전주</h2>
                    <p class="card-description">
                        전통 한옥과 맛있는 음식으로 유명한 도시. 한옥마을에서 한국의
                        전통 문화를 체험하고 비빔밥의 본고장을 느껴보세요.
                    </p>
                    <div class="card-footer">
                        <span class="card-price">130,000원~</span>
                        <button class="card-button">자세히 보기</button>
                    </div>
                </div>
            </div>
        </div>
    </div>
</body>
</html>

이 HTML 구조에서 주목할 점:

  1. .container: 전체 콘텐츠를 감싸는 컨테이너
  2. .card-container: 모든 카드를 감싸는 Flexbox 컨테이너가 될 요소
  3. .card: 개별 카드 컴포넌트
  4. .card-image: 카드 상단의 이미지 영역
  5. .card-content: 카드의 텍스트 콘텐츠 영역
  6. .card-footer: 가격과 버튼이 위치하는 카드 하단 영역

기본 CSS 설정

이제 스타일링을 시작하겠습니다. 먼저 기본적인 CSS 설정과 전체 레이아웃을 잡아보겠습니다.

/* 기본 리셋 및 폰트 설정 */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: 'Noto Sans KR', sans-serif;
    line-height: 1.6;
    color: #333;
    background-color: #f8f9fa;
    padding: 20px;
}

.container {
    max-width: 1200px;
    margin: 0 auto;
    padding: 20px;
}

.page-title {
    text-align: center;
    margin-bottom: 40px;
    color: #1a1a1a;
    font-size: 2.5rem;
}

/* 이미지 기본 스타일 */
img {
    max-width: 100%;
    height: auto;
    display: block;
}

이 기본 설정은 다음과 같은 역할을 합니다:

  • 모든 요소의 기본 마진과 패딩을 제거
  • box-sizing: border-box로 요소의 크기 계산 방식 설정
  • 기본 폰트와 라인 높이, 텍스트 색상 설정
  • 페이지 배경색 설정
  • 최대 너비가 1200px인 중앙 정렬된 컨테이너 설정
  • 페이지 제목 스타일링
  • 이미지가 컨테이너를 넘어가지 않도록 설정

카드 컴포넌트 스타일링

이제 개별 카드 컴포넌트의 스타일을 정의해보겠습니다.

/* 카드 기본 스타일 */
.card {
    background-color: #fff;
    border-radius: 8px;
    overflow: hidden;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
    transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.card:hover {
    transform: translateY(-5px);
    box-shadow: 0 5px 20px rgba(0, 0, 0, 0.15);
}

/* 카드 이미지 영역 */
.card-image {
    height: 200px;
    overflow: hidden;
}

.card-image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.5s ease;
}

.card:hover .card-image img {
    transform: scale(1.05);
}

/* 카드 콘텐츠 영역 */
.card-content {
    padding: 20px;
}

.card-title {
    font-size: 1.5rem;
    margin-bottom: 10px;
    color: #1a1a1a;
}

.card-description {
    color: #666;
    font-size: 0.95rem;
    margin-bottom: 20px;
    /* 두 줄 이상이면 말줄임표(...) 표시 */
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-overflow: ellipsis;
    height: 4.8em; /* line-height(1.6) * 3줄 */
}

/* 카드 푸터 영역 */
.card-footer {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding-top: 15px;
    border-top: 1px solid #eee;
}

.card-price {
    font-weight: bold;
    color: #ff6b6b;
    font-size: 1.1rem;
}

.card-button {
    background-color: #4dabf7;
    color: white;
    border: none;
    padding: 8px 16px;
    border-radius: 4px;
    cursor: pointer;
    font-weight: 500;
    transition: background-color 0.2s ease;
}

.card-button:hover {
    background-color: #339af0;
}

카드 스타일의 주요 포인트:

  1. 기본 스타일: 흰색 배경, 둥근 모서리, 부드러운 그림자
  2. 호버 효과: 마우스 오버시 카드가 약간 위로 떠오르고 그림자가 강화
  3. 이미지 영역: 고정 높이와 object-fit: cover로 이미지 비율 유지
  4. 이미지 호버 효과: 마우스 오버시 이미지가 약간 확대
  5. 설명 텍스트: 3줄 이상은 말줄임표(...) 처리
  6. 푸터 영역: Flexbox로 가격과 버튼 배치

Flexbox로 카드 배치하기

이제 Flexbox를 사용하여 카드들을 그리드 형태로 배치하겠습니다.

/* 카드 컨테이너 레이아웃 */
.card-container {
    display: flex;
    flex-wrap: wrap;
    gap: 30px;
    justify-content: center;
}

/* 기본(모바일) 카드 너비 */
.card {
    width: 100%; /* 모바일에서는 한 줄에 하나의 카드 */
    max-width: 400px;
}

이 코드는 다음과 같은 레이아웃을 구성합니다:

  • .card-containerdisplay: flex를 적용하여 Flexbox 컨테이너로 만듭니다.
  • flex-wrap: wrap으로 카드가 한 줄에 다 들어가지 않으면 다음 줄로 넘어가도록 합니다.
  • gap: 30px으로 카드 사이의 간격을 설정합니다.
  • justify-content: center로 카드들을 중앙에 정렬합니다.
  • 모바일 뷰에서는 카드 너비를 100%로 설정하여 한 줄에 하나의 카드만 표시합니다.

반응형 디자인 적용

이제 미디어 쿼리를 사용하여 화면 크기에 따라 카드 레이아웃이 변하도록 설정하겠습니다.

/* 태블릿 뷰 */
@media (min-width: 768px) {
    .card {
        width: calc(50% - 15px); /* 한 줄에 2개 카드 (간격 고려) */
    }
}

/* 데스크톱 뷰 */
@media (min-width: 1024px) {
    .card {
        width: calc(33.333% - 20px); /* 한 줄에 3개 카드 */
    }
}

/* 대형 데스크톱 뷰 */
@media (min-width: 1440px) {
    .card {
        width: calc(25% - 22.5px); /* 한 줄에 4개 카드 */
    }
}

반응형 디자인의 브레이크포인트:

  • 768px 이상(태블릿): 한 줄에 2개의 카드가 표시됩니다.
  • 1024px 이상(데스크톱): 한 줄에 3개의 카드가 표시됩니다.
  • 1440px 이상(대형 데스크톱): 한 줄에 4개의 카드가 표시됩니다.

각 카드의 너비는 컨테이너 너비 백분율에서 간격을 고려하여 계산됩니다.

고급 스타일링 효과

카드 레이아웃에 몇 가지 고급 효과를 추가해 보겠습니다.

/* 카드 배지(신규 상품 등 표시) */
.card {
    position: relative;
}

.card-badge {
    position: absolute;
    top: 10px;
    right: 10px;
    background-color: #ff6b6b;
    color: white;
    padding: 5px 10px;
    border-radius: 4px;
    font-size: 0.8rem;
    font-weight: bold;
    z-index: 1;
}

/* 카드 로딩 애니메이션 */
@keyframes fadeIn {
    from { opacity: 0; transform: translateY(20px); }
    to { opacity: 1; transform: translateY(0); }
}

.card {
    animation: fadeIn 0.5s ease forwards;
    opacity: 0;
}

.card:nth-child(1) { animation-delay: 0.1s; }
.card:nth-child(2) { animation-delay: 0.2s; }
.card:nth-child(3) { animation-delay: 0.3s; }
.card:nth-child(4) { animation-delay: 0.4s; }
.card:nth-child(5) { animation-delay: 0.5s; }
.card:nth-child(6) { animation-delay: 0.6s; }

이 코드는 다음 효과를 추가합니다:

  1. 카드 배지: "NEW", "인기" 등의 배지를 카드 우측 상단에 표시할 수 있습니다.
  2. 로딩 애니메이션: 페이지가 로드될 때 카드가 아래에서 위로 서서히 나타나는 효과가 적용됩니다.

HTML에서 배지를 추가하려면 아래와 같이 특정 카드에 코드를 추가하세요:

<div class="card">
    <span class="card-badge">NEW</span>
    <!-- 나머지 카드 내용 -->
</div>

접근성 향상 팁

카드 레이아웃의 접근성을 향상시키기 위한 몇 가지 팁을 적용해 보겠습니다.

/* 포커스 스타일 개선 */
.card-button:focus {
    outline: 3px solid #4dabf7;
    outline-offset: 2px;
}

/* 고대비 모드 지원 */
@media (prefers-contrast: high) {
    .card {
        border: 2px solid #000;
    }

    .card-title, .card-description {
        color: #000;
    }

    .card-button {
        background-color: #000;
        color: #fff;
        border: 2px solid #000;
    }
}

/* 화면 리더기 전용 텍스트 */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border-width: 0;
}

HTML에서는 다음과 같이 활용할 수 있습니다:

<button class="card-button">
    자세히 보기
    <span class="sr-only">제주도 여행 상품에 대한 상세 정보</span>
</button>

완성된 코드

지금까지 작성한 모든 CSS 코드를 하나로 합치면 다음과 같습니다:

/* 기본 리셋 및 폰트 설정 */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: 'Noto Sans KR', sans-serif;
    line-height: 1.6;
    color: #333;
    background-color: #f8f9fa;
    padding: 20px;
}

.container {
    max-width: 1200px;
    margin: 0 auto;
    padding: 20px;
}

.page-title {
    text-align: center;
    margin-bottom: 40px;
    color: #1a1a1a;
    font-size: 2.5rem;
}

/* 이미지 기본 스타일 */
img {
    max-width: 100%;
    height: auto;
    display: block;
}

/* 카드 컨테이너 레이아웃 */
.card-container {
    display: flex;
    flex-wrap: wrap;
    gap: 30px;
    justify-content: center;
}

/* 카드 기본 스타일 */
.card {
    background-color: #fff;
    border-radius: 8px;
    overflow: hidden;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
    transition: transform 0.3s ease, box-shadow 0.3s ease;
    width: 100%; /* 모바일에서는 한 줄에 하나의 카드 */
    max-width: 400px;
    position: relative;
    animation: fadeIn 0.5s ease forwards;
    opacity: 0;
}

.card:hover {
    transform: translateY(-5px);
    box-shadow: 0 5px 20px rgba(0, 0, 0, 0.15);
}

/* 카드 로딩 애니메이션 */
@keyframes fadeIn {
    from { opacity: 0; transform: translateY(20px); }
    to { opacity: 1; transform: translateY(0); }
}

.card:nth-child(1) { animation-delay: 0.1s; }
.card:nth-child(2) { animation-delay: 0.2s; }
.card:nth-child(3) { animation-delay: 0.3s; }
.card:nth-child(4) { animation-delay: 0.4s; }
.card:nth-child(5) { animation-delay: 0.5s; }
.card:nth-child(6) { animation-delay: 0.6s; }

/* 카드 배지 */
.card-badge {
    position: absolute;
    top: 10px;
    right: 10px;
    background-color: #ff6b6b;
    color: white;
    padding: 5px 10px;
    border-radius: 4px;
    font-size: 0.8rem;
    font-weight: bold;
    z-index: 1;
}

/* 카드 이미지 영역 */
.card-image {
    height: 200px;
    overflow: hidden;
}

.card-image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.5s ease;
}

.card:hover .card-image img {
    transform: scale(1.05);
}

/* 카드 콘텐츠 영역 */
.card-content {
    padding: 20px;
}

.card-title {
    font-size: 1.5rem;
    margin-bottom: 10px;
    color: #1a1a1a;
}

.card-description {
    color: #666;
    font-size: 0.95rem;
    margin-bottom: 20px;
    /* 두 줄 이상이면 말줄임표(...) 표시 */
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-overflow: ellipsis;
    height: 4.8em; /* line-height(1.6) * 3줄 */
}

/* 카드 푸터 영역 */
.card-footer {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding-top: 15px;
    border-top: 1px solid #eee;
}

.card-price {
    font-weight: bold;
    color: #ff6b6b;
    font-size: 1.1rem;
}

.card-button {
    background-color: #4dabf7;
    color: white;
    border: none;
    padding: 8px 16px;
    border-radius: 4px;
    cursor: pointer;
    font-weight: 500;
    transition: background-color 0.2s ease;
}

.card-button:hover {
    background-color: #339af0;
}

.card-button:focus {
    outline: 3px solid #4dabf7;
    outline-offset: 2px;
}

/* 화면 리더기 전용 텍스트 */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border-width: 0;
}

/* 태블릿 뷰 */
@media (min-width: 768px) {
    .card {
        width: calc(50% - 15px); /* 한 줄에 2개 카드 (간격 고려) */
    }
}

/* 데스크톱 뷰 */
@media (min-width: 1024px) {
    .card {
        width: calc(33.333% - 20px); /* 한 줄에 3개 카드 */
    }
}

/* 대형 데스크톱 뷰 */
@media (min-width: 1440px) {
    .card {
        width: calc(25% - 22.5px); /* 한 줄에 4개 카드 */
    }
}

/* 고대비 모드 지원 */
@media (prefers-contrast: high) {
    .card {
        border: 2px solid #000;
    }

    .card-title, .card-description {
        color: #000;
    }

    .card-button {
        background-color: #000;
        color: #fff;
        border: 2px solid #000;
    }
}

응용 및 확장 아이디어

카드 레이아웃을 더 발전시킬 수 있는 몇 가지 아이디어를 소개합니다:

1. 필터링 기능 추가

카테고리 버튼을 추가하여 특정 카드만 표시할 수 있는 필터링 기능을 구현할 수 있습니다:

<div class="filter-buttons">
    <button class="filter-btn active" data-filter="all">전체</button>
    <button class="filter-btn" data-filter="nature">자연</button>
    <button class="filter-btn" data-filter="culture">문화</button>
    <button class="filter-btn" data-filter="food">음식</button>
</div>

JavaScript로 필터링 기능을 구현할 수 있습니다.

2. 카드 내용의 동적 로딩

카드 데이터를 JSON 형식으로 준비하고 JavaScript로 동적으로 카드를 생성할 수 있습니다. 이를 통해 API에서 데이터를 가져오거나 페이지네이션을 구현할 수 있습니다.

3. 그리드 레이아웃 대안

Flexbox 대신 CSS Grid를 사용하여 카드 레이아웃을 구현하는 방법도 있습니다:

.card-container {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 30px;
}

이 방법은 카드의 크기를 일정하게 유지하면서 화면 크기에 따라 열 수가 자동으로 조정됩니다.

4. 스켈레톤 로딩 상태

데이터 로딩 중에 표시할 스켈레톤 UI를 추가할 수 있습니다:

.card-skeleton {
    background: #fff;
    border-radius: 8px;
    overflow: hidden;
    height: 350px;
    padding: 20px;
}

.skeleton-image {
    width: 100%;
    height: 200px;
    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
    background-size: 200% 100%;
    animation: loading 1.5s infinite;
    margin-bottom: 15px;
}

.skeleton-title {
    width: 70%;
    height: 24px;
    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
    background-size: 200% 100%;
    animation: loading 1.5s infinite;
    margin-bottom: 10px;
}

@keyframes loading {
    0% { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}

마무리

이 실습을 통해 Flexbox를 활용하여 반응형 카드 레이아웃을 처음부터 만드는 방법을 배웠습니다. 카드 디자인은 웹사이트의 사용자 경험을 크게 향상시킬 수 있으며, 이 기본 패턴을 다양한 프로젝트에 응용할 수 있습니다.

기억해야 할 주요 포인트:

  1. 구조와 스타일 분리: HTML로 의미 있는 구조를 만들고 CSS로 스타일을 적용
  2. Flexbox의 유연성: 다양한 화면 크기에 쉽게 적응하는 레이아웃 구성
  3. 반응형 디자인: 미디어 쿼리를 통한 다양한 화면 크기 지원
  4. 시각적 효과: 호버 효과, 애니메이션 등으로 사용자 경험 향상
  5. 접근성: 모든 사용자가 콘텐츠에 접근할 수 있도록 배려

이 카드 레이아웃은 쇼핑몰, 블로그, 포트폴리오, 레스토랑 메뉴 등 다양한 웹사이트에 적용할 수 있습니다. 필요에 맞게 색상, 폰트, 여백 등을 조정하여 브랜드에 맞는 디자인을 만들어보세요!


이 튜토리얼이 도움이 되었나요? 질문이나 피드백이 있으시면 댓글로 남겨주세요. 다음 실습에서는 CSS Grid를 활용한 더 복잡한 레이아웃 구성에 대해 알아보겠습니다.