내비게이션은 사용자에게 지금 어디에 있고 어디로 갈 수 있는지를 알려 주는 안내판입니다. 이 안내판은 대부분 flex와 링크 스타일 몇 줄로 만들어집니다. 아래 예제로 상단 바부터 모바일 하단 탭까지 코드로 세워 보겠습니다.

14.1 상단 가로 바

가장 흔한 내비게이션은 위쪽에 가로로 걸린 바입니다. 로고는 왼쪽, 메뉴는 오른쪽에 두는 배치를 flex로 잡습니다.


.nav {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20px;
height: 56px;
}
.nav .menu {
display: flex;
gap: 20px;
}


justify-content: space-between이 로고와 메뉴를 양 끝으로 밀어냅니다. 메뉴 안쪽은 또 다른 flex로 항목들을 20px 간격으로 늘어놓습니다.

14.2 링크 스타일과 hover

메뉴 항목은 눌리는 것임이 보여야 합니다. 기본 밑줄은 걷어 내되 손을 올리면 반응하게 합니다.


.menu a {
color: #4b5563;
text-decoration: none;
padding: 8px 4px;
transition: color .15s;
}
.menu a:hover {
color: #111827;
}


평소엔 차분한 회색이다가 마우스를 올리면 짙어집니다. 이 작은 변화가 여기는 눌러도 되는 곳이라고 손끝에 일러 줍니다.

14.3 현재 위치 표시

사용자가 지금 어느 화면에 있는지 메뉴에서 도드라져야 합니다. 색과 밑줄로 현 위치를 짚습니다.


.menu a.active {
color: #2563eb;
font-weight: 600;
border-bottom: 2px solid #2563eb;
}


지금 보는 화면의 메뉴만 파랗게 물들고 아래 선이 깔립니다. 색을 못 보는 사용자를 위해 굵기까지 함께 바꿔, 신호를 색 하나에만 맡기지 않았습니다.

14.4 접근성을 위한 마크업

겉모습만 링크처럼 꾸미면 키보드나 스크린 리더 앞에서 무용지물이 됩니다. 진짜 링크와 nav 태그로 짭니다.


<nav aria-label="주 메뉴">
<a href="/">홈</a>
<a href="/board" aria-current="page">게시판</a>
<a href="/qna">질문</a>
</nav>


aria-current="page"는 스크린 리더가 이 항목이 현재 위치라고 읽게 해 줍니다. 눈에 보이는 파란 강조와 짝을 이뤄, 보는 사람과 듣는 사람 모두에게 현 위치가 닿습니다.

14.5 모바일 하단 탭

좁은 화면에서는 엄지가 닿는 아래쪽에 탭을 두는 편이 편합니다. 화면 하단에 고정하고 균등하게 나눕니다.


.tabbar {
position: fixed;
left: 0;
right: 0;
bottom: 0;
display: flex;
height: 56px;
border-top: 1px solid #e5e7eb;
background: #fff;
}
.tabbar a {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: 11px;
}


flex: 1을 준 탭들이 화면 폭을 똑같이 나눠 가집니다. 세로 flex로 아이콘 위에 라벨을 얹으면 좁은 탭 안에서도 뜻이 분명해집니다.

14.6 햄버거 메뉴 토글

좁은 화면에서 메뉴를 접어 둘 때는, 자주 쓰는 항목 한둘은 밖에 남기고 나머지만 접습니다. 미디어쿼리로 전환합니다.


.menu {
display: flex;
gap: 20px;
}
@media (max-width: 640px) {
.menu {
display: none;
}
.menu.open {
display: flex;
flex-direction: column;
}
}


640px 아래에서는 메뉴가 숨었다가, open 클래스가 붙으면 세로로 펼쳐집니다. 눌러야 열리는 메뉴는 그만큼 덜 발견되니, 정말 자주 찾는 것은 밖에 꺼내 두는 편이 좋습니다.

14.7 이동 경로 표시

갈래가 여러 층 깊어지면 지금 어느 골목까지 왔는지 자취를 남깁니다. 상위에서 현재까지의 경로를 나열합니다.


.crumbs {
display: flex;
gap: 8px;
font-size: 13px;
color: #9ca3af;
}
.crumbs a { color: #6b7280; }
.crumbs span::before {
content: "/";
margin-right: 8px;
color: #d1d5db;
}


::before로 항목 사이에 슬래시를 넣으면 마크업을 더럽히지 않고 구분선을 그립니다. 사용자는 이 자취를 따라 언제든 상위로 거슬러 오를 수 있습니다.

14.8 스크롤에 따라오는 바

화면이 길면 아래로 내려가도 메뉴가 따라와야 편합니다. sticky 한 줄이면 됩니다.


.nav {
position: sticky;
top: 0;
z-index: 10;
background: #fff;
box-shadow: 0 1px 0 #e5e7eb;
}


position: sticky는 스크롤이 바를 지날 때부터 화면 위에 붙박습니다. z-index로 본문보다 앞에 세워 내용에 가리지 않게 하고, 얇은 그림자로 아래 내용과 경계를 지었습니다.

14.9 포커스 표시

키보드로 메뉴를 넘나드는 사용자를 위해 지금 어느 항목에 포커스가 있는지 또렷이 보여야 합니다.


.menu a:focus-visible {
outline: 2px solid #2563eb;
outline-offset: 4px;
border-radius: 4px;
}


focus-visible는 마우스 클릭엔 조용하고 키보드 이동에만 외곽선을 띄웁니다. 마우스를 안 쓰는 사람도 지금 여기가 어디인지 놓치지 않습니다.

14.10 드롭다운 하위 메뉴

항목이 많으면 상위 메뉴 아래로 하위 목록을 접어 둡니다. 마우스를 올리거나 포커스가 갈 때 펼칩니다.


.has-sub {
position: relative;
}
.submenu {
position: absolute;
top: 100%;
left: 0;
display: none;
min-width: 160px;
padding: 8px 0;
background: #fff;
border: 1px solid #e5e7eb;
border-radius: 8px;
}
.has-sub:hover .submenu,
.has-sub:focus-within .submenu {
display: block;
}


부모에 position: relative를 주고 하위 목록을 absolute로 바로 아래에 띄웁니다. focus-within을 함께 걸어, 키보드로 상위에 들어와도 하위가 펼쳐지게 했습니다. 마우스에만 열리면 키보드 사용자는 하위를 영영 못 보니까요.

14.11 정리

내비게이션은 flex로 늘어놓고, 링크에 hover와 active로 상태를 입히고, sticky로 따라오게 하고, 미디어쿼리로 좁은 화면에 맞추는 몇 가지 조합으로 대부분 완성됩니다. 화려한 모양보다 지금 어디에 있고 어디로 갈 수 있는지라는 두 물음의 답이 어느 화면에서나 또렷한지를 먼저 챙기면, 사용자는 넓은 화면에서도 길을 잃지 않습니다.