Computer >> 컴퓨터 >  >> 프로그래밍 >> 프로그래밍

반응형 네비게이션 바 만들기: Flexbox vs CSS Grid 비교

이번 튜토리얼에서는 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 네비게이션

데스크톱 레이아웃을 먼저 작성합니다. '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 스타일

모바일에서는 모든 콘텐츠를 중앙 정렬하고, 보조 링크들이 다음 줄로 넘어가게 합니다.

  1. justify-content: space-between을 미디어 쿼리(600px 이상)로 옮기고, 기본값을 center로 설정.
  2. flex-wrap: wrap으로 줄바꿈 허용.
  3. <ul>fullwidth 헬퍼 클래스를 추가해 모바일에서 100% 너비를 차지하게 함(flex: 1 0 100%).
  4. 보조 링크 각각의 너비를 모바일에서 100px로 고정(flex: 0 0 100px)해 'Blog'가 'Home' 정중앙에 오게 함.
  5. '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에서 확인하실 수 있습니다.