프로젝트 구조
food-recipe-app ___ index.html
|___ style.css
|___ app.js
프로젝트 구조는 간단하다. food-recipe-app 이라는 루트폴더 아래 HTML, CSS, JAVASCRIPT 파일 3개가 있다.
웹페이지 레이아웃 설계
프로토타이핑을 참고하여 웹페이지 레이아웃을 간단하게 설계하였다. 네모 박스는 모두 div 요소(element)를 가리킨다.
우선 헤딩(heading)과 검색창이 들어가는 상위 div 요소와 사진 리스트가 들어가는 하위 div 요소로 분리하였다. 그 다음은 상위 div 안에 헤딩과 검색창을 화면 중앙에 정렬하기 위한 div 요소가 들어간다. 그리고 중앙에 정렬된 div 안에 헤딩을 담기 위한 div 요소와 검색창을 담기 위한 div 요소를 상하로 배치하였다.
하위 div 요소에는 각각의 사진과 사진 설명을 담기 위한 아이템(item) div 가 존재한다. 아이템 div 안에는 사진을 담는 div 요소와 사진 설명을 담는 div 요소를 상하로 배치하였다.
HTML 뼈대구조 생성과 글로벌 스타일 적용
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>사진 갤러리 앱</title>
<link rel="stylesheet" href="style.css" />
</head>
<body></body>
</html>
HTML 뼈대 구조를 생성하고 애플리케이션 이름에 해당하는 타이틀을 설정하였다. 또한, 스타일을 적용하기 위한 style.css 파일은 link 태그로 불러와서 사용하도록 한다.
body {
margin: 0;
padding: 0;
}
브라우저에는 기본적인 margin 과 padding 이 존재하기 때문에 정확한 스타일링을 위하여 margin 과 padding 을 전부 0 으로 설정하였다.
<div id="header">헤더</div>
<div id="photo-list">사진 리스트</div>
body 요소 안에 헤딩과 검색창이 들어가는 상위 div 요소와 사진 리스트가 들어가는 하위 div 로 분리하였다. 스타일링을 위하여 id 속성을 추가하였다. 상위 div 요소는 헤딩이 들어가므로 header 라고 id 이름을 설정하였고, 하위 div 요소는 사진 리스트가 들어가므로 photo-list 라고 이름을 설정하였다. id 나 class 이름에는 하이푼(-)을 추가할 수 있다.
#header {
width: 100%;
height: 200px;
margin-top: 100px;
margin-bottom: 100px;
background: rgb(224, 224, 224);
}
#photo-list {
width: 100%;
background: rgb(224, 224, 224);
}
header 위아래로 100px 정도의 공백을 적용하였다. 사진 리스트의 height 은 내부 컨텐츠에 따라 자동으로 늘어날 수 있도록 설정하지 않았다.
<div id="header">
<div id="center">센터</div>
</div>
header 요소 내부에 헤딩과 검색창을 화면 중앙에 정렬하기 위한 div 요소를 추가하였다.
#center {
width: 600px;
height: 100%;
margin: 0 auto;
background: rgb(158, 158, 158);
}
width 를 퍼센트(%)로 설정하지 않은 이유는 퍼센트로 설정했을때 브라우저 화면이 줄어들면 헤딩과 검색창이 너무 적은 공간을 차지하기 때문이다. height 을 100%로 적용한 이유는 부모 요소인 header 의 높이가 변경되더라도 center 요소의 높이도 동일하게 변경되도록 하기 위함이다.
<div id="center">
<div id="heading">헤딩</div>
<div id="search">검색창</div>
</div>
#heading {
width: 100%;
height: 70%;
border: 1px solid red;
background: rgb(224, 224, 224);
}
#search {
width: 100%;
height: 30%;
border: 1px solid blue;
background: rgb(224, 224, 224);
}
heading 과 search 의 width 를 모두 100% 로 설정한 이유는 center 의 width 값이 변경되더라도 항상 너비가 center 내부에 딱 맞도록 하기 위함이다. heading 과 search 의 height 을 모두 퍼센트로 지정한 이유는 header 요소의 높이가 변경되더라도 heading 과 search 요소가 변경된 header 높이에 딱 맞도록 하기 위함이다.
<div id="heading">
<h1>My photo gallery</h1>
<h4>my old memories from my life</h4>
</div>
#heading {
width: 100%;
height: 70%;
text-align: center;
letter-spacing: 2px;
border: 1px solid red;
background: rgb(224, 224, 224);
}
헤딩 h1, h4 를 추가하고 heading div 요소에 텍스트 중앙정렬을 위하여 text-align 을 center 로 지정하였다.
<div id="search">
<input type="text" placeholder="Search photo ... " />
</div>
search 요소 하위에 input 요소를 추가하였다.
#search {
width: 100%;
height: 30%;
text-align: center;
}
search 요소 하위의 input 요소를 중앙에 정렬하기 위하여 text-align 을 center 로 설정하였다.
#search input {
all: unset;
width: 400px;
height: 50px;
border-radius: 30px;
padding-left: 20px;
text-align: left;
border: 2px solid rgb(224, 224, 224);
color: #ff7f00;
}
#search input::placeholder {
color: #ff7f00;
font-size: 15px;
}
의사요소를 사용하여 input 요소의 placeholder 를 스타일링하였다. 그리고 레이아웃을 위하여 설정한 border 와 background 설정을 모두 제거하였다.
#photo-list {
width: 940px;
background: rgb(224, 224, 224);
margin: 0 auto;
overflow: hidden;
}
모든 사진을 감싸고 있는 photo-list 요소를 중앙에 배치하기 위하여 width 값을 940px 로 수정하고, margin 값을 설정하였다. overflow 값을 설정해야 모든 사진을 감싸게 된다.
<div id="photo-list">
<div class="photo-container">사진</div>
<div class="photo-container">사진</div>
<div class="photo-container">사진</div>
<div class="photo-container">사진</div>
<div class="photo-container">사진</div>
<div class="photo-container">사진</div>
<div class="photo-container">사진</div>
<div class="photo-container">사진</div>
<div class="photo-container">사진</div>
</div>
사진 리스트의 아이템 9개를 생성하였다. 각각의 아이템에 동일한 스타일을 적용하기 위하여 class 이름을 설정하였다.
.photo-container {
width: 300px;
height: 400px;
float: left;
margin-bottom: 20px;
background: rgb(158, 158, 158);
}
사진 아이템들을 감싸고 있는 전체 너비가 940px 이므로 한 행에 3개씩의 사진이 들어가려면 각 아이템 너비를 300px 로 설정하고 나머지 40px 은 중앙 열에 있는 모든 div 요소 양쪽에 margin 을 20px 씩 준다. 모든 아이템에 아래쪽 마진을 20px 씩 준다. float 속성을 설정하여 아이템을 가로로 나열한다.
.photo-container:nth-child(3n + 2) {
margin-left: 20px;
margin-right: 20px;
background: skyblue;
}
중앙열에 있는 div 요소는 2번째, 5번째, 8번째이므로 3n+2 로 선택할 수 있다. 양쪽 여백을 20px 씩 설정한다.
<div id="photo-list">
<div class="photo-container">
<div class="photo-card">사진</div>
<div class="photo-name">이름</div>
</div>
<div class="photo-container">
<div class="photo-card">사진</div>
<div class="photo-name">이름</div>
</div>
<div class="photo-container">
<div class="photo-card">사진</div>
<div class="photo-name">이름</div>
</div>
<div class="photo-container">
<div class="photo-card">사진</div>
<div class="photo-name">이름</div>
</div>
<div class="photo-container">
<div class="photo-card">사진</div>
<div class="photo-name">이름</div>
</div>
<div class="photo-container">
<div class="photo-card">사진</div>
<div class="photo-name">이름</div>
</div>
<div class="photo-container">
<div class="photo-card">사진</div>
<div class="photo-name">이름</div>
</div>
<div class="photo-container">
<div class="photo-card">사진</div>
<div class="photo-name">이름</div>
</div>
<div class="photo-container">
<div class="photo-card">사진</div>
<div class="photo-name">이름</div>
</div>
</div>
photo-container 요소 안에 photo-card 요소와 photo-name 요소를 추가한다. 각각은 공통적인 스타일링을 위하여 class 이름을 설정하였다.
.photo-card {
height: 300px;
}
.photo-name {
height: 100px;
background: tomato;
}
photo-container 높이가 400px 이므로 그 안에 들어가는 photo-card 와 photo-name 은 각각 300px 과 100px 로 높이를 설정하였다.
.photo-name {
height: 100px;
background: tomato;
text-align: center;
line-height: 100px;
}
사진 이름을 정중앙에 정렬하였다.
<div id="photo-list">
<div class="photo-container">
<div class="photo-card">
<img src="" alt="">
</div>
<div class="photo-name">이름</div>
</div>
<div class="photo-container">
<div class="photo-card">
<img src="" alt="">
</div>
<div class="photo-name">이름</div>
</div>
<div class="photo-container">
<div class="photo-card">
<img src="" alt="">
</div>
<div class="photo-name">이름</div>
</div>
<div class="photo-container">
<div class="photo-card">
<img src="" alt="">
</div>
<div class="photo-name">이름</div>
</div>
<div class="photo-container">
<div class="photo-card">
<img src="" alt="">
</div>
<div class="photo-name">이름</div>
</div>
<div class="photo-container">
<div class="photo-card">
<img src="" alt="">
</div>
<div class="photo-name">이름</div>
</div>
<div class="photo-container">
<div class="photo-card">
<img src="" alt="">
</div>
<div class="photo-name">이름</div>
</div>
<div class="photo-container">
<div class="photo-card">
<img src="" alt="">
</div>
<div class="photo-name">이름</div>
</div>
<div class="photo-container">
<div class="photo-card">
<img src="" alt="">
</div>
<div class="photo-name">이름</div>
</div>
</div>
photo-card 내부에 img 요소를 추가한다. 이미지 경로를 설정하여 이미지를 불러온다.
.photo-container {
width: 300px;
height: 400px;
float: left;
margin-bottom: 20px;
border-radius: 15px;
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 5px 5px rgba(0, 0, 0, 0.23);
}
photo-container 에 border-radius 속성과 box-shadow 속성을 추가하였다.
.photo-card {
height: 300px;
border-radius: 15px 15px 0px 0px;
}
.photo-card img {
width: 100%;
height: 100%;
border-radius: 15px 15px 0px 0px;
}
photo-card 와 photo-card 하위의 img 요소에 상단 좌우측 모서리에만 border-radius 를 적용하였다.
.photo-container:hover {
transform: scale(1.01);
opacity: 0.7;
}
각 사진을 hover 하면 크기가 조금 커지고 투명도가 변하는 효과를 주었다.
전체 소스 코드는 아래와 같다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>사진 갤러리 앱</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div id="header">
<div id="center">
<div id="heading">
<h1>My photo gallery</h1>
<h4>my old memories from my life</h4>
</div>
<div id="search">
<input type="text" placeholder="Search photo ... " />
</div>
</div>
</div>
<div id="photo-list">
<div class="photo-container">
<div class="photo-card">
<img src="" alt="" />
</div>
<div class="photo-name">이름</div>
</div>
<div class="photo-container">
<div class="photo-card">
<img src="" alt="" />
</div>
<div class="photo-name">이름</div>
</div>
<div class="photo-container">
<div class="photo-card">
<img src="" alt="" />
</div>
<div class="photo-name">이름</div>
</div>
<div class="photo-container">
<div class="photo-card">
<img src="" alt="" />
</div>
<div class="photo-name">이름</div>
</div>
<div class="photo-container">
<div class="photo-card">
<img src="" alt="" />
</div>
<div class="photo-name">이름</div>
</div>
<div class="photo-container">
<div class="photo-card">
<img src="" alt="" />
</div>
<div class="photo-name">이름</div>
</div>
<div class="photo-container">
<div class="photo-card">
<img src="" alt="" />
</div>
<div class="photo-name">이름</div>
</div>
<div class="photo-container">
<div class="photo-card">
<img src="" alt="" />
</div>
<div class="photo-name">이름</div>
</div>
<div class="photo-container">
<div class="photo-card">
<img src="" alt="" />
</div>
<div class="photo-name">이름</div>
</div>
</div>
</body>
</html>
body {
margin: 0;
padding: 0;
}
#header {
width: 100%;
height: 200px;
margin-top: 100px;
margin-bottom: 100px;
/* background: rgb(224, 224, 224); */
}
#photo-list {
width: 940px;
/* background: rgb(224, 224, 224); */
margin: 0 auto;
overflow: hidden;
}
#center {
width: 600px;
height: 100%;
margin: 0 auto;
/* background: rgb(158, 158, 158); */
}
#heading {
width: 100%;
height: 70%;
text-align: center;
letter-spacing: 2px;
/* border: 1px solid red; */
/* background: rgb(224, 224, 224); */
}
#search {
width: 100%;
height: 30%;
/* border: 1px solid blue; */
text-align: center;
/* background: rgb(224, 224, 224); */
}
#search input {
all: unset;
width: 400px;
height: 50px;
border-radius: 30px;
padding-left: 20px;
text-align: left;
border: 2px solid rgb(224, 224, 224);
color: #ff7f00;
}
#search input::placeholder {
color: #ff7f00;
font-size: 15px;
}
h1 {
font-size: 40px;
}
.photo-container {
width: 300px;
height: 400px;
float: left;
margin-bottom: 20px;
border-radius: 15px;
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 5px 5px rgba(0, 0, 0, 0.23);
}
.photo-container:hover {
transform: scale(1.01);
opacity: 0.7;
}
.photo-container:nth-child(3n + 2) {
margin-left: 20px;
margin-right: 20px;
}
.photo-card {
height: 300px;
border-radius: 15px 15px 0px 0px;
}
.photo-card img {
width: 100%;
height: 100%;
border-radius: 15px 15px 0px 0px;
}
.photo-name {
height: 100px;
text-align: center;
line-height: 100px;
}