뭐 CSS로 이걸 할 수 있다고?
사실 별건 아니지만, 기능을 구현할 때 무작정 자바스크립트로 작성하는 것이 당연하다고 생각했던 나는, 이번에 Next.js, Typescript로 진행한 미션에서 반응형에 따라 보여지는 컴포넌트 개수와 관련된 기능 요구사항을 페이지 너비에 기반한 resize 이벤트로 구현했다. 기능은 잘 동작했지만, 페이지 너비를 줄일 때마다 버벅거림이 느껴졌다.
부끄럽지만 기능 화면과 코드를 공유해본다.
자바스크립트 resize event로 구현한 기능 화면 및 코드
화면
코드 및 설명
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
function Best() {
const [articles, setArticles] = useState<Article[]>([]);
const [pageSize, setPageSize] = useState(3);
useEffect(() => {
async function fetchArticles() {
try {
const params = {
page: 1,
pageSize: pageSize,
orderBy: "like",
keyword: "",
};
const { list } = await getArticles(params);
setArticles(list);
} catch (error) {
console.error("데이터를 불러오는 데 실패했습니다..!", error);
}
}
fetchArticles();
}, [pageSize]);
useEffect(() => {
const handleResize = debounce(() => {
if (window.innerWidth >= 1200) {
setPageSize(3);
} else if (window.innerWidth >= 768 && window.innerWidth <= 1199) {
setPageSize(2);
} else if (window.innerWidth <= 767) {
setPageSize(1);
}
}, 100);
handleResize();
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
};
}, []);
return (
<div className={styles["container"]}>
<label className={styles["title"]}>베스트 게시글</label>
<div className={styles["best-post-wrapper"]}>
{articles.map((article) => (
<BestPost key={article.id} article={article} />
))}
</div>
</div>
);
}
export default Best;
handleResize함수로 화면 크기에 따라pageSize조정debouncing적용으로 이벤트 핸들러 호출 빈도 제어
작성한 코드가 비효율적인 것 같다는 느낌을 받았다. 굳이 이렇게까지 코드를 작성해야 하나? 뭔가 과한 것 같은데? 아… 그런데 이게 아니면 어떻게 하지?
그래서 자바스크립트로 구현했던 기능을 CSS로 리팩토링 하기로 결정했다.
CSS로 리팩토링을 하는 이유
성능 측면에서 브라우저는 자바스크립트보다 CSS를 먼저 파싱하고 적용하며, CSS는 브라우저에 의해 매우 효율적으로 처리되므로 더 나은 결과를 얻을 수 있다. 또한 자바스크립트로 작성한 코드가 실행되는 횟수가 감소할수록 성능 측면에서 더 유리하기 때문이다.
리팩토링 어떻게 할 건데?
- 자바스크립트로 작성된
pageSize관련 로직 제거 - CSS 미디어 쿼리를 사용해서 반응형에 따라 보이는 컴포넌트 개수 처리 (진짜 간단함 ㄷㄷ)
코드와 화면을 보면서 알아보자!
CSS로 구현한 기능 화면 및 코드
화면
코드 및 설명
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import { useState, useEffect } from "react";
function Best() {
const [articles, setArticles] = useState<Article[]>([]);
useEffect(() => {
async function fetchArticles() {
try {
const params = {
page: 1,
pageSize: 3,
orderBy: "like",
keyword: "",
};
const { list } = await getArticles(params);
setArticles(list);
} catch (error) {
console.error("데이터를 불러오는 데 실패했습니다..!", error);
}
}
fetchArticles();
}, []);
return (
<div className={styles["container"]}>
<label className={styles["title"]}>베스트 게시글</label>
<div className={styles["best-post-wrapper"]}>
{articles.map((article) => (
<BestPost key={article.id} article={article} />
))}
</div>
</div>
);
}
export default Best;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@import "@/styles/import.scss";
.container {
padding-top: 24px;
}
.title {
@include Font(20px, 700, $color-gray-900);
}
.best-post-wrapper {
@include Flex(row, space-between, center);
width: 1200px;
& > * {
display: block;
}
}
@media screen and (max-width: $width-max-tablet) {
.best-post-wrapper {
width: 100%;
gap: 16px;
& > *:nth-child(3) {
display: none;
}
}
}
@media screen and (max-width: $width-max-mobile) {
.best-post-wrapper {
& > *:nth-child(2),
& > *:nth-child(3) {
display: none;
}
}
}
데스크탑 일 때,
.best-post-wrapper에서& > *로 모든 자식 요소를 대상으로 화면에 보이게 해줌
태블릿 일 때,
.best-post-wrapper에서& > *:nth-child(3)로 3번 째 자식 요소를 대상으로 화면에서 보이지 않게 해줌
모바일 일 때,
.best-post-wrapper에서& > *:nth-child(2), & > *:nth-child(3)로 2, 3번 째 요소를 대상으로 화면에 보이지 않게 해줌
자바스크립트에서 CSS로 리팩토링 후 장점
장점이 있다면..,,
- 성능 향상
- 브라우저의 기본 최적화 및 자바스크립트 실행 감소 (기존 코드에서는
resize이벤트 리스너를 사용해 화면 크기 변경을 감지하고 상태를 업데이트 했는데, 이는 성능 측면에서 불리하게 작용함)
- 코드의 단순화 및 유지보수 용이
- CSS로 코드를 작성하여 로직을 단순화 시켰고, 복잡한 상태 관리나 (여기선 복잡하진 않지만) 이벤트 리스너에 대한 설정이 필요하지 않음
- 일관성 있는 동작
- CSS 미디어 쿼리는 모든 브라우저에서 일관되게 동작하고, CSS는 브라우저 렌더링 엔진에 의해 즉각적으로 적용이 되므로 반응 시간이 빠름 (위에 첨부한 화면을 보면 알 수 있듯이 리팩토링 후 버벅거림이 사라짐!)
마치며
만약 매우 복잡한 동적 요구사항이었다면 당연히 자바스크립트로 구현할 수밖에 없겠지만, 지금 요구사항은 충분히 CSS로 훨씬 간단하게 구현할 수 있다! 앞으로 요구사항을 보고 코드를 작성할 때, 무조건 자바스크립트로 기능을 구현하기보다 CSS로 먼저 구현해보는 노력을 해야겠다. 직접 코드를 작성하고 부딪히는 과정에서 얻는 게 많은 거 같다!!! 코드를 작성하는 시야도 넓어지는 거 같고, 효율적인 측면에서 코드 작성을 고려할 수 있게 되는 게 뿌듯하다..!

