쿠키런 소식 페이지 만들기 - [1] 화면 만들기
프론트엔드 기본기를 함께 익혀봐요 🚀
프론트엔드의 코어 기본기는 HTML, CSS, JavaScript 이렇게 세 가지가 있습니다. 기본의 중요성은 백날 말해도 모자라지 않은데요. 그런데 이들과 함께 중요한 것들이 더 있습니다. 그중에서도 개발 도구를 다루는 것이 있습니다. 요즘은 리액트와 같은 라이브러리를 사용하는 방법도 알아야 하지만, 웹팩 또는 바벨과 같은 도구를 설정하고 적용하는 것 역시 알아야 합니다. 그래서 지금까지 공부한 기본기들을 이용해 시맨틱 한 쿠키런 소식 페이지를 만들고, 많이 사용되는 도구들을 하나씩 적용해보려 합니다.
저도 아직은 개발 도구를 다루는 것이 미숙하지만, 이번 기회에 같이 만들면서 연습해봐요!
예제에 사용된 코드와 이미지는 GitHub 저장소에서 확인 가능합니다 ❤️
프로젝트 계획
쿠키런 소식을 전하는 쿠키 뉴스는 구현할 내용이 많지 않습니다.
- 사이트에 접속하면 로딩이 시작되며, 스피너가 움직인다.
- 로딩 중에 쿠키런 소식이 담긴 json 파일을 조회한다.
- 조회를 마치면 로딩을 마치고, 화면에 순차적으로 소식을 출력한다.
그리고 프로젝트 구조는 다음과 같이 구성해서 쭉쭉 진행할 생각입니다 😆
- cookie-news: 시작 페이지와 여러 개발 설정이 위치하는 루트 디렉토리
- asset: CSS, 이미지, 스크립트 파일이 위치하는 디렉토리
- data: 조회할 데이터(news.json) 파일이 위치하는 디렉토리
.prettierrc는 VS Code의 확장 프로그램인 Prettier의 설정 파일이니 무시하셔도 좋습니다.
Markup Design
HTML 마크업은 최대한 시맨틱 태그를 이용했고, 클래스 이름 작명에는 BEM 방법론을 적용했습니다. 그리고 이번 예제는 별도의 스피너 이미지와 json 파일을 준비해 사용했기 때문에, 본문 예제와 동일하게 진행하고 싶으신 분들은 꼭 GitHub 저장소에서 자료를 받아 주세요. (별도의 설명이 필요하지 않은 CSS도 본문에는 첨부하지 않았습니다!)
자 그럼 우리가 만들 페이지를 먼저 확인하고, 디자인을 진행해 봅시다.
컨테이너 (Container)
컨테이너 또는 래퍼는 웹사이트의 구조를 잡기 위해 사용하는 요소입니다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="쿠키런에 관한 소식을 빠르게 알려드립니다." />
<title>쿠키런 소식 페이지</title>
<!-- Styles -->
<link rel="stylesheet" href="asset/css/style.css" />
</head>
<body>
<div id="dev-sisters">
<!-- Header -->
<!-- Main -->
<!-- Footer -->
</div>
<!-- Scripts -->
<script type="module" src="asset/js/main.js"></script>
</body>
</html>
예제에서는 <div id="dev-sisters">가 전체 구조에 대한 컨테이너가 되는데, 구조를 잡는 것 외에도 다른 태그를 포함하고 있다는 의미 자체로도 컨테이너라 부를 수 있습니다. 그리고 맨 아래 스크립트를 불러오는 부분에서 type="module" 속성을 사용했는데, 이는 스크립트를 ES6 모듈 단위로 불러올 수 있게 해 줍니다.
헤더 (Header)
<header>는 사이트를 설명하는 부분이며, 사용자들은 이를 보고 어떤 사이트인지 알 수 있어야 합니다.
<!-- Header -->
<header class="header">
<img class="header__logo" src="..." alt="쿠키런 로고" />
<h1 class="header__title">Cookie News</h1>
<p class="header__description">세상에서 제일 빠른 쿠키런 소식</p>
</header>
<img> 요소는 접근성을 위해 alt 속성을 필수로 작성해야 합니다. 네트워크 문제로 사진을 올바르게 불러오지 못한 경우, 해당 속성에 적힌 값이 대체 문자열로 출력됩니다. 웹사이트를 이용하는 사용자들에게 정보를 제공할 때, 차별이 없도록 접근성을 확보하는 것은 정말 중요합니다.
예제의 이미지 요소들에 사용된 경로가 너무 길어 본문 코드에서는 ...으로 대체합니다 😅
메인 (Main)
<main>은 페이지마다 하나만 존재해야 하며, 사이트의 주요 콘텐츠를 담고 있습니다.
<!-- Main -->
<main class="content">
<section class="news-section">
<h2 class="news-section__title">Weekly News ❤️</h2>
<article class="news-list">
<!-- 로딩 스피너
<div class="spinner">
<img class="spinner__img" src="asset/img/spinner.gif" alt="로딩 스피너" />
</div> -->
<!-- 소식 정보
<article class="news">
<a class="news__link" href="#">
<img class="news__thumb" src="https://via.placeholder.com/100" alt="뉴스 썸네일" />
<div class="news__info">
<h3 class="news__title">소식 제목</h3>
<p class="news__summary">소식 요약</p>
</div>
</a>
</article> -->
</article>
</section>
<aside class="partner">
<h3 class="partner__title">Partnership 🤝</h3>
<ul class="partner__list">
<li class="partner__item">
<a class="partner__link" href="#">
<img class="partner__thumb" src="..." alt="파트너 썸네일" />
<h4 class="partner__name">공식 페이지</h4>
</a>
</li>
<li class="partner__item">
<a class="partner__link" href="#">
<img class="partner__thumb" src="..." alt="파트너 썸네일" />
<h4 class="partner__name">데브시스터즈</h4>
</a>
</li>
<li class="partner__item">
<a class="partner__link" href="#">
<img class="partner__thumb" src="..." alt="파트너 썸네일" />
<h4 class="partner__name">네이버 카페</h4>
</a>
</li>
<li class="partner__item">
<a class="partner__link" href="#">
<img class="partner__thumb" src="..." alt="파트너 썸네일" />
<h4 class="partner__name">나무위키</h4>
</a>
</li>
</ul>
</aside>
</main>
<section>은 단순히 구조를 분할할 때 사용하며, 디자인이 많이 들어간다면 이 때는 <div>를 사용해 구분해야 합니다. 그리고 각 섹션 안에는 쿠키런 소식들이 들어갈 건데, 각 소식은 다른 곳에서도 독립적으로 재사용 가능하므로 <article>로 만들 수 있습니다.
위 코드에서 article의 내부를 보면 주석 처리된 두 개의 요소(div#spinner, article#news)가 있는데, 이들은 이후 자바스크립트로 추가할 부분들입니다. 사이트를 접속하면 최초에는 로딩 스피너를 보여주면서 로딩 중임을 알려야 하고, 데이터 조회가 끝나면 스피너를 제거하면서 불러온 데이터를 화면에 출력해야 합니다. 내부 내용을 어떻게 만들지 미리 작성해 두면 스타일을 미리 준비할 수 있어 좋습니다.
마지막으로 <aside>는 본문과 간접적으로 연관이 있거나 광고가 들어갈 수 있는 영역입니다.
시맨틱 태그로 구조를 분할한 이후에는 해당 영역들을 h1~h6 태그로 설명해야 합니다.
푸터 (Footer)
<footer>는 저작권이나 연락처 등의 정보를 담고 있으며 사이트 최하단에 위치합니다.
<!-- Footer -->
<footer class="footer">
<div class="footer__services">
<a class="footer__service" href="#">이용약관</a>
<a class="footer__service footer__service--bold" href="#">개인정보처리방침</a>
<a class="footer__service" href="#">고객센터</a>
</div>
<div class="footer__address">
<span>서울특별시 강남구 도산대로 327</span>
</div>
<div class="footer__phone">
<span>전화: 02-2148-0750</span>
<span>팩스: 02-2148-0629</span>
</div>
<div class="footer__copyright">
<span>© 2022 Devsisters Corp. All Rights Reserved.</span>
</div>
<div class="footer__logo">
<svg viewBox="0 0 448 58" style="width: 7.72414em" fill="#FFF" stroke="#FFF" class="css-16686xk">
<path d="..."></path>
<path d="..."></path>
</svg>
</div>
</footer>
SVG는 Scalable Vector Graphics의 약자로 벡터 기반 그래픽을 XML 형식으로 정의하는 것을 의미합니다. 이미지를 벡터 그래픽으로 만들면 해상도가 달라져도 그래픽이 깨지지 않기에 최근에는 많이 사용되고 있습니다. 본문에서는 SVG에 대해 별도로 소개하지 않으니, 궁금한 분들은 한 번 찾아보시기 바랍니다.
예제에 사용된 path 요소의 d 속성 값이 너무 길어 본문 코드에서는 ...으로 대체합니다 😅
Start Coding
기본 틀 만들기
사이트에 접속하면 소식 정보를 조회하기 위해 로딩을 진행합니다.
// main.js
function renderNews() {
const newsList = document.querySelector('.news-list');
}
document.addEventListener('DOMContentLoaded', renderNews);
로딩과 데이터 조회를 구현하기 위해 여기서는 DOM 트리가 완성되는 즉시 발생하는 DOMContentLoaded 이벤트에 리스너를 붙였습니다. 데이터를 조회할 때는 CSS나 이미지와 같은 리소스를 불러온 여부는 필요하지 않기 때문에 사용했는데, 만약 리소스를 모두 불러온 이후 작업을 처리해야 한다면 load 이벤트를 사용하면 됩니다.
로딩 모듈 만들기
로딩을 관리하는 함수는 loading.js 모듈에 따로 작성합니다.
// loading.js
export function createSpinner(parent) {
const spinner = document.createElement('div');
const spinnerImg = document.createElement('img');
spinner.className = 'spinner';
spinnerImg.className = 'spinner__img';
spinnerImg.src = 'asset/img/spinner.gif';
spinnerImg.alt = '로딩 스피너';
spinner.append(spinnerImg);
parent.append(spinner);
}
export function hideSpinner(parent) {
const spinner = parent.querySelector('.spinner');
spinner.style.display = 'none';
}
// main.js
import { createSpinner, hideSpinner } from './loading.js';
function renderNews() {
const newsList = document.querySelector('.news-list');
createSpinner(newsList);
}
document.addEventListener('DOMContentLoaded', renderNews);
작성된 로딩 함수들은 export로 내보내기 때문에 외부에서 모듈로 사용 가능하며, 이들을 사용하고자 하는 파일 안의 최상단에서 import 키워드를 사용해 참조하면 됩니다. 이제 이 함수들을 사용해 사용자가 사이트에 접속하면 로딩 스피너를 생성해서 로딩이 되고 있음을 보여주다가, 데이터 조회가 완료될 때 스피너를 제거하면 됩니다.
데이터 띄우기
화면에 보여줄 데이터는 fetch API를 통해 조회하면 됩니다.
function createArticle({ title, summary, thumb }) {
const article = document.createElement('article');
article.className = 'news';
article.innerHTML = `
<a class="news__link" href="#">
<img class="news__thumb" src="${thumb}" alt="뉴스 썸네일" />
<div class="news__info">
<h3 class="news__title">${title}</h3>
<p class="news__summary">${summary}</p>
</div>
</a>`;
return article;
}
function renderNews() {
const newsList = document.querySelector('.news-list');
createSpinner(newsList);
function renderNews() {
const newsList = document.querySelector('.news-list');
createSpinner(newsList);
setTimeout(() => {
fetch('./data/news.json')
.then((res) => res.json())
.then((data) => {
const { articles } = data;
const articleList = articles.map((article) => createArticle(article));
hideSpinner(newsList);
newsList.append(...articleList);
});
}, 2000);
}
}
데이터는 별도로 만들어 둔 news.json 파일에서 가져왔으며, 쿠키런 소식들은 티스토리 찌니님 블로그에서 가져왔습니다. fetch는 프로미스를 기반으로 만들어진 API이기에, 데이터를 조회를 마치면 조회 결과를 프로미스로 반환합니다. 그리고 첫 결괏값이 자바스크립트에서 사용하기 어려우므로 json() 메서드로 한 번 더 가공해야 합니다. 다만 이 메서드도 프로미스이기에 총 두 번의 then으로 확인해야 하는 점을 유의해야 합니다.
조회를 마친 후에는 받아온 데이터를 각각 createArticle 함수의 인자로 보내 article 요소로 만든 다음 리스트에 추가하면 됩니다.
fetch를 setTimeout으로 감싼 이유는 조회할 데이터가 적어 로딩 시간이 너무 짧기 때문입니다. 그래서 예제에서는 일부러 2초 동안은 로딩이 이어지면서 스피너가 보일 수 있도록 했습니다.
최종 결과
여기까지 해서 기본 화면 구성을 마쳤습니다.
다 만들고 나니 별 거 없는 프로젝트여서 힘이 좀 빠질 수도 있지만, 이제부터는 개발 도구를 하나씩 적용하면서 빌드업할 예정이라 재밌을(?) 거예요. 그럼 다음 글에서 찾아뵐게요!
Series
'🌈 기술스택 > Web Basic' 카테고리의 다른 글
쿠키런 소식 페이지 만들기 - [3] 바벨 적용하기 (0) | 2022.01.19 |
---|---|
쿠키런 소식 페이지 만들기 - [2] 웹팩 적용하기 (0) | 2022.01.19 |
웹 접근성과 표준의 중요성 (0) | 2021.10.22 |
Flex 대신 Grid를 사용해 레이아웃 만들기 (0) | 2021.10.21 |
BEM의 10가지 일반적인 문제와 이를 피하는 방법 (9) | 2021.10.18 |
댓글
이 글 공유하기
다른 글
-
쿠키런 소식 페이지 만들기 - [3] 바벨 적용하기
쿠키런 소식 페이지 만들기 - [3] 바벨 적용하기
2022.01.19 -
쿠키런 소식 페이지 만들기 - [2] 웹팩 적용하기
쿠키런 소식 페이지 만들기 - [2] 웹팩 적용하기
2022.01.19 -
웹 접근성과 표준의 중요성
웹 접근성과 표준의 중요성
2021.10.22 -
Flex 대신 Grid를 사용해 레이아웃 만들기
Flex 대신 Grid를 사용해 레이아웃 만들기
2021.10.21