728x90
반응형
- 2024-09-12 : First posting.
main {} section {}
의 css 가 달라져야 했는데, 각 페이지 별로 (혹은 component 별로) css file import 를 다르게 해줘도 SPA 이다 보니 css 파일이 어느 페이지를 들어가든 이미 다 load 된 상태가 되어버려서 뒤죽박죽이 된 듯 했다.
## module.css (CSS module 을 사용해보자.)
속도 측면에서도 CSS in js
보다 빠르다고 하고 , 계층적 구조와 semantic 하게 css 를 써야 좋을거 같아서 module.css
를 사용해 보기로 했다.
```[.scrollable.lang-css]
/* ItemsPage.module.css */
.main {
max-width: 1920px;
padding: 20px 0;
display: flex;
flex-direction: column;
justify-content: space-evenly;
gap: 20px;
background-color: white;
}
.section {
max-width: 1200px;
width: 100%;
padding: 0;
margin: 0 auto;
}
.items_head {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
margin-bottom: var(--text-xl);
}
.items_head h2 {
font-size: var(--text-xl);
font-weight: 700;
}
ul.items {
list-style-type: none;
display: flex;
justify-content: space-between;
flex-wrap: wrap;
margin: 0;
padding: 0;
}
ul.items.normal {
display: grid;
grid-template: repeat(2, auto) / repeat(5, 1fr);
gap: 10px;
}
ul.items li {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: flex-start;
gap: 8px;
margin-bottom: 30px;
& .name {
font-size: var(--text-md);
font-weight: 500;
line-height: var(--text-2xl);
}
& .price {
font-size: var(--text-lg);
font-weight: 700;
line-height: var(--text-2xl);
}
& .favorite_count {
font-size: var(--text-xs);
font-weight: 500;
line-height: var(--text-2lg);
& .heart {
font-size: 1.3em;
}
}
}
ul.items.best li {
width: 24%;
}
ul.items.normal li {
width: 100%;
}
ul.items li img {
width: 100%;
aspect-ratio: 1 / 1;
border-radius: 16px;
}
.input_wrapper {
position: relative;
height: 43px;
width: 325px;
}
.input_wrapper img {
position: absolute;
cursor: pointer;
left: 20px;
top: 14px;
bottom: 14px;
width: 17px;
z-index: 10;
}
.input_wrapper input {
position: absolute;
inset: 0;
border-radius: 12px;
padding: 9px 20px 9px 45px;
background-color: var(--secondary-color-gray100);
color: var(--secondary-color-gray400);
z-index: 1;
}
.items_head_query {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 12px;
}
.post_product {
padding: 12px 23px;
font-size: var(--text-lg);
font-weight: 600;
color: var(--secondary-color-gray100);
background-color: var(--primary-color-100);
border-radius: 8px;
display: inline-block;
}
.select_order_by {
padding: 12px 20px;
background-color: white;
font-size: var(--text-lg);
font-weight: 400;
color: var(--secondary-color-gray800);
}
.pagenation {
display: flex;
align-items: center;
gap: 12.5px;
margin: 0 auto 45px;
justify-content: center;
}
.pagenation div {
display: inline-flex;
align-items: center;
justify-content: center;
width: var(--text-4xl);
height: var(--text-4xl);
padding: 12.5px;
background-color: white;
color: var(--secondary-color-gray500);
font-size: var(--text-lg);
font-weight: 600;
border-radius: 9999px;
border: 2px solid var(--secondary-color-gray200);
}
.pagenation div:hover {
background-color: var(--primary-color-300);
color: white;
}
.pagenation div.disabled {
background-color: rgb(216, 216, 216);
color: var(--secondary-color-gray200);
}
.pagenation div.selected {
background-color: var(--primary-color-100);
color: white;
}
@media (max-width:1200px) {
.section {
flex-direction: column;
margin: 0 auto;
padding: 0 24px;
}
.main {
padding: 15px;
}
.input_wrapper {
width: 242px;
}
ul.items.normal {
grid-template: repeat(2, auto) / repeat(3, 1fr);
}
ul.items.best>li {
width: 49%;
}
}
@media (max-width:744px) {
.section {
margin: 0 auto;
padding: 0 16px;
}
.main {
padding: 10px;
}
.head_row {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
margin: 6px 0;
width: 100%;
gap: 10px;
}
.head_row h2 {
flex-grow: 1;
}
.head_row .input_wrapper {
flex-grow: 1;
width: auto;
min-width: 90px;
}
.input_wrapper {
flex-grow: 1;
}
ul.items.normal {
grid-template: repeat(2, auto) / repeat(2, 1fr);
}
ul.items.best>li {
width: 100%;
}
}
```/
와 같이 일반 css 작성하듯 css 를 작성하고 ItemsPage.js
에서 다음과 같이 className 을 설정하자.
```[.scrollable.lang-jsx]
import { useEffect, useState, useCallback } from "react";
import styles from './ItemsPage.module.css'; // 이렇게 import 하자.
import useAsync from "../hooks/useAsync.js";
import BestItemsList from "../BestItemsList.js";
import ItemsList from "../ItemsList.js";
import PageNum from "../PageNum.js";
function ItemsPage() {
// ... codes ...
return (
<main className={styles.main}>
<BestItemsList bestItems={bestItems}/>
<ItemsList items={items} orderBy={orderBy} setOrderBy={setOrderBy} keyword={keyword} setKeyword={setKeyword} onSearch={handleSearch}/>
<PageNum pageNum={pageNum} setPageNum={setPageNum} pageNumMax={pageNumMax}/>
</main>
);
}
export default ItemsPage;
```/
### 작동되는 원리
정확한건 아니지만 내가 써보면서 느낀 작동원리를 설명하자면, .class-selector .sub-class-selector tagName
과 같은 css 가 module.css
에 작성되었다고 치면, compile 단계에서 이런 class-selector
, sub-class-selector
의 이름들을 FileName_class-selector__hashxxx
, FileName_sub-class-selector__hashxxx
로 변환한 채로 css file 이 upload (client 입장에선 download) 된다. 어차피 bundling 된 상태로 올라갈거라 다른 react component 의 같은 이름의 class selector 에 걸리지 말라고 prefix 로 FileName 을, 뒷쪽엔 postfix 로 hashxxx random 문자열이 추가되는거 같다.
그리고 jsx 에서 className={styles[".class-selector"]}
를 불러오면 그냥 class-selector
가 들어가는게 아니라 FileName_class-selector__hashxxx
형태로 올라가는듯 하다. (class-selector 를 javascript 에서 변수로 불러 올 수 있게 항상 class_selector 처럼 underbar 같은걸로 대체해야 하는 줄만 알았는데, 아니었다. 그냥 styles.class-selector 로 못 쓸 뿐, styles[".class-selector"] 로 충분히 접근 가능했다. 이거 때문에 엄청 삽질을 했는데 ㅠㅜ 다른 분들은 저같은 삽질 하지 마시고 시간 아끼시길...)
그래서 @media query 도 쓸 수 있고, nested CSS 도 사용 가능하고, tagName0 .class0 ul li
같은 selector 도 정상 동작한다.
헷갈리는 부분들은 댓글로 알려주시길... 댓글에서 코드 블록은 ```
시작 ```/
마지막으로 감싸면 prettyprint 되어서 나옵니다. (티스토리도 댓글 수에는 제한을 둬놔서 긴 코드는 못쓸거에요. 최대한 축약해서 올리시길...)
## RRA
- 카카오웹툰은 CSS를 어떻게 작성하고 있을까?, 2022-02-10, by 서현우(bono)
- 내가 하면 더 잘 만들 것 같아서 만들어 본 세상 귀여운 on-demand Atomic CSS Library. -Part.1, 2022-05-20, by teo.yu
- 리액트에서 모듈 CSS를 쓸 때 이모저모, 2024-09-12, by 코드잇 풀스택 2기 주강사 이창신
- React로 웹사이트 만들기 (Router/라우터) - 코드잇:
https://recoeve.net/user/kipid/mode/multireco?cat=[IT/Programming]--국비 지원 코딩/공부#https://www.codeit.kr/topics/building-a-website-with-react
https://www.codeit.kr/topics/building-a-website-with-react
728x90
반응형