복습하다가 노션이 다운돼서 오랜만에 벨로그를 쓰게되었다는 슬픈 얘기를 전하며... 시작
리액트 프로젝트에서 컴포넌트를 스타일링할 때, 여러 개의 CSS 파일을 사용하다보면 동일한 이름의 클래스가 중복으로 정의될 수 있다.
중복된 클래스가 정의된 리액트 엘리먼트는 여러 클래스에서 지정한 스타일이 모두 다 적용되며 내가 원하는 스타일이 안나올 수 있다!
이때, CSS Module 기술을 사용하면 CSS 클래스가 중첩되는 것을 방지할 수 있다.
[클래스 이름]_[해시값] 형태로 만들어진다.
같은 rounded-button을 가지고 있지만, 클래스 이름에 대해 고유한 이름이 만들어지기 때문에 CSS 클래스 이름과 중복되는 일에 대해 걱정할 필요는 없다.
간단하게, css 파일의 확장자를 .module.css
로 하면 된다.
css module 기술을 이용해 위 사진의 버튼 컴포넌트들을 만들어 보았다.
Button.module.css
css 파일 ⬇️
📁 cssmodule/src/components/Button.module.css
.rounded-button {
background-color: dodgerblue; /* background */
border: none; /* Remove borders */
color: white; /* White text */
padding: 6px 18px; /* Padding */
text-align: center; /* Center text */
text-decoration: none; /* Remove underline */
display: inline-block; /* Display as inline-block */
font-size: 16px; /* Font size */
margin: 4px 2px; /* Margin */
cursor: pointer; /* Cursor pointer */
border-radius: 6px; /* Border radius */
}
.button-darkblue-gray {
background-color: darkblue;
color: gray;
}
.button-lightblue-black {
background-color: lightblue;
color: black;
}
.button-bg-gray {
background-color: darkblue;
color: lightgray;
}
.button-bg-black {
background-color: lightblue;
color: black;
}
.button-salmon {
background-color: salmon;
}
Button.jsx
컴포넌트 파일 ⬇️
컴포넌트 상단에 module.css
파일을 import 한 후 사용
📁cssmodule/src/components/Button.jsx
import PropTypes from 'prop-types';
import styles from './Button.module.css'
// propType 지정
Button.propTypes = {
children: PropTypes.string.isRequired,
color: PropTypes.string,
backgroundColor: PropTypes.string
}
function Button({ children, color, backgroundColor }) {
return <button className={
`${styles['rounded-button']}
${styles['button-'+backgroundColor]}
${styles['button-bg-'+color]}` }>{ children }
</button>
}
export default Button;
템플릿 리터럴 방식으로 클래스 이름을 가져와준다.
근데 만약 여러 개라면 ${style.first}
, ${style.second}
이렇게 해야 하는데 너무 번거롭게 느껴진다..
(-> 를 해결하기 위해 classNames 라이브러리를 쓸 수 있다.
이건 다음에 알아봐야지..)
App.jsx
최종 렌더링 파일 ⬇️
📁cssmodule/src/App.jsx
import './App.css'
import Button from './components/Button';
function App(){
return (
<>
<h1>CSS 모듈 사용</h1>
<Button>기본 버튼</Button>
<Button backgroundColor="darkblue" color="gray">다크블루색 버튼</Button>
<Button backgroundColor="lightblue" color="black">라이트블루색 버튼</Button>
</>
)
}
export default App;
렌더링 결과 ⬇️
CSS Module은 Sass에서도 사용할 수 있다! (아직은 안써봤지만)
node-sass
를 설치한 후, 확장자를 .module.scss
로만 바꿔주면 사용할 수 있다.
💅 styled-components
! 저 네일아트 하는 이모지가 인상 깊어서 정말 써보고 싶었던 라이브러리다.
styled-components는 대표적인 css in js 라이브러리이며, 그만큼 대중적으로 많이 사용하고 있다.
(이 외에는 emotion과 styled-jsx가 있다.)
(css in js: 자바스크립트 코드로 css를 작성하는 것)
css module 방식과는 다르게, class로 지정하는 것이 아니라 props를 이용해서 css를 적용하는 것을 볼 수 있다.
그럼 어떻게 사용하느냐?
npm i styled-components
styled-components가 필요한 프로젝트 폴더에서 명령어를 입력해주고 엔터치면 설치 완료!
styled-components를 이용해 버튼을 만들어보았다.
버튼 컴포넌트를 만들고, 스타일 입히기
StyledButton.jsx
⬇️
📁 styledcomponents/src/components/StyledButton.jsx
import styled from 'styled-components';
import PropTypes from 'prop-types';
// Tagged Template Literal 방식을 사용해 컴포넌트의 props를 읽어온다.
const ButtonStyle = styled.button`
background-color: ${ props => props.backgroundColor || 'dodgerblue' }; /* background */
border: none; /* Remove borders */
color: ${ props => props.color || 'white' }; /* White text */
padding: 6px 18px; /* Padding */
text-align: center; /* Center text */
text-decoration: none; /* Remove underline */
display: inline-block; /* Display as inline-block */
font-size: ${ props => props.size || '16px' }; /* Font size */
margin: 4px 2px; /* Margin */
cursor: pointer; /* Cursor pointer */
border-radius: 6px; /* Border radius */
`;
// ButtonStyle에서 색상만 따로 바꾸고 싶다면 이렇게 작성한다.
const ButtonStyleSalmon = styled(ButtonStyle)`
background-color: salmon; /* background */
`;
// propType 지정
Button.propTypes = {
children: PropTypes.string.isRequired,
}
Submit.propTypes = {
children: PropTypes.string.isRequired,
backgroundColor: PropTypes.string
}
// props를 하나하나 넣어주는 번거로운 짓은 하지 말고, rest 문법을 사용한다.
function Button({ children, ...rest }){
return <ButtonStyle type="button" { ...rest }>{ children }</ButtonStyle>
}
function Submit({ children, ...rest }){
return <ButtonStyleSalmon type="submit" { ...rest }>{ children }</ButtonStyleSalmon>
}
export { Button, Submit }
최종 렌더링 파일 App.jsx
⬇️
📁 styledcomponents/src/App.jsx
import { Button, Submit } from "./components/StyledButton";
function App(){
return (
<>
<h1>Styled Components</h1>
// props를 넘겨주어 size, color, bgColor 등 원하는 것을 바꿔줄 수도 있다.
<Button
size="12px"
color="lightblue"
backgroundColor="darkblue">Button Type 버튼</Button>
<Submit>Submit Type 버튼</Submit>
</>
)
}
export default App;
렌더링 결과 ⬇️
props
, state
등을 이용해서)-webkit-line-clamp: 5;
내 개인적 의견으로는 styled-components가 더 쓰기 편한 것 같다!
한 파일 안에서 컴포넌트를 관리하는게 더 좋아서 .. (프로젝트 시작하면 또 다를 수도?)
일단 오늘 처음 배워본 입장에선, styled-components 압승
CSS 수업이 끝나고 혼자 조금 독학해 본 테일윈드!
리액트에서도 쓸 수 있는 줄 몰랐는데, 오늘 배우게 되었다~!
tailwindcss를 사용할 프로젝트 폴더에 아래 명령어를 입력해서 설치해준다.
npm i -D tailwindcss postcss autoprefixer
설치를 마쳤으면, 설정 파일을 수정해주어야 한다.
npx tailwindcss init -p
를 터미널에 입력해주면,
postcss.config.js
파일이 생성된다.
tailwind.config.js
파일도 확인할 수 있다.
📁 tailwind/postcss.config.js
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
기본적으로 tailwindcss와 autoprefixer 플러그인이 추가되어 있다. 없다면 수정해주기~
📁 tailwind/tailwind.config.js
/** @type {import('tailwindcss').Config} */
export default {
content: [
"./index.html",
// 타입스크립트를 사용한다면, ts, tsx 확장자명도 추가해준다.
"./src/**/*.{js,jsx}",
],
theme: {
extend: {},
},
plugins: [],
}
📁 tailwind/src/index.css
@import 'tailwindcss/base';
@import 'tailwindcss/components';
@import 'tailwindcss/utilities';
@import './App.css';
이렇게 써도 되고, 아니면
// 이 때, App.css import 구문은 최상단에 위치해야 함
@import './App.css';
@tailwind base;
@tailwind components;
@tailwind utilities;
요렇게 써도 된다.
만약 esLint에서 자꾸 경고를 준다면
vscode settings - unknown at rules - CSS > Lint: Unknown At Rules를 ignore로 변경한다.
테일윈드로도 똑같이 버튼 컴포넌트를 만들어 보았다~
버튼 컴포넌트 파일 ⬇️
📁 tailwind/src/components/Button.jsx
import PropTypes from 'prop-types';
// propType 설정
Button.propTypes = {
children: PropTypes.string.isRequired,
bgColor: PropTypes.string,
fontSize: PropTypes.string
}
// 역시나 여기서도 rest 문법을 사용한다.
function Button({ children, bgColor="red", fontSize="sm", ...rest }){
let btnColor = {
blue: `bg-blue-400`,
green: `bg-green-400`,
gray: `bg-gray-400`,
red: `bg-rose-400`
};
let btnSize = {
sm: 'py-1 px-2 text-sm',
md: 'py-2 px-4 text-base',
lg: 'py-2 px-6 text-lg',
xl: 'py-2 px-8 text-xl'
};
let btnHoverColor = {
blue: `hover:bg-blue-300`,
green: `hover:bg-green-300`,
gray: `hover:bg-gray-300`,
red: `hover:bg-rose-300`
};
return <button
className={`
${btnColor[bgColor]}
text-gray-50
font-bold ${btnSize[fontSize]}
mx-2
my-3
rounded-md
${btnHoverColor[bgColor]}
`}
{...rest} >{ children }</button>
}
export default Button;
tailwind 공식 문서에 따르면, Dynamic class name을 설정할 때는 항상 완전한 클래스 이름으로 설정해야 한다.
완전한 클래스 네임만 따로 추출해서 그 추출한 애들만 최종 결과에 반영하기 때문이다.
따라서, bg-${bgColor}-300
이렇게 사용하는 것은 안된다!!
(이거 때문에 tailwind 쓰기 싫다 엉엉 코드가 너무 길어~!)
아무튼 계속해서 최종 렌더 파일인 App.jsx 파일을 보자.
(벨로그는 콜아웃 기능이 없나요?.... 불편해)
📁 tailwind/src/App.jsx
import Button from "./components/Button";
function App(){
return (
<>
<h1 className="myTitle">Tailwind CSS</h1>
<p>Hello Tailwind</p>
<Button>기본 버튼</Button>
<Button
bgColor="blue"
fontSize="md">파란 버튼</Button>
<Button
type="submit"
bgColor="green"
fontSize="lg"
onClick={ () => alert('등록하시겠습니까?') }>녹색 버튼</Button>
<Button
bgColor="gray"
fontSize="xl">회색 버튼</Button>
<button
className={`
bg-violet-400
text-gray-50
font-bold
px-3
py-1
mx-2
my-3
text-lg
rounded-md
hover:bg-violet-300
`}>컴포넌트 아님</button>
<br />
<button className="btn btn-primary">주요 버튼</button>
<button className="btn btn-warn">경고 버튼</button>
</>
)
}
export default App;
클래스를 이용해 스타일을 입히다 보니, 아주 번잡스럽기 그지 없다.
그럴 땐 주요 버튼과 경고 버튼의 코드를 보자. 깔끔하지 않는가요?
저렇게 줄여쓰기 위해.. index.css 파일을 이용해 자주 사용하는 버튼들을 따로 설정해주었다.
📁 tailwind/src/index.css
@import 'tailwindcss/base';
@import 'tailwindcss/components';
@import 'tailwindcss/utilities';
@import './App.css';
@layer components {
.btn {
@apply
bg-violet-400
text-gray-50
font-bold
px-3
py-1
mx-2
my-3
text-lg
rounded-md
hover:bg-violet-300
}
.btn-primary {
@apply bg-orange-400 hover:bg-orange-300
}
.btn-warn {
@apply bg-yellow-400 hover:bg-yellow-300
}
}
이렇게 설정해두고 갖고오면 된다!
최종 결과물 ⬇️
ㅎ Button 컴포넌트 파일을 만드는가 vs index.css 파일에서 한번에 하는가~는 자신의 선택입니다용
근데 .. 나는 너무너무 불편해서 못쓸 것 같다 ㅠㅠ
난.. tailwind 잘 모르겠다.. (새로운게 아니라 그런가?ㅋㅋㅋ)
근데 배우는 입장이니까.. 다 열심히 써봐야겠다...!!
그럼 오늘 정리는 끝! 휴 이거 다쓰니까 노션 복구됐네~!