Logo

[CSS] 성배 (Holy Grail) 레이아웃 (Flexbox, Grid)

웹사이트에서 정말 흔하게 접할 수 있는 성배(Holy Grail) 레이아웃은 한 때 개발자 사이에서 제대로 구현하기 어렵기로 악명이 높았었는데요. Flexbox와 CSS Grid가 보편화되면서 이제는 옛말이 되어 가고 있는 것 같습니다.

이번 포스트에서는 CSS의 최신 기술을 이용하여 어떻게 성배 레이아웃을 구현할 수 있는지 알아보도록 하겠습니다.

기본 구조

성배 레이아웃은 일반적으로 5개의 영역으로 구성이 되는데요. 회면 최상단에 각각 헤더(header)와 풋터(footer) 영역이 위치하고, 그 사이의 영역이 다시 네비게이션(nav), 메인(main), 사이드바(aside) 영역으로 나누어지게 됩니다.

시멘틱(semantic) HTML을 이용해서 성배 레이아웃을 마크업을 해보면 다음과 같은 구조를 가지게 됩니다.

<div class="wrapper">
  <header>Header</header>
  <nav>Nav</nav>
  <main>Main</main>
  <aside>Aside</aside>
  <footer>Footer</footer>
</div>

성배 레이아웃의 핵심은 전체 화면을 가로로 3개의 영역을 분할한체로, 중앙에 있는 3개의 영역을 어떻게 추가로 세로로 분할하냐는 것인데요. 예전에는 HTML의 <table> 엘리먼트나 CSS의 float 속성을 이용해서 이 부분을 다소 억지스럽게 처리했었습니다. 하지만 최근에는 Flexbox나 CSS Grid를 이용해서 이러한 레이아웃을 좀 더 효과적으로 만들 수가 있게 되었습니다.

CSS Grid

현재 대부분의 모던 브라우저에서 지원하고 있는 CSS Grid를 사용하면 성배 레이아웃을 매우 쉽게 구현할 수 있습니다.

먼저 최외각 엘리먼트의 display 속성을 grid로 바꾸서 레이아웃을 Grid 모드로 전환해줍니다. 그 다음, grid-template 속성을 통해 중간에 있는 메인 영역이 가장 큰 공간을 차지하는 3 x 3 Grid를 만들어줍니다.

각 영역에는 grid-column 속성을 이용하여 Grid 내에서 점유할 공간을 지정할 수 있습니다. 헤더와 풋터 영역은 한 줄을 전체를 점유하고, 네비게이션과, 메인, 사이드바 영역은 한칸만 차지하도록 설정을 합니다.

.wrapper {
  display: grid;
  grid-template: auto 1fr auto / auto 1fr auto;
  height: 100%;
}

header {
  grid-column: 1 / 4;
}

nav {
  grid-column: 1 / 2;
}

main {
  grid-column: 2 / 3;
}

aside {
  grid-column: 3 / 4;
}

footer {
  grid-column: 1 / 4;
}

Flexbox

CSS Grid를 지원하지 않는 구식의 브라우저를 이용하는 사용자를 위해서, Flexbox를 중첩하여 동일한 성배 레이아웃을 만들 수 있습니다.

Flexbox는 Gird와 달리 가로가 됐든 세로가 됐든 단방향 레이아웃만 가능하기 때문에 HTML 코드에 약간의 변경이 필요합니다. 다음과 같이 헤더와 풋터 사이의 영역을 새로운 엘리먼트로 묶어줌으로써 두 개의 다른 방향으로 Flexbox를 적용할 수 있도록 해줍니다.

<div class="wrapper">
  <header>Header</header>
  <section>
    <nav>Nav</nav>
    <main>Main</main>
    <aside>Aside</aside>
  </section>
  <footer>Footer</footer>
</div>

.wrapper 클래스에는 세로 방향의 Flex 컨테이너(container)로 전환하고, <section> 엘리먼트에는 가로 방향의 Flex 컨테이너로 전환합니다. Flexbox의 기본 방향이 가로 이기 때문에, .wrapper 클래스에만 flex-direction 속성을 column으로 지정해주었습니다.

이제 메인 영역이 가장 많은 공간을 차지하도록 Flex 아이템(item)의 flex 속성을 조정해줄 차례입니다. <section> 엘리먼트의 flex 속성을 1로 지정해주므로서, 헤더와 풋터 사이에 여유 공간을 모두 점유할 수 있게 해줍니다. <main> 엘리먼트의 flex 속성을 1로 지정해주므로서, 네비게이션과 사이드바 사이에 여유 공간을 모두 점유할 수 있게 해줍니다.

.wrapper {
  display: flex;
  flex-direction: column;
  height: 100%;
}

section {
  flex: 1;
  display: flex;
}

main {
  flex: 1;
}

마치면서

한 4년 전 쯤, 다른 포스팅을 통해 비슷한 레이아웃을 만드는 방법을 float 속성을 이용해서 설명드렸던 기억이 나네요. 당시만 해도 익스플로러와 같이 최신 CSS 지원이 빈약한 브라우저 때문에 울며 겨자먹기로 float 속성을 사용해서 레이아웃을 잡는 경우가 더러 있었었죠. 최근에는 많은 웹사이트들이 익스플로러 지원을 중단하면서 자연스럽게 Flexbox나 CSS Grid로 레이아웃을 구성하는 것이 트랜드로 자리 잡고 있습니다.