본문 바로가기
프론트엔드 HTML CSS JAVASCRIPT

[HTML, CSS] 기본적인 페이지 레이아웃(layout) 잡기 네이버 클론코딩 (2) - flex, grid 레이아웃

by jaewooojung 2020. 3. 28.

HTML CSS


네이버 UI 클론코딩 (2) - flex, grid 레이아웃

이전 글에서 완성한 header, footer에 이어 이 글에서는 main 영역을 만들어보겠습니다. main에서는 모든 요소를 세부적으로 카피하지는 않고 레이아웃을 구현하는 작업을 두 가지 방식으로 살펴보겠습니다.

  1. 큰 단위부터 작은 단위로
  2. grid cell로 나눠서 할당

네이버 레이아웃

 

1. 큰 단위부터 작은 단위로

가장 큰 요소부터 시작해서 하위 요소들을 점진적으로 나눠주는 방식입니다. body를 header, main, footer의 영역으로, main을 또다시 각 구역으로, 각 구역을 다시 세부적으로 계속 나눠줍니다.

 

우선 main영역을 크게 아래와 같이 나눠보겠습니다.

flex 레이아웃

  
여기서는 flex와 grid 레이아웃을 자유롭게 사용할 수 있습니다. 이전 글에서도 말씀드렸지만 어느 한 가지 기술이 반드시 필요한 경우는 없습니다. 가장 편안한 레이아웃을 사용하면 됩니다. (grid 시스템이 가장 강력하긴 합니다.)
 
저는 위의 8개의 구역을 나누는 작업은 grid 레이아웃을, 각 구역 내부에서의 작업은 flex 레이아웃을 사용해 보겠습니다.

 

index.html - main

<main>
  <div class="box-container">
    <div class="box-item">1</div>
    <div class="box-item">2</div>
    <div class="box-item">3</div>
    <div class="box-item">4</div>
    <div class="box-item">5</div>
    <div class="box-item">6</div>
    <div class="box-item">7</div>
    <div class="box-item">8</div>
  </div>
</main>

여기서는 모두 div를 사용했지만, 실제로는 각 구역의 역할에 따라 section, article을 활용하시면 좋습니다.

 

main {
  background: #f2f4f7;
  min-height: 700px;
}
.box-container {
  width: 1080px;
  margin: auto;
  display: grid;
  grid-template-columns: 740px 330px; /* 각 행(세로줄)의 길이 */
  grid-template-rows: 120px 310px 890px 130px; /* 각 열(가로줄)의 길이 */
  gap: 10px; /* 자식요소간의 간격 */
}
.box-item {
  background: yellow;
  width: 100%;
  height: 100%;
  font-size: 40px;
  border: 1px solid #dee3eb;
  text-align: center;
}

main의 8개 구역

 

네이버 사이트를 자세히 보면 3번 구역과 4번 구역이 각각 두 부분으로 나뉘어 있습니다. 이곳을 각각 3-1, 3-2 / 4-1, 4-2로
flex 레이아웃을 사용해서 나눠보겠습니다.

 

index.html - main

<main>
  <div class="box-container">
    <div class="box-item">1</div>
    <div class="box-item">2</div>
    <div class="box-item box3">
      <div>3-1</div>
      <div>3-2</div>
    </div>
    <div class="box-item box4">
      <div>4-1</div>
      <div>4-2</div>
    </div>
    <div class="box-item">5</div>
    <div class="box-item">6</div>
    <div class="box-item">7</div>
    <div class="box-item">8</div>
  </div>
</main>

 

main.css

main {
  background: #f2f4f7;
  min-height: 700px;
}
.box-container {
  width: 1080px;
  margin: auto;
  display: grid;
  grid-template-columns: 740px 330px;
  grid-template-rows: 120px 310px 890px 130px;
  gap: 10px; /* 구역간의 간격 */
}
.box-item {
  background: yellow;
  width: 100%;
  height: 100%;
  font-size: 40px;
  border: 1px solid #dee3eb;
  text-align: center;
}
.box3 {
  display: flex;
  flex-direction: column; /* 세로 정렬 */
  gap: 10px;
  border: none; /* border를 지우고 3-1과 3-2에 각각 border를 적용해줍니다. */
}
.box3 > div:first-child {
  width: 100%;
  flex: 1; /* 공간차지비율 */
  border: 1px solid #dee3eb;
}
.box3 > div:last-child {
  width: 100%;
  flex: 8; /* 공간차지비율 */
  border: 1px solid #dee3eb;
}
.box4 {
  display: flex;
  flex-direction: column;
  gap: 10px;
  border: none;
}
.box4 > div:first-child {
  flex: 1;
  border: 1px solid #dee3eb;
}
.box4 > div:last-child {
  flex: 1;
  border: 1px solid #dee3eb;
}

 

3-1, 3-2 / 4-1, 4-2

 

완성되었습니다. 이렇게 큰 단위부터 하나씩 나눠서 구현하면 눈에 보이는 대로, 직관적으로 쉽게 설계할 수 있습니다.

 

2. grid cell

화면을 grid cell이라는 최소 단위의 균일한 블록으로 나눈 뒤, grid layout을 활용하여 각 구역에 cell들을 할당하는 방식입니다. 그림으로 살펴보겠습니다.

첫번째 방식

 

위와 같은 최종 레이아웃을 만들기 위해 main영역 전체를 X*Y의 균일한 cell들로 나눠줍니다.

 

 

그 후 각 cell이 속한 구역을 지정해 주면 준비완료입니다.

균일한 cell로 나눈 후 구역 지정

 

가로 3개 * 세로 24개 = 총 72개의 cell들로 나뉘었습니다.
 
계산이 끝났으니 grid 시스템에 적용해 줍니다.

 

index.html - main

<main>
  <div class="box-container">
  </div>
</main>

 

main.css

main {
  background: #f2f4f7;
  min-height: 700px;
}
.box-container {
  width: 1080px;
  margin: auto;
  display: grid;
  grid-template-columns: repeat(3, 1fr); /* 균일한 크기로 3등분 */
  grid-template-rows: repeat(24, 40px); /* 40px로 24등분 -> <main> 영역의 전체 height가 계산된다면 height 지정 후 1fr로 사용하셔도 좋습니다.*/
}

 

 

개발자 도구를 열어서 (F12) <div class="box-container"> 요소를 확인해 봅니다.

 

개발자 도구에서 확인

 

 

해당 요소의 코드에 마우스를 올리면 좌측 화면에서 grid system에 의해 나뉜 구역을 확인할 수 있습니다.
 
다음으로 1~8번 구역에 각 cell을 할당해 주면 됩니다. grid-column과 grid-row 속성을 사용합니다.

<main>
  <div class="box-container">
    <div class="box-item box1">1</div>
  </div>
</main>
main {
  background: #f2f4f7;
}
.box-container {
  width: 1080px;
  margin: auto;
  display: grid;
  grid-template-columns: repeat(3, 1fr); /* 균일한 크기로 3등분 */
  grid-template-rows: repeat(24, 40px); /* 40px로 24등분 -> <main> 영역의 전체 height가 계산된다면 height 지정 후 1fr로 사용하셔도 좋습니다.*/
  gap: 10px;
}
.box-item {
  background: skyblue;
  text-align: center;
  font-size: 30px;
  border: 1px solid #dee3eb;
}
.box1 {
  grid-column: 1 / 3; /* 시작column번호 / 끝column번호 */
  grid-row: 1 / 3; /* 시작row번호 / 끝row번호 */
}

 

 

여기에 사용되는 column번호와 row번호는 다음과 같습니다.

column, row 번호
1번 구역에 cell 할당

 

1번 구역에 cell들이 할당되었습니다. 나머지 구역들도 모두 할당해 줍니다.

<main>
  <div class="box-container">
    <div class="box-item box1">1</div>
    <div class="box-item box2">2</div>
    <div class="box-item box3-1">3-1</div>
    <div class="box-item box3-2">3-2</div>  
    <div class="box-item box4-1">4-1</div>
    <div class="box-item box4-2">4-2</div>
    <div class="box-item box5">5</div>
    <div class="box-item box6">6</div>
    <div class="box-item box7">7</div>
    <div class="box-item box8">8</div>
  </div>
</main>

 

main.css

main {
  background: #f2f4f7;
}
.box-container {
  width: 1080px;
  margin: auto;
  display: grid;
  grid-template-columns: repeat(3, 1fr); /* 균일한 크기로 3등분 */
  grid-template-rows: repeat(24, 40px); /* 40px로 24등분 -> <main> 영역의 전체 height가 계산된다면 height 지정 후 1fr로 사용하셔도 좋습니다.*/
  gap: 10px;
}
.box-item {
  background: skyblue;
  text-align: center;
  font-size: 30px;
  border: 1px solid #dee3eb;
}
.box1 {
  grid-column: 1 / 3;
  grid-row: 1 / 3;
}
.box2 {
  grid-column: 3 / 4;
  grid-row: 1 / 3;
}
.box3-1 {
  grid-column: 1 / 3;
  grid-row: 3 / 4;
}

.box3-2 {
  grid-column: 1 / 3;
  grid-row: 4 / 7;
}
.box4-1 {
  grid-column: 3 / 4;
  grid-row: 3 / 5;
}
.box4-2 {
  grid-column: 3 / 4;
  grid-row: 5 / 7;
}
.box5 {
  grid-column: 1 / 3;
  grid-row: 7 / 23;
}
.box6 {
  grid-column: 3 / 4;
  grid-row: 7 / 23;
}
.box7 {
  grid-column: 1 / 3;
  grid-row: 23 / 25;
}
.box8 {
  grid-column: 3 / 4;
  grid-row: 23 / 25;
}

 

cell 할당 완료

 

두 번째 방법처럼 cell로 나눈 후 구역에 할당하는 경우에는 cell의 할당에 따라 레이아웃이 자유롭게 변형될 수 있기 때문에 확장 및 수정이 용이하고, 반응형에 강합니다.

 

수고하셨습니다!

 

전체 코드를 첨부하고 마치겠습니다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>레이아웃 잡기</title>
    <link rel="stylesheet" type="text/css" href="/css/header.css">
    <link rel="stylesheet" type="text/css" href="/css/main.css">
    <link rel="stylesheet" type="text/css" href="/css/footer.css">
    <link rel="stylesheet" type="text/css" href="/css/global.css">
  </head>
  <body>
    <header>
      <div class="links">
        <a href="/" class="link_text">네이버를 시작페이지로</a>
        <a href="/" class="link_text">쥬니어네이버</a>
        <a href="/" class="link_text">해피빈</a>
      </div>
      <a href="/"><img src="images/naver_logo.png" class="img_logo"/></a>
      <form>
        <!-- 웹접근성 향상을 위해 fieldset과 legend를 사용해주는 것이 좋습니다. 
              두 요소의 기본 디자인을 숨기는 방법은 CSS(.visually-hidden)를 참고해주세요-->
        <fieldset>
          <legend class="visually-hidden">검색</legend>
          <div class="search_box">
            <input type="text" maxlength="225" tabindex="1" />
            <button type="submit" tabindex="2">
              검색
            </button>
          </div>
        </fieldset>
      </form>
      <nav>
        <div class="nav_items">
          <ul>
            <li><a href="/">메일</a></li>
            <li><a href="/">카페</a></li>
            <li><a href="/">블로그</a></li>
            <li><a href="/">지식iN</a></li>
            <li><a href="/">쇼핑</a></li>
            <li><a href="/">Pay</a></li>
            <li><a href="/">TV</a></li>
            <li><a href="/">사전</a></li>
            <li><a href="/">뉴스</a></li>
            <li><a href="/">증권</a></li>
            <li><a href="/">부동산</a></li>
            <li><a href="/">지도</a></li>
            <li><a href="/">영화</a></li>
            <li><a href="/">뮤직</a></li>
            <li><a href="/">책</a></li>
            <li><a href="/">웹툰</a></li>
            <li><a href="/">더보기</a></li>
          </ul>
          <div class="keyword">
            <span class="color_naver">1</span>
            <span>Eoldam spark</span></span>
          </div>
        </div>
      </nav>
    </header>
    <main>
      <div class="box-container">
        <div class="box-item box1">1</div>
        <div class="box-item box2">2</div>
        <div class="box-item box3-1">3-1</div>
        <div class="box-item box3-2">3-2</div>  
        <div class="box-item box4-1">4-1</div>
        <div class="box-item box4-2">4-2</div>
        <div class="box-item box5">5</div>
        <div class="box-item box6">6</div>
        <div class="box-item box7">7</div>
        <div class="box-item box8">8</div>
      </div>
    </main>
    <footer>
      <div class="notice_box">
        <a href="/">공지사항</a>
        <a href="/">서비스 전체보기></a>
      </div>
      <div class="aside_box">
        <div class="area_user">
          <div class="area_user_row">
            <span class="text_bold-13">Creators</span>
            <ul>
              <li><a href="/">크리에이터</a></li>
              <li><a href="/">스몰비즈니스</a></li>
            </ul>
          </div>
          <div class="area_user_row">
            <span class="text_bold-13">Partners</span>
            <ul>
              <li><a href="/">비즈니스 광고</a></li>
              <li><a href="/">스토어 개설</a></li>
              <li><a href="/">지역업체 등록</a></li>
            </ul>
          </div>
          <div class="area_user_row">
            <span class="text_bold-13">Developers</span>
            <ul>
              <li><a href="/">네이버 개발자센터</a></li>
              <li><a href="/">오픈API</a></li>
              <li><a href="/">오픈소스</a></li>
              <li><a href="/">네이버 D2</a></li>
              <li><a href="/">네이버 D2SF</a></li>
              <li><a href="/">네이버 랩스</a></li>
            </ul>
          </div>
        </div>
        <div class="area_col">
          <div class="ac_content">
            <div class="text_bold-13">웨일 브라우저</div>
            <div class="ac_link"><a href="/">다운받기</a></div>
          </div>
          <a href="/"><img src="images/icon_whale.png" class="ac_img"/></a>
        </div>
        <div class="area_col">
          <div class="ac_content">
            <div class="text_bold-13">프로젝트 꽃</div>
            <div class="ac_link"><a href="/">바로가기</a></div>
          </div>
          <a href="/"><img src="images/icon_flower.png" class="ac_img"/></a>
        </div>
      </div>
      <div class="bottom_box">
        <ul>
          <li><a href="/">회사소개</a></li>
          <li><a href="/">인재채용</a></li>
          <li><a href="/">제휴제안</a></li>
          <li><a href="/">이용약관</a></li>
          <li><a href="/">개인정보처리방침</a></li>
          <li><a href="/">청소년보호정책</a></li>
          <li><a href="/">네이버 정책</a></li>
          <li><a href="/">고객센터</a></li>
          <li><a href="/">&copy; NAVER Corp.</a></li>
        </ul>
      </div>
    </footer>
  </body>
</html>

 

header.css

header {
  margin: auto; /* header의 양쪽 여백(margin)을 동등하게 맞춤 -> 수평가운데정렬 */
  width: 1080px;
  height: 215px;
  display: flex;
  align-items: center; /* 하위 요소들 수직 가운데정렬 */
  position: relative;
}
fieldset {
  border: none; /* 기본 border 없애기(이 코드를 지우고 기본 border를 확인해보세요) */
}
.visually-hidden {
  position: absolute !important;
  height: 1px;
  width: 1px;
  overflow: hidden;
  clip: rect(1px 1px 1px 1px);
  clip: rect(1px, 1px, 1px, 1px);
  white-space: nowrap;
}
.links {
  /* 링크들을 상단 우측에 위치시킵니다. */
  position: absolute;
  top: 0;
  right: 0;
}
.links .link_text {
  font-size: 12px;
  margin-left: 5px;
}
.img_logo {
  margin-bottom: 12px;
  width: 220px;
  height: 65px;
}
.search_box {
  width: 520px;
  height: 50px;
  border: 2px solid #03cf5d;
  display: flex;
  align-items: center;
}
.search_box input {
  flex: 9; /* search-box내부에서 9만큼의 크기를 차지(비율) */
  height: 46px;
  padding-left: 12px;
  padding-right: 12px;
  border: none;
  outline: none;
  font-size: 18px;
}
.search_box button {
  flex: 1; /* search-box내부에서 1만큼의 크기를 차지(비율) */
  height: 46px;
  margin: 0;
  padding: 0;
  border: none;
  outline: none;
  background: #03cf5d;
  color: #ffffff;
}
/* nav */
header > nav {
  width: 100%;
  height: 45px;
  position: absolute;
  bottom: 0;
}
.nav_items {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 15px;
  font-weight: bold;
  border-top: 1px solid #f1f3f6;
}
.keyword {
  width: 200px;
}
.nav_items ul > li {
  display: inline-block;
  margin-left: 8px;
}
.nav_items ul > li:nth-child(-n + 7) > a {
  /* <ul>하위 7번째 <li>까지 각각 내부의 <a> 태그 접근 */
  color: #03cf5d;
}
.nav_items ul > li > a {
  text-decoration: none;
  cursor: pointer;
}

 

main.css

main {
  background: #f2f4f7;
  min-height: 700px;
}
.box-container {
  width: 1080px;
  margin: auto;
  display: grid;
  grid-template-columns: repeat(3, 1fr); /* 균일한 크기로 3등분 */
  grid-template-rows: repeat(24, 40px); /* 40px로 24등분 -> <main> 영역의 전체 height가 계산된다면 height 지정 후 1fr로 사용하셔도 좋습니다.*/
  gap: 10px;
}
.box-item {
  background: skyblue;
  text-align: center;
  font-size: 30px;
  border: 1px solid #dee3eb;
}
.box1 {
  grid-column: 1 / 3;
  grid-row: 1 / 3;
}
.box2 {
  grid-column: 3 / 4;
  grid-row: 1 / 3;
}
.box3-1 {
  grid-column: 1 / 3;
  grid-row: 3 / 4;
}

.box3-2 {
  grid-column: 1 / 3;
  grid-row: 4 / 7;
}
.box4-1 {
  grid-column: 3 / 4;
  grid-row: 3 / 5;
}
.box4-2 {
  grid-column: 3 / 4;
  grid-row: 5 / 7;
}
.box5 {
  grid-column: 1 / 3;
  grid-row: 7 / 23;
}
.box6 {
  grid-column: 3 / 4;
  grid-row: 7 / 23;
}
.box7 {
  grid-column: 1 / 3;
  grid-row: 23 / 25;
}
.box8 {
  grid-column: 3 / 4;
  grid-row: 23 / 25;
}

 

footer.css

footer {
  width: 1080px;
  height: 310px;
  margin: auto;
  padding: 0 8px 0 8px; /* 각각 위 오른쪽 아래 왼쪽 */
  display: flex;
  flex-direction: column; /* 요소들을 수평정렬 */
  font-size: 12px;
}
.notice_box {
  flex: 1;
  display: flex;
  justify-content: space-between; /* 양끝 정렬 */
  align-items: center;
  border-bottom: 1px solid #f1f3f6;
}
.notice_box a {
  font-weight: bold;
  color: black;
}
.aside_box {
  flex: 2;
  display: flex;
  align-items: center;
  border-bottom: 1px solid #f1f3f6;
}
.area_user {
  flex: 4;
  line-height: 2em; /* 줄간격 */
}
.area_user_row {
  display: flex;
}
.area_user_row span {
  flex: 1;
}
.area_user_row ul {
  flex: 6;
}
.aur_title {
  font-size: 13px;
  font-weight: bold;
}
.area_user_row ul > li {
  display: inline-block; /* li 수평정렬하는 방법 */
  margin-left: 8px;
}
.area_col {
  flex: 1;
  display: flex;
}
.area_col .ac_content {
  line-height: 20px;
}
.area_col .ac_img {
  width: 60px;
  height: 60px;
}
.bottom_box {
  flex: 3;
  padding-top: 20px;
  font-size: 14px;
}
.bottom_box ul > li {
  display: inline-block; /* 수평정렬 */
  margin-left: 8px;
}
.bottom_box ul > li:last-child {
  /* 마지막 li요소 (Naver Corp.) 굵게 */
  font-weight: bold;
}

 

global.css

* {
  box-sizing: border-box;
}
body {
  margin: 0;
  font-family: sans-serif;
}
a {
  text-decoration: none;
  color: #888;
}
a:hover {
  text-decoration: underline;
}
ul {
  margin: 0;
  padding: 0;
}
/* 재사용 클래스 */
.color_naver {
  color: #03cf5d;
}
.text_bold-13 {
  font-weight: bold;
  font-size: 13px;
}

MDN document - grid layout

 

CSS grid layout - CSS: Cascading Style Sheets | MDN

The CSS grid layout module excels at dividing a page into major regions or defining the relationship in terms of size, position, and layer, between parts of a control built from HTML primitives.

developer.mozilla.org

 



        
답변을 생성하고 있어요.