이번 튜토리얼에서는 HTML과 CSS를 사용해 상단 네비게이션 바를 제작해 보겠습니다. Flexbox 방식과 CSS Grid 방식, 두 가지 접근법을 모두 다뤄 그 차이점을 비교하고 자신에게 더 잘 맞는 방법을 찾아보실 수 있습니다.
완성된 네비게이션 바 미리보기
데스크톱 환경에서는 모든 링크가 한 줄에 배치되며, 'Home'은 왼쪽에, 나머지 링크들은 오른쪽에 정렬됩니다.
모바일 환경에서는 'Home'이 첫 번째 행에, 나머지 링크들이 두 번째 행에 중앙 정렬되어 배치됩니다.
파일 설정
index.html 파일과 style.scss 파일을 생성합니다. SCSS 파일은 VS Code의 Live Sass Compiler 확장 프로그램을 사용해 style.css로 컴파일합니다. <head> 섹션에 <link> 요소를 추가해 컴파일된 CSS 파일을 불러옵니다.
HTML 마크업 작성
가능한 한 시맨틱 HTML 태그를 사용해 의미 있는 구조를 만듭니다. <nav> 요소 안에 네비게이션 링크들을 담고, 링크들은 순서 없는 목록 <ul> 요소로 구성합니다.
<nav>
<ul>
<li><a href="#">Home</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Blog</a></li>
<li><a href="#">Contact</a></li>
</ul>
</nav>
이 마크업을 기본으로 Flexbox 버전과 Grid 버전용으로 두 개의 <nav> 요소를 복사해 둡니다. 브라우저에서 확인하면 기본 스타일만 적용된 단순한 모습입니다.
전역 스타일 및 미디어 쿼리 추가
먼저 항상 사용하는 전역 스타일을 추가합니다.
html {
font-size: 100%;
box-sizing: border-box;
}
body {
margin: 0;
padding: 0;
min-height: 100vh;
}
*, *::before, *::after {
box-sizing: inherit;
}
다크 테마를 위해 <body>에 background-color: #1b1b1b를, 모든 요소와 링크에는 color: #ffffff를 적용합니다. <nav> 안의 <ul>에는 불릿을 숨기고 여백을 제거합니다. <nav>에는 기본 패딩 10px을 주고, 태블릿/데스크톱에서는 미디어 쿼리로 20px로 늘립니다.
nav {
padding: 10px;
@media (min-width: 600px) {
padding: 20px;
}
}
글꼴은 Google Fonts의 'Open Sans'를 사용합니다. SCSS 파일 최상단에 import 구문을 추가하고 <body>에 폰트 패밀리를 지정합니다.
@import url('https://fonts.googleapis.com/css?family=Open+Sans&display=swap');
body {
font-family: 'Open Sans', Arial, Helvetica, sans-serif;
}
링크 스타일: 그라데이션 밑줄 효과
기본 밑줄을 제거하고(text-decoration: none), 가상 요소(::before)를 이용해 두꺼운 핑크색 밑줄을 만듭니다. 호버 시에는 핑크에서 퍼플로 그라데이션이 적용되도록 합니다. 색상 관리를 위해 SCSS 변수를 정의합니다.
$linkPink: rgb(216, 29, 216);
$linkPurple: rgb(98, 16, 250);
a {
position: relative;
text-decoration: none;
}
a::before {
content: "";
position: absolute;
height: 3px;
right: 0;
bottom: -3px;
left: 0;
background-color: $linkPink;
}
<a>에 position: relative를 주어 가상 요소가 부모 기준 절대 위치로 배치되게 합니다. bottom: -3px으로 텍스트와 약간의 간격을 두고, left: 0, right: 0으로 링크 너비만큼 선을 채웁니다.
호버 시 그라데이션 스타일
a:hover {
color: $linkPink;
&::before {
background: linear-gradient(to right, $linkPink 40%, $linkPurple 75%);
}
}
왼쪽에서 오른쪽으로 40%까지 핑크, 75%부터 퍼플, 중간은 자연스러운 그라데이션으로 전환됩니다. 텍스트 색상도 핑크로 변경되어 시각적 피드백을 줍니다.
이제 Flexbox와 Grid 양쪽에서 공통으로 사용할 기본 스타일이 완성되었습니다.
Flexbox 네비게이션
링크를 Flex 자식 그룹으로 나누기
데스크톱 레이아웃을 먼저 작성합니다. 'Home'은 왼쪽, 나머지 세 링크는 오른쪽에 모아둡니다. Flexbox에서는 이를 위해 링크를 두 그룹으로 나누고, 둘 다 Flex 컨테이너(<nav>)의 직계 자식이 되게 해야 합니다.
HTML을 수정해 'Home' 링크를 <ul> 밖으로 꺼내 <nav> 직계 자식으로 만들고, 나머지 링크는 <ul> 안에 둡니다. 구분을 위해 <nav>에 flexbox 클래스를 추가합니다.
<nav class="flexbox">
<a href="#">Home</a>
<ul>
<li><a href="#">About</a></li>
<li><a href="#">Blog</a></li>
<li><a href="#">Contact</a></li>
</ul>
</nav>
데스크톱용 Flexbox 스타일
nav.flexbox {
display: flex;
justify-content: space-between;
align-items: center;
ul {
display: flex;
align-items: center;
}
ul li {
margin-right: 20px;
&:last-child {
margin-right: 0;
}
}
}
nav.flexbox를 Flex 컨테이너로 만들고 justify-content: space-between으로 양끝 정렬합니다. <ul>도 Flex 컨테이너로 만들어 자식 링크들을 수평 정렬하고, margin-right로 간격을 줍니다(마지막 항목 제외).
모바일용 Flexbox 스타일
모바일에서는 모든 콘텐츠를 중앙 정렬하고, 보조 링크들이 다음 줄로 넘어가게 합니다.
justify-content: space-between을 미디어 쿼리(600px 이상)로 옮기고, 기본값을center로 설정.flex-wrap: wrap으로 줄바꿈 허용.<ul>에fullwidth헬퍼 클래스를 추가해 모바일에서 100% 너비를 차지하게 함(flex: 1 0 100%).- 보조 링크 각각의 너비를 모바일에서 100px로 고정(
flex: 0 0 100px)해 'Blog'가 'Home' 정중앙에 오게 함. - 'Home' 링크 하단에 여백(
margin-bottom: 10px) 추가.
nav.flexbox {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
@media (min-width: 600px) {
justify-content: space-between;
}
> a {
margin-bottom: 10px;
@media (min-width: 600px) {
margin-bottom: 0;
}
}
.fullwidth {
flex: 1 0 100%;
justify-content: center;
@media (min-width: 600px) {
flex: 0 1 auto;
}
}
ul li {
flex: 0 0 100px;
margin-right: 10px;
text-align: center;
@media (min-width: 600px) {
flex: 0 0 auto;
margin-right: 20px;
}
&:last-child {
margin-right: 0;
}
}
}
CSS Grid 네비게이션
Flexbox가 '콘텐츠 우선(content-first)' 접근이라면, Grid는 '그리드 우선(grid-first)' 접근입니다. 부모에서 그리드 템플릿(열/행)을 정의하고, 각 자식 요소를 그리드 셀에 배치합니다. 덕분에 모든 링크를 하나의 <ul> 안에 둘 수 있습니다.
<nav class="grid">
<ul>
<li><a href="#">Home</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Blog</a></li>
<li><a href="#">Contact</a></li>
</ul>
</nav>
모바일용 Grid 스타일 (모바일 퍼스트)
<ul>을 Grid 컨테이너로 만들고(display: grid), 3열 템플릿을 정의합니다(grid-template-columns: repeat(3, 100px)). grid-gap: 10px으로 간격을 주고, justify-content: center, justify-items: center로 전체 그리드와 셀 안 콘텐츠를 중앙 정렬합니다.
'Home' 링크가 3열을 모두 차지하게 하려면 해당 <li>에 fullwidth 클래스를 주고 grid-column: 1 / 4를 지정합니다(1번 선에서 4번 선까지).
데스크톱용 Grid 스타일
데스크톱에서는 4열로 변경하고, 첫 열은 남은 공간을 모두 차지(1fr), 나머지 세 열은 콘텐츠 크기에 맞춤(fit-content(50px))합니다. 정렬도 오른쪽 정렬(justify-items: end)로 바꾸고, 'Home'만 왼쪽 정렬(justify-self: start)합니다.
nav.grid ul {
display: grid;
grid-template-columns: repeat(3, 100px);
grid-gap: 10px;
justify-content: center;
justify-items: center;
@media (min-width: 600px) {
grid-template-columns: 1fr repeat(3, fit-content(50px));
justify-items: end;
}
.fullwidth {
grid-column: 1 / 4;
@media (min-width: 600px) {
grid-column: 1 / 2;
justify-self: start;
}
}
}
Flexbox vs Grid: 어느 쪽을 선택할까?
이 예제에서 Flexbox 스타일은 약 46줄, Grid 스타일은 24줄이 소요되었습니다. Grid가 더 간결한 이유는 grid-gap 한 줄로 간격 처리가 끝나기 때문입니다. Flexbox는 각 자식에 마진을 일일이 지정해야 합니다.
개인적으로 Grid의 간결한 코드를 선호하지만, Flexbox에 더 익숙하다면 여전히 훌륭한 선택지입니다. 전체 소스 코드는 Codepen에서 확인하실 수 있습니다.