네이버 UI 클론코딩 (1)
네이버 사이트를 그대로 카피하면서 레이아웃을 잡는 연습을 해보겠습니다. 웹개발 초기에는 이렇게 잘 만들어진 사이트를 클론코딩하는 게 실력향상에 큰 도움이 됩니다.
레이아웃 설계
간단한 웹사이트라도 항상 설계를 먼저 하고 나서 작업에 들어가시는 게 정신건강에 좋습니다. 설계 시 가장 먼저 할 일은 페이지를 가장 큰 단위로 나누는 일입니다. 여기에는 정해진 규칙은 없고, 사이트의 목적에 따라 다양한 형태가 존재하지만 일반적으로는 header, main, footer의 세 가지 영역으로 나뉩니다. HTML5 요소로는 각각 랜드마크 요소인 <header>, <main>, <footer>에 해당됩니다.
header | 웹페이지의 최상단부분. 주로 사이트의 이름, 검색창, 네비게이션 등의 내용이 포함됩니다. |
main | 본문 영역입니다. 일반적으로 body 내에서 1개만 존재합니다. header와 footer를 제외한 모든 내용의 부모 요소입니다. |
footer | 웹페이지의 최하단부분. 주로 상호명, 연락처, 개인정보처리방침 등의 내용이 포함됩니다. |
랜드마크 요소를 사용하지 않고 모든 영역을 div 태그로 만들어도 에러는 없습니다. 하지만 이는 웹 접근성과 SEO(Search Engine Optimization, 검색엔진 최적화)에 좋지 않습니다. HTML5 각 요소들의 의미(semantic meaning)를 최대한 살릴 수 있도록 노력해야 합니다. 그리고 항상 W3C의 가이드라인을 준수하며 페이지를 제작하는 습관을 들이는 것이 좋습니다.
https://www.w3schools.com/html/html5_semantic_elements.asp
https://co-natus.tistory.com/entry/Semantic-Tag
시작!
우선 네이버 홈페이지를 header, main, footer의 영역으로 나눠보겠습니다(실제 구조와는 무관한 주관적인 설계입니다). 아래 이미지는 화면을 최대한 축소하여 전체 웹사이트를 캡처한 이미지입니다.
하늘색의 main 영역을 중심으로 위, 아래로 각각 header와 footer가 위치해 있습니다. 복잡해 보이는 main의 설계와 작업은 다음글로 미루고, 이 글에서는 페이지를 header, main, footer로 나눈 뒤에 header와 footer만 세부적으로 만들어 보겠습니다.
코드 편집기를 열어서 작업에 들어갑니다.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>레이아웃 잡기</title>
</head>
<body>
<header>상단</header>
<main>메인</main>
<footer>하단</footer>
</body>
</html>
body 내부에 header, main, footer를 순서대로 출력합니다.
참고)
위에서 언급한 div만 사용하는 경우에도 웹접근성을 향상시킬 수 있는 방법이 있습니다. id와 role속성을 적절하게 부여해 주면 됩니다.
<div id="header" role="banner">상단</div>
<div id="main" role="main">메인</div>
<div id="footer" role="contentinfo">하단</div>
이런 방법이 있다는 점만 참고해 주세요. role속성의 자세한 사용은 이 글에서는 다루지 않겠습니다. HTML5 이후로는 role 속성대신 랜드마크 요소(header, main, footer, section, nav 등)를 적절히 사용하시는 게 좋습니다. 이 글에서도 랜드마크 요소를 사용하겠습니다.
실행화면입니다.
header와 footer의 height 속성(높이)을 설정하고, 배경색을 지정해서 눈으로 확인해 봅니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>레이아웃 잡기</title>
<style>
header {
background-color: lightgray;
height: 215px;
}
main {
background: #f2f4f7;
}
footer {
background-color: darkgray;
height: 310px;
}
</style>
</head>
<body>
<header>상단</header>
<main>메인</main>
<footer>하단</footer>
</body>
</html>
header와 footer는 보통 고정 높이를 사용하지만, main은 사용목적에 따라 높이를 지정할 수도, 하지 않을 수도 있습니다.
height를 지정하면
main 영역의 높이가 고정됩니다. 하위에 포함되는 요소가 main의 높이를 초과했을 때에는 overflow 속성으로 스크롤을 생성할 수 있습니다.
height를 지정하지 않으면
main 영역의 하위 요소들의 크기에 따라 height가 유연하게 결정됩니다. 위의 코드에서는 하위 요소가 없고 '메인'이라는 텍스트뿐이므로 main 영역이 해당 텍스트의 높이만큼만 공간을 차지하였습니다.
height 속성 사용 여부에 따라 레이아웃이 크게 달라지므로 상황에 맞는 적절한 방법을 사용하시는 게 좋습니다. 초기 레이아웃을 잡을 때 추천드리는 방법은 min-height 속성을 사용하는 방법입니다.
min-height
min-height를 지정하면 main 영역 내부에 하위 요소들이 작더라도 지정해 준 최소 길이를 유지합니다. 그리고 하위 요소들이 커지면서 그 높이가 min-height 값을 초과하면, 길이가 자동으로 늘어납니다.
min-height 속성을 활용하겠습니다.
main {
background: #f2f4f7;
min-height: 700px;
}
main의 하위 요소에 관계없이 최소 높이 700px로 출력된 모습입니다.
이렇게 3가지 영역을 잡았습니다. 앞서 말씀드렸듯이 main 영역은 배치할 하위요소들이 많기 때문에 다음 글에서 살펴보기로 하고, 이 글에서는 header와 footer를 네이버 사이트와 똑같이 만들어보겠습니다.
아래부터는 코드는 조금 복잡할 수 있습니다. 세부적인 css 사용에 관한 내용은 이 글의 목적이 아니니 주석으로 간단히 처리하고 넘어가겠습니다.
header
요소들을 배치할 때에는 여러 가지 방법이 있습니다.
- float
- position
- flex layout
- grid layout
아래로 갈수록 현대적인 방법입니다. 저는 개인적으로 간단한 레이아웃은 flex, 복잡한 레이아웃은 grid를 사용하고 position 속성은 필요할 때만 부분적으로 사용합니다. 어느 한 가지 기술만 반드시 필요한 경우는 없습니다. 취향에 따라 어느 하나만 잘 다루어도 좋고, 상황에 맞게 조화롭게 사용하셔도 좋습니다.
여기서는 flex 박스를 활용합니다.
index.html - header 부분
<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 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>
header css
* {
box-sizing: border-box; /* 길이 계산을 편하게 하기위함. box-sizing에 관한 설명은 아래 링크를 참고해주세요 */
}
body {
margin: 0; /* body의 기본마진을 없애줍니다(선택사항) */
font-family: sans-serif;
}
a {
text-decoration: none; /* 기본 밑줄을 제거합니다 */
color: #888;
}
a:hover {
text-decoration: underline; /* 마우스 커서가 올라갔을 때 밑줄을 생성합니다*/
}
header {
margin: auto; /* header의 양쪽 여백(margin)을 동등하게 맞춤 -> 수평가운데정렬 */
width: 1080px;
height: 215px;
display: flex;
align-items: center; /* 하위 요소들 수직 가운데정렬 */
position: relative;
}
fieldset {
border: none; /* 기본 border 없애기(이 코드를 지우고 기본 border를 확인해보세요) */
}
.visually-hidden {
/* legend 안보이게 설정. 이렇게하면 접근성을 준수하면서 디자인을 해치지 않습니다. */
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px, 1px, 1px, 1px);
white-space: nowrap;
}
.links {
/* 링크들을 상단 우측에 위치시킵니다. */
position: absolute;
top: 0;
right: 0;
}
.link_text {
font-size: 10px;
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;
}
.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 {
background: #f2f4f7;
min-height: 700px;
}
footer {
background: darkgray;
height: 310px;
}
/* 재사용 클래스 */
.color_naver {
color: #03cf5d;
}
최상단 box-sizing을 설정한 이유가 궁금하시면 아래글을 참고해 주세요
2020.03.22 - [HTML, CSS] box-sizing 속성 / 테두리도 크기에 포함시키기
footer
<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>
footer css
ul {
/* li의 깔끔한 정렬을 위해 기본마진, 패딩 제거 */
margin: 0;
padding: 0;
}
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;
}
/* 재사용 클래스 */
.color_naver {
color: #03cf5d;
}
.text_bold-13 {
font-weight: bold;
font-size: 13px;
}
내부 구조는 네이버 사이트를 대부분 카피했습니다.
코드가 길어졌으니 아래 이미지와 같이 css파일들을 따로 분리시키고 마무리하겠습니다. 코드 분리 후에 index.html에서 <link> 태그로 해당 css 파일을 불러오시면 됩니다.
수고하셨습니다! 아래에 전체코드를 첨부하고 마치겠습니다.
다음글
2020.03.28 - [HTML, CSS] 기본적인 페이지 레이아웃(layout) 잡기 네이버 클론코딩 (2) - flex, grid 레이아웃
index.html
<!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>
메인
</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>
global.css
body {
margin: 0;
font-family: sans-serif;
}
a {
text-decoration: none;
color: #888;
}
a:hover {
text-decoration: underline;
}
ul {
margin: 0;
padding: 0;
}
* {
box-sizing: border-box; /* 길이 계산을 편하게 하기위함. box-sizing에 관한 설명은 아래 링크를 참고해주세요 */
}
/* 재사용 클래스 */
.color_naver {
color: #03cf5d;
}
.text_bold-13 {
font-weight: bold;
font-size: 13px;
}
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;
}
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;
}
'프론트엔드 HTML CSS JAVASCRIPT' 카테고리의 다른 글
[HTML, CSS] 기본적인 페이지 레이아웃(layout) 잡기 네이버 클론코딩 (2) - flex, grid 레이아웃 (2) | 2020.03.28 |
---|---|
[HTML, CSS] box-sizing 속성 / 테두리도 크기에 포함시키기 (0) | 2020.03.22 |
[HTML, CSS] input창 클릭 시 CSS적용하는 방법(focus, animation (4) | 2019.12.29 |
[HTML, JAVASCRIPT] 웹 게임 만들기 포트리스 (2) - 미사일 (0) | 2019.10.29 |
[HTML, JAVASCRIPT] 웹 게임 만들기 포트리스 (1) - 탱크, 표적 (0) | 2019.10.28 |