네이버 UI 클론코딩 (2) - flex, grid 레이아웃
이전 글에서 완성한 header, footer에 이어 이 글에서는 main 영역을 만들어보겠습니다. main에서는 모든 요소를 세부적으로 카피하지는 않고 레이아웃을 구현하는 작업을 두 가지 방식으로 살펴보겠습니다.
- 큰 단위부터 작은 단위로
- grid cell로 나눠서 할당
1. 큰 단위부터 작은 단위로
가장 큰 요소부터 시작해서 하위 요소들을 점진적으로 나눠주는 방식입니다. body를 header, main, footer의 영역으로, main을 또다시 각 구역으로, 각 구역을 다시 세부적으로 계속 나눠줍니다.
우선 main영역을 크게 아래와 같이 나눠보겠습니다.
여기서는 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;
}
네이버 사이트를 자세히 보면 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;
}
완성되었습니다. 이렇게 큰 단위부터 하나씩 나눠서 구현하면 눈에 보이는 대로, 직관적으로 쉽게 설계할 수 있습니다.
2. grid cell
화면을 grid cell이라는 최소 단위의 균일한 블록으로 나눈 뒤, grid layout을 활용하여 각 구역에 cell들을 할당하는 방식입니다. 그림으로 살펴보겠습니다.
위와 같은 최종 레이아웃을 만들기 위해 main영역 전체를 X*Y의 균일한 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번호는 다음과 같습니다.
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의 할당에 따라 레이아웃이 자유롭게 변형될 수 있기 때문에 확장 및 수정이 용이하고, 반응형에 강합니다.
수고하셨습니다!
전체 코드를 첨부하고 마치겠습니다.
<!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="/">© 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;
}
'프론트엔드 HTML CSS JAVASCRIPT' 카테고리의 다른 글
[HTML, CSS] flexbox(display: flex) 총정리 (0) | 2023.12.28 |
---|---|
[HTML, CSS] 스크롤바 생성 overflow (auto, scroll, hidden) (2) | 2021.04.01 |
[HTML, CSS] box-sizing 속성 / 테두리도 크기에 포함시키기 (0) | 2020.03.22 |
[HTML, CSS] 기본적인 페이지 레이아웃(layout) 잡기 네이버 클론코딩 (1) (6) | 2020.03.21 |
[HTML, CSS] input창 클릭 시 CSS적용하는 방법(focus, animation (4) | 2019.12.29 |