No CSS Clubํ์์ด ์๋๋ผ๋ฉด ์นํ์ด์ง์ ์คํ์ผ๋ง์ ์ํด CSS๋ ํ์์ ์ด๊ณ ์ค์ํฉ๋๋ค
๊ทธ๋ฌ๋ ์ญ์ฌ์ ์ผ๋ก CSS๋ ๊ฐ๋ฐ์๋ค์๊ฒ ๋ง์ ๊ณ ํต์ ์ฃผ์์ต๋๋ค..
๊ทธ ์ญ์ฌ์ ๋ํด์๋ CSS๋ ์ ์ด๋ ค์ด๊ฐ?์๋ฆฌ์ฆ ๊ธ์ด ์ฌ๋ฐ๊ณ ์ ์ตํ๋ ํ๋ฒ์ฏค ๋ณด์๋ฉด ์ข๊ฒ ์ต๋๋ค.
์ด ๊ธ ์ฐ์ ๋ถ์ด ๊ฝค ์ ๋ช
ํ์ ๋ถ์ด๋๋ฐ, ์ต๊ทผ์ ํ๋์ velog trending 1์์ ๋จธ๋ฌด๋ ์ค์ธ ํ๋ก ํธ์๋ ๊ด์ฌ์ฌ ๋ถ๋ฆฌ์ ๊ดํ ๊ธ ๋ ๋งค์ฐ ์ ์ตํฉ๋๋ค. ์ถ์ฒ
์๋ฌดํผ CSS์๋ ๋ช ๊ฐ์ง ๊ฒฐํจ์ด ์กด์ฌํ์ต๋๋ค :
- Global Scope : CSS ๊ท์น์ ์ ์ธํ๋ฉด ์ ์ฒด ๋ฌธ์์ ์ํฅ์ ๋ฏธ์นฉ๋๋ค. ์ด ํน์ฑ์ ํ๋ก์ ํธ๊ฐ ์ปค์ง์๋ก ๋ฌธ์๋ฅผ ๋ฐ๋๋ ํ ์๋ ๊ท์น๊ณผ ์ ํ์์ ์ง๋ขฐ๋ฐญ์ผ๋ก ๋ง๋ค์์ต๋๋ค.
- Specificity : CSS๋ ์ ํ์์ ์ํ ๊ท์น์ ์ ์ฉ์ ์ฐ์ ์์๊ฐ ์กด์ฌํฉ๋๋ค. ๊ท์น์ ๋์ค์ ์ ์ธํ๋ค๊ณ ํด์ ๊ธฐ์กด ์คํ์ผ์ ๋ฎ์ด์ธ ์ ์๋๊ฒ ์๋ ๊ฒ์
๋๋ค. ์ด๋ฌํ ํน์ฑ์ ๊ฐ๋ฐ์๋ค๋ก ํ์ฌ๊ธ ์ ์ ๋ ๋ณต์กํ ์ ํ์๋ฅผ ๋ง๋ค๊ณ ,
!important
๋ inline-style๊ฐ์ ์ฐํ์ฑ ์ ์ฐ๋ค๊ฒ ํ์ต๋๋ค
ํ๋ก์ ํธ๊ฐ ์ปค์ง์๋ก ์ด ๊ฒฐํจ์ ๋์ด๋๊ณ ๋ถ์ด๋์ ๊ฐ๋ฐ์๋ค์ ๊ณ ํต์ค๋ฝ๊ฒ ํ์ต๋๋ค
์ด๋ฌํ ๋ฌธ์ ์ ์ ํด๊ฒฐํ๊ณ CSS๋ฅผ ํ๋ช
ํ๊ฒ ์ฌ์ฉํ๊ธฐ ์ํด, ๋จ์ํ CSS๋ฅผ ์ด์ง ํ์ฅํ๋ ๋ฐฉ๋ฒ๋ก ๋ถํฐ ์์ ์๋ก์ด ํจ๋ฌ๋ค์์ ๊ฐ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ํ๋ ์์ํฌ ๋ฑ์ด ๋ฑ์ฅํด์์ต๋๋ค.
CSS Modules, SCSS, CSS-in-JS, Utility-First CSS ๋ผ์ด๋ธ๋ฌ๋ฆฌ, ๋ฑ๋ฑ..
์ด๋ฌํ ๋ง์ ์ ํ์ง๋ค ์ฌ์ด์์ ํ๋ก ํธ์๋ ๊ฐ๋ฐ์๋ ๋งค๋ฒ ์ ํ์ ๊ธฐ๋ก์ ๋์
๋๋ค.
ํ๋ก์ ํธ์ ํน์ฑ, ํจ๊ป ์ธ ๊ธฐ์ , ์์ง์ฑ, ์์ฐ์ฑ ๋ฑ.. ๋ง์ ์์ธ๋ค์ด ๊ณ ๋ ค๋๋๋ฐ
์ ๋ ์ด์ ๋ํด ๊ณ ๋ฏผํ๊ณ ์ ์ ํ ๊ทผ๊ฑฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ด๋ค ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ์ง ์ ํํ๋ ค๋ฉด ์ด๋ก ์ ๋์ด์ ๊ฒฝํ์ด ํ์ํ๋ค๊ณ ์๊ฐํ์ด์
์ด๊ฒ๋ ์จ๋ณด๊ณ , ์ ๊ฒ๋ ์จ๋ณด๊ณ , ๊ทธ ์ฅ๋จ์ ์ ๋ชธ์ผ๋ก ๋๊ปด๋ณด๊ณ , ๊ทธ ๊ฒฝํ๋ค์ ๊ฐ์ง๊ณ ์๋ค๊ฐ ๋์ค์ ์ง์ง ํ์ํ ๋ ์์ฌ๊ฒฐ์ ์ ์ฐ๊ณ ์ ํ์ต๋๋ค
๊ทธ๋ฆฌ๊ณ ์ง๊ธ๊น์ง์ ๊ณ ๋ฏผ๊ณผ ๊ฒฝํ์ ๋๋๊ณ ์ ํด์
์ด์ ๋ถํฐ๋ ์ ๊ฐ ์ง๊ธ๊ป ์ฌ์ฉํด๋ณธ ์คํ์ผ๋ง ๋ฐฉ๋ฒ๋ค์ ๋ํด ์ด์ผ๊ธฐํ๊ณ
์ด๋ฅผ ์ค์ ๋ก ์ฌ์ฉํ๋ ์
์ฅ์์ ์ด๋ค ์ฅ๋จ์ ๋ค์ด ์์๋์ง ์จ๋ณด๊ฒ ์ต๋๋ค
๊ทธ๋ฆฌ๊ณ ๋ชจ๋ ์นํ์ด์ง ๊ตฌ์ฑ์ ์ํด ํ์์ ์ธ ๋์ ์คํ์ผ๋ง ์ธก๋ฉด์ ๋ํด์๋ ์ฐ๋ ค๊ณ ํฉ๋๋ค
์ด๋ ๋งค์ฐ ์ค์ํ๊ณ ์ด ๋ํ ์ด๋ค ๋ฐฉ๋ฒ์ ๊ณ ๋ฅผ์ง ๊ณ ๋ฏผํ ๋ ์ค์ํ ์์ธ์ด๋๊น์
vanila CSS
์ด ๋ธ๋ก๊ทธ์๋ ์์ํ๊ฒ CSS๋ง ์ฌ์ฉํ๊ณ ์์ต๋๋ค.
์ฒ์ ๋ง๋ค ๋๋ถํฐ ์ผ๋ถ๋ฌ ์๊ฐํ์ด์. CSS๋ง ์จ๋ณด๋ฉด์, ๋ฌด์จ ๋ถํธํจ์ด ์๊ธฐ๊ณ , ์ด๋ค ๋์ฆ๊ฐ ์๊ธฐ๋์ง ๋๊ปด๋ณด๊ณ ์ถ์์ต๋๋ค
Global Scope๋ ํ์คํ ๋ฌธ์ ์
๋๋ค.
๋ธ๋ก๊ทธ๋ ์ ๊ฐ ํผ์ ๊ฐ๋ฐํ๊ธฐ๋ ํ๊ณ , ๊ทธ์ ๋๋ก ๋ง์ ์คํ์ผ ์ฝ๋๊ฐ ๋ฐ์ํ์ง ์์์ ๋คํ์ด์ง, ํ์
์๊ฐ ์๊ณ ํ๋ก์ ํธ๊ฐ ์ปค์ง ์๋ก ์ด ์ ํ์๋ค ์ฌ์ด์ ์ง๋ขฐ๋ฐญ์ ํผํ๊ธฐ๋ ์ฝ์ง ์์๊ฑฐ์์
๊ทธ๋ฆฌ๊ณ ๋ชจ๋ ์คํ์ผ์ฝ๋๊ฐ ์ค์ํ๋ ์๋ฐ์ ์๊ธฐ ๋๋ฌธ์, ์ ํ ์ฌ์ด์ ๊ฑฐ๋ฆฌ๊ฐ ๋๋ฌด ๋ฉ์ด์ง๋๋ค..
๊ทธ๋ ๋ค๊ณ ์คํ์ผ์ฝ๋๋ฅผ ์ฌ๋ฌ๊ฐ ๋ ์๋ ์์ฃ . ํํธํ๋๊ธฐ ์์ํ๋ฉด Global Scope๋ฅผ ๊ฐ๋นํ๊ธฐ ๋์ฐํด์ง๋๋ค
vanila CSS์์๋ ์กฐ๊ฑด๋ถ ์คํ์ผ๋ง์, class๊ฐ์ ๊ฒ์ ๋์ ์ผ๋ก ์ถ๊ฐํ๊ฑฐ๋ ์ ๊ฑฐํ์ฌ ๋ฌ์ฑํฉ๋๋ค.
๋ง์ฝ ๋ฒํผ์ ํด๋ฆญํ์ฌ body์ darkmode ํด๋์ค๋ฅผ ๋ฃ๊ฑฐ๋ ์ ๊ฑฐํ๋ ค๋ฉด, ์๋์ฒ๋ผ ํฉ๋๋ค.
button.addEventListener("click", () => {
// body ํ๊ทธ์ darkmode ํด๋์ค๋ฅผ ์ถ๊ฐํ๊ฑฐ๋ ์ ๊ฑฐ
document.body.classList.toggle("darkmode");
});
๋๋ ๋ฆฌ์กํธ ์ํ๋ฅผ ์ด์ฉํ์ฌ ์ผ๋ถ ์ปดํฌ๋ํธ์ ๋ํด ๋์ ์ผ๋ก ์คํ์ผ์ ์ ์ฉํ๋ ค๋ฉด ์ด๋ ๊ฒ ๋๊ฒ ๋ค์
<button className={isActive ? "active" : undefined}>
CSS Modules
๋ฐํ ์ผ์ด๋ผ๋ ์๋น์ค๋ฅผ ๊ฐ๋ฐํ ๋ ์ผ์ต๋๋ค
๊ทธ๋๋ก CSS๋ฅผ ์์ฑํ๋๊ฑด ๋๊ฐ์๋ฐ, ์ผ์ ๋ถ๋ถ(ํ์ผ ๋ฑ)์๋ง ๊ตญํ๋๋ Local Scope๋ฅผ ๊ฐ์ง CSS์ฝ๋๋ฅผ ์์ฑํ ์ ์์ด์.
ํ์ผ๋ช
.module.css
์ด๋ ๊ฒ ์ด๋ฆ์ ์ง์ผ๋ฉด CSS module์ด ๋ฉ๋๋ค
์ด๋ฅผ import styles from './my-style.module.css'
์ ๊ฐ์ด importํ์ฌ ์ฌ์ฉํด์
๊ทธ๋ผ ์ด์ CSS Module์ ์ ์ธ๋ ํด๋์ค๋ค์ ๋ํด ์์์ ํด์๊ฐ์ ์ถ๊ฐํ๋ฏ๋ก, class์ด๋ฆ์ด ๊ฒน์น๋๋ผ๋ ๋ค๋ฅธ ํด๋์ค๊ฐ ๋์ด ๋ฒ์๊ฐ ์ด๋ฅผ importํ ํ์ผ์๋ง ํ์ ๋ฉ๋๋ค.
์ด ๋๋ถ์ CSS์ฝ๋๋ฅผ ํ์ผ(์ปดํฌ๋ํธ, ํ์ด์ง ๋ฑ) ๋จ์๋ก ๊ฒฉ๋ฆฌํ๊ณ ๊ตฌ๋ถ์ง์ ์ ์์ด์.
/* Button.module.css */
.button {
background-color: #3498db;
padding: 10px;
}
// React Component
import styles from "./Button.module.css";
function Button() {
return <button className={styles.button}>Click Me</button>;
}
CSS Modules์์ ์กฐ๊ฑด๋ถ๋ก ์คํ์ผ์ ์ ์ฉํ๊ณ ์ถ๋ค๋ฉด
vanila CSS์์์ฒ๋ผ ํด๋์ค๋ฅผ ๋์ ์ผ๋ก ๋ผ์ฐ๋ ๊ฒ์ผ๋ก ํด์
className={isActive ? styles.active : undefined}
์ด๋ฐ ์์ผ๋ก์
์ฅ๋จ์
์ข์ ์ ์, vanila CSS๋ฅผ ์ ์๋ฉด ์ด module๋ง์ผ๋ก๋ ์ถฉ๋ถํ ํธํฉ๋๋ค.
์ฌ์ค์ CSS์ ๋ฌ๋ผ์ง๊ฒ ํ๋๋ ์์ผ๋๊น์.
๊ธฐ์กด CSS์์ ์ด๋ฐ์๋ global scope๋ฅผ ํด๊ฒฐํ๊ณ , ๋๋ถ์ ์ฐ์ ๋์ ๋ณต์ก๋๊ฐ ์ ์ ๊น์ด์ง๋ ์ํฉ๋ ํผํ ์ ์์ต๋๋ค
๋ํ ์ด์ ์ด ๋๋ถ์ CSS ์ฝ๋๋ ์ด๋ฅผ ํ์๋กํ๋ ์ฝ๋์ ๋ฐ๋ก ์์ ์์นํ์ฌ ๋ฌถ์ผ ์ ์๊ฒ ๋ผ์
๋จ์ ์ผ๋ก๋ class์ด๋ฆ์ ๊ฐ๋
์ฑ์ด ์ข ๋จ์ด์ง๋๋ค. ์ด๋์ ๋๋ ์์๋ณผ๋งํ๋ฐ, ๊ฐ๋ฐ์๋๊ตฌ๋ก ๊ฒ์ฌํ ๋ ์ข ๊น๋ค๋ก์์ง๋ ์ธก๋ฉด์ด ์์ง์์ ์์ต๋๋ค.
๋์ ์คํ์ผ๋ง๋ ์ฌ์ค์ ๋ค๋ฅธ ๋ฐฉ๋ฒ๋ค์ ๋นํด ๊ฐ์ ์ด ์๋ ํธ์ ์๋์ฃ , ํด๋์ค ์์ฒด๋ฅผ ๊ฐ์๋ผ์ฐ๊ธฐ ๋๋ฌธ์
๋๋ค
์ด์ธ์ ๋ค๋ฅธ ์๋ฃ๋ค์์ ๋ณด๋ฉด ์ ์ญ์คํ์ผ๋ง์ด๋, ํํธํ๊ฐ ์ฌํด์ง๋ค๋ ๊ฒ์ ๋จ์ ์ผ๋ก ์ด์ผ๊ธฐํ๊ธฐ๋ ํ๋๋ฐ, ์ ๋ฑํ ๊ณต๊ฐํ์ง๋ ์์ต๋๋ค.
์ ์ญ์คํ์ผ๋ง์ด ํ์ํ๋ฉด ์ฌ์ ํ ๋ชจ๋์ด ์๋ ์ ์ญcss์ํธ๋ฅผ ์์ฑํ ์ ์๊ณ , ์ฐ๋ฆฌ๋ ๋ชจ๋ํ๋ฅผ ์ํด CSS Modules๋ฅผ ์ฌ์ฉํ๊ธฐ ์์ํ๊ฒ๋๋ค
CSS-in-JS
CSS-in-JS๋ ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋์์ CSS๋ฅผ ์์ฑํ๋ ํจ๋ฌ๋ค์์
๋๋ค.
styled-component๋ emotion๊ฐ์ ๊ฒ๋ค์ด ๋ํ์ฃผ์์ธ๋ฐ
์ ๋ emotion์ ์ฃผ๋ก ์ฌ์ฉํด๋ดค์ต๋๋ค.
ํ์ฌ์์๋ emotion์ผ๋ก ์์ฑํ๋ ๊ฒฝ์ฐ๊ฐ ๊ฝค ๋ง๊ณ ,
์ฒ์ ๋ฆฌ์กํธ ํ๋ก์ ํธ ํ ๋๋ ์ด๊ฑฐ๋ก ์์ํ์ด์.
emotion์ ์๋์ฒ๋ผ ์์ฑํด์
const RedButton = styled.button`
background-color: red;
`;
function FooComponent() {
return <RedButton>START!</RedButton>;
}
์คํ์ผ์ ๊ฐ๋ ์ปดํฌ๋ํธ๋ฅผ ์์ฑํ๊ณ , ๋ง์น ์ผ๋ HTML์์๋ ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ๋ฏ์ด ์ฌ์ฉํฉ๋๋ค.
์ปดํฌ๋ํธ ํ์ผ์ ํจ๊ป ์กด์ฌํ๊ฒ ํด๋ ๋๊ณ , ๋ฐ๋ก style.jsx
๋ก ์์ ๋ถ๋ฆฌํ์ฌ ๋ฌ๋ ๊ด์ฐฎ์ต๋๋ค.
์ทจํฅ์ ๋ฐ๋ผ ๊ฐ๋ฆฌ๋ ๊ฒ ๊ฐ์์.
๋์ ์คํ์ผ๋ง์ ์๋์ฒ๋ผ ํฉ๋๋ค.
const RedButton = styled.button`
background-color: ${props => (props.active ? "red" : "gray")};
`;
function FooComponent() {
const [isActive, setIsActive] = useState(false);
return (
<RedButton active={isActive} onClick={() => setIsActive(prev => !prev)}>
START!
</RedButton>
);
}
๋ง์น ์ง์ง ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค๋ฏ์ด, props๋ฅผ ๋๊ธฐ๊ณ styled ์ฝ๋ ๋ด์์ props๋ฅผ ๋ฐ์ ์ธ ์ ์์ด์.
๋๋ ์๋์ฒ๋ผ๋ ๋ฉ๋๋ค.
function FooComponent() {
const [isActive, setIsActive] = useState(false);
const buttonStyle = css`
background-color: ${isActive ? "red" : "gray"};
`;
return (
<button css={buttonStyle} onClick={() => setIsActive(prev => !prev)}>
START!
</button>
);
}
์ฅ๋จ์
์ด ๋ฐฉ๋ฒ์ ์คํ์ผ ์ฝ๋์ ์ฌ์ฌ์ฉ์ด ๊ฝค ์ฝ๊ณ ์ข์์ด์.
๊ทธ๋ฆฌ๊ณ ์ ์ผ ์ข์ ์ ์, ๊ฐ ์ปดํฌ๋ํธ๋ค์ ์ด๋ฆ์ด ์์ผ๋๊น ์ฝ๋ ์์ ํ ๋ ์์๋ณด๊ธฐ ์ฝ๋ค๋ ์ ์
๋๋ค.
์๋ฅผ ๋ค์ด TitleWrapper, ContentWrapper
์ด๋ฐ์์ผ๋ก์. ์๋๊ฐ์ผ๋ฉด ๊ทธ๋ฅ div, div, ...
๋ค ๋๊ฐ์ div๊ฒ ๋ค์.
๊ฝค ์ฝ๊ธฐ ์ฌ์ด ์ฝ๋๋ฅผ ๋ง๋ค์ด์ค๋๋ค.
JS ๋ณ์๋ฅผ ๊ทธ๋๋ก ๊ฐ์ ธ๋ค๊ฐ ๋์ ์คํ์ผ๋ง์ ํ์ฉํ ์ ์๋ค๋ ์ ๋ ํฐ ์ฅ์ ์
๋๋ค.
๋ฆฌ์กํธ๋ JS์ ์ธ ์ฌ๊ณ ๋ฐฉ์์์ ๋ณ๋ก ๋ฉ๋ฆฌ ๋จ์ด์ง์ง ์์๋ ๋๋ค๋ ์ ์์ ์ข์ต๋๋ค
๋ค๋ฅธ ๋ฐฉ๋ฒ๋ค๋ ๋์ ์คํ์ผ๋ง์ด ์ด๋ ค์ด๊ฑด ์๋์ง๋ง, ๋ฐ์ง์๋ฉด ์ด๊ฒ ์ข ๋ ํธํ๋๋ผ๊ตฌ์
๊ทธ๋ฆฌ๊ณ CSS์ฝ๋๊ฐ JS์ฝ๋ ์์ ์กด์ฌํ ์ ์๋ค๋ ์ ๋ ์๊ทผํ ์ฅ์ ์
๋๋ค (colocation.)
๋ฑ ํ ํ์ผ์ ํ์ํ CSS-in-JS ์ฝ๋๋ง์ด ํด๋น ํ์ผ ์ ๋๋ ์ฌ์ง์ด ๊ฐ์ ํ์ผ์ ์กด์ฌํ ์ ์์ต๋๋ค
ํ ๊ฐ์ง ์์ฌ์ด ์ ์, ๊ฐ๋ฐ์๋๊ตฌ์์ ๊ฒ์ฌํ ๋ class์ด๋ฆ์ด ๊ทธ๋ฅ ์์์ ๋ฌธ์์ด์
๋๋ค
์ด๊ฒ ์ง์ง ์์๋ณด๊ธฐ ํ๋ค์ด์ ธ์.
๊ทผ๋ฐ ์ด ๋จ์ ์ ์ด๋ฐ ํ๋ฌ๊ทธ์ธ๊ฐ์ ๊ฒ๋ค๋ก ์ปค๋ฒํ ์ ์์ต๋๋ค
์ง์ง ๋จ์ ์ผ๋ก๋ ๋ฐํ์ ์ฑ๋ฅ์ด ์์ข๋ค๋ ์ฐ์ด ์๋๋ฐ.. ๋ฐ์์ ์์๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
Material UI (UI ๋ผ์ด๋ธ๋ฌ๋ฆฌ)
์ฌ์ค ๋ฐํ
์ผ์ด๋ผ๋ ์๋น์ค๋ฅผ ๊ฐ๋ฐํ๋ ๋จ๊ณ์์ ์ฒ์์ ์ฃผ๋ก Material UI๋ฅผ ์ฌ์ฉํ์ต๋๋ค
Material UI๋ผ๋๊ฑด ์ผ์ข
์.. UI๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋๋ ์ปดํฌ๋ํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์
npm install @mui/material @emotion/react @emotion/styled
์ด๋ ๊ฒ ์ผ๋จ ์ค์นํ๋ฉด
์ด ํจํค์ง์์ ์ฌ๋ฌ ๋ฏธ๋ฆฌ ์คํ์ผ์ด ์ ์ฉ๋ ์ปดํฌ๋ํธ๋ค์ ์ ๊ณตํด์ค๋๋ค.
Material UI ์ด์ธ์๋ Chakra UI, bootstrap, ... ์ด๋ฐ๊ฒ ์๋๋ด
๋๋ค.
import React from "react";
import Button from "@mui/material/Button";
function App() {
return (
<Box sx={{ textAlign: "center", marginTop: "50px" }}>
<Button variant="contained" color="primary">
Click Me
</Button>
<Button variant="outlined" color="secondary" sx={{ marginLeft: "10px" }}>
Cancel
</Button>
</Box>
);
}
export default App;
๋์ ์คํ์ผ๋ง์ mui๊ฐ์ ๊ฒฝ์ฐ sx
props๋ฅผ inline-style์ฒ๋ผ ๋ช
์ํ๊ฒ ํ๊ฑฐ๋, ์์ ๋ช๋ช ์์ฃผ ์ฐ์ด๋ ํ ํฐ์ props๋ก ๋ฃ์ ์ ์์ผ๋ ์ด๊ฑธ ์ด์ฉํฉ๋๋ค.
<Button variant="contained" color={isCancel ? "red" : "blue"}>
This is button
</Button>
์ฅ๋จ์
์ฅ์ ์ผ๋ก๋, ์ผ๋จ "์ฐ๋ฆฌ ํ๋ก์ ํธ ๊น์๋ ์ด๊ฒ ๋ง๊ฒ ๋ค" ์ถ์๊ฑธ ์ ๊ณ ๋ฅด๊ณ ์์ํ๋ค๋ฉด, ๋ณ๋์ CSS์ฝ๋๋ฅผ ๊ฑฐ์ ์์ฑํ์ง ์์๋ ๋ฉ๋๋ค
๋ฐํ
์ผ ํ๋ก์ ํธ๋ ์ฒ์์๋ ์์ ์คํ์ผ ๊ตฌ์ํ๋๊ฒ ๋ฑ MUI ๊น์ด๋ผ์, ์ด๊ฑธ ๊ฑฐ์ ๊ฐ์ ธ๋ค ์ผ์ด์
๊ทธ๋ฌ๋๋ ์์ ์ ์ฒด ํ๋ก์ ํธ์์ css์ฝ๋๋ ๊ฑฐ์ ์์์ต๋๋ค
๊ทผ๋ฐ ๋์์ธ ์ปจ์
์ ์๋ก ์์ ํ๋ v2์์
์ ์งํํ๋ฉด์ ๊ฑฐ์ ์ธ๋ชจ๊ฐ ์์ด์ก์ง๋ง..
์ด๊ฒ ๋จ์ ์ด๊ธดํฉ๋๋ค. ์ด๋์ ๋ ์์ค์์๋ ๋งค์ฐ ๋น ๋ฅด๊ณ ๊ฐ๋จํ๊ฒ ์คํ์ผ๋งํ ์ ์์ง๋ง, ๋ํ
์ผ์ด ๋ฌ๋ผ์ง๊ฒ ๋๋ฉด ํ๋ค์ด์ ธ์. ๊ฒฐ๊ตญ์ ์ฐ๋ ์๋ฏธ๊ฐ ๊ฑฐ์ ์์ด์ง๋๋ค
๋ ๋จ์ ์ธ๊ฑด ๋์ ํด์ฃผ๋๊ฒ ๋๋ฌด ๋ง์์. ๊ธฐ๋ณธ ๊ธ๋ก๋ฒ ์คํ์ผ์ด๋, ์ปดํฌ๋ํธ ์์ฒด์ ์คํ์ผ์ด๋, ์ด๋์๋ถํฐ ์๋ชป๋๋์ง๋ฅผ ์ ๋ชจ๋ฅผ ๋๊ฐ ์์ต๋๋ค
๊ทธ๋ฆฌ๊ณ ๊ทธ UI๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ํด ์กฐ๊ธ์ ์๊ณ ์์ํด์ผํ๋ ๋ฌ๋์ปค๋ธ๊ฐ ์กด์ฌํฉ๋๋ค
MUI๋ฅผ ์๋ก ๋ค๋ฉด, <Box>
๋ฅผ ์ด์ฉํด์ผ๊ฒ ๊ตฌ๋, <Card>
๋ฅผ ์ฌ์ฉํด์ผ์ง, ์ด๋ฐ๊ฑฐ๋ฅผ ์ฒ์๋ถํฐ ์ ์๋ ์์ผ๋๊น์
๊ทธ๋ฆฌ๊ณ MUI๋ <Grid>, <TreeView>
๊ฐ์ ์ ํธ๋ฆฌํฐ UI ์ปดํฌ๋ํธ ์
๋ ์ ๊ณตํฉ๋๋ค.
์ด๊ฑด ๊ฝค ๊ฐ๋ ฅํ๋ฐ, <Grid>
๋ก ๋ฐ์ํ ๋ ์ด์์์ ๋นํ์์ด ๊ตฌ์ฑํ ์๋ ์๊ณ
<TreeView>
๊ฐ์ ๊ฒฝ์ฐ, ๋ณต์กํ UI๊ตฌ์ฑ์ ๋นํธ์ธ ์ปดํฌ๋ํธ๋ก ํธํ๊ฒ ์์ฑํด๋ณผ ์ ์์ต๋๋ค
Tailwind CSS
tailwind css๋ utility-first CSS ํ๋ ์์ํฌ์ ๋๋ค.
Tailwind CSSย is a utility-first CSS framework for rapidly building modern websites without ever leaving your HTML.
๊ณต์์ฌ์ดํธ์์ ์ด๋ฐ ์๊ฐ๋ฅผ ํ ์ ๋๋ก, ์ด๋ ๊ฐ์ง ๋ง๊ณ ์ ๋นํ ํด๋์ค ๋ช ๊ฐ ๋ถ์ฌ์ ์คํ์ผ์ ์ ์ฉํ ์ ์๊ฒ ํ๋ค, ๋ผ๋ ๋ชฉํ๋ฅผ ๋๊ณ ์์ต๋๋ค.
์ค์ ๋ก๋ ์ปดํฌ๋ํธ์์ ๋ฐ๋ก ์ธ๋ผ์ธ์ผ๋ก ์คํ์ผ์ ์ฃผ๋ฅด๋ฅต ์จ๋๊ธฐ๋ง ํ๋ฉด ๋์
๋๋ค
<button className="bg-blue-500 text-white py-2 px-4 rounded hover:bg-blue-700">
Click Me
</button>
์ด๋ฐ ์์ผ๋ก, ๊ฐ๋จํ ์ ํธ๋ฆฌํฐ ํด๋์ค๋ฅผ ๋ช ๊ฐ ๋์ง๋์ง ๋ถ์ฌ์ ์คํ์ผ์ ์ ์ฉํฉ๋๋ค.
์๋ฅผ ๋ค์ด, "๊ธ์จ๋ ํฐ์์ด๋ฉด ์ข๊ฒ ์ด" => text-white
Tailwind CSS๋ฅผ ์ฌ์ฉํ๋๋ฐ ์กฐ๊ฑด๋ถ๋ก ์คํ์ผ์ ์ ์ฉํ๊ณ ์ถ๋ค๋ฉด
๊ฐ๋จํ, ์๋ฐ์คํฌ๋ฆฝํธ์ ํ
ํ๋ฆฟ ๋ฆฌํฐ๋ด ๋ฌธ๋ฒ์ผ๋ก ์ํ๋ ์๋ฆฌ์ ์ฝ๊ฒ ๋์ ์ผ๋ก ์ ํธ๋ฆฌํฐ ํด๋์ค๋ฅผ ๋ฃ์ ์ ์์ต๋๋ค
<button
className={`bg-blue-500 ${theme === "DARK" ? "text-white" : "text-black"}`}
>
Click Me
</button>
์ด๋ ๊ฒ์
์๋๋ฉด ๋ฌธ์์ด ๋ค์ + " text-white"
์ฒ๋ผ ๋ง๋ถ์ฌ์ ์คํ์ผ์ ๋น๋ํ ์๋ ์์ต๋๋ค
๋ฌผ๋ก ์ค๊ฐ์ค๊ฐ์ ๊ณต๋ฐฑ์ด ์ ๋ค์ด๊ฐ๊ฒ ํด์ฃผ๋๋ก ํฉ์๋ค
์ด๋ฐ ์์ผ๋ก ํ ์ ์๋ค๋ ๋ป
const buttonClassName = "rounded ";
if (selectedColor === "RED") buttonClassName += "bg-red-500 ";
if (selectedColor === "GREEN") buttonClassName += "bg-green-500 ";
if (selectedColor === "BLUE") buttonClassName += "bg-blue-500 ";
...
return <button className={buttonClassName}>Click Me</button>
๊ทธ๋ผ ๋ณต์กํ ์กฐ๊ฑด๋ฌธ์ด๋ผ๋ ๋ฌธ์ ์์ด ์ฃผ๋ฅด๋ฅต ๋ค ๊ฑฐ์ณ์ ๋ฌธ์์ด๋ก ์ฝ๊ฒ ๋น๋ํ๊ณ ๊ฝ์๋ฃ์ ์ ์์ต๋๋ค
์ฅ๋จ์
๋จ์ ์ผ๋ก๋..
๋งค์ฐ ๊ธด.. ๋์ฐํ๊ฒ ๊ธด ํด๋์ค์ด๋ฆ์ ๊ฐ๋ ์ปดํฌ๋ํธ๊ฐ ๋ฑ์ฅํด๋ฒ๋ฆฝ๋๋ค ;; ๋ง ์ฐ๋ค๋ณด๋ฉด ์๊ฐ๋ณด๋ค ๊ธธ์ด์ ธ์.
๊ทธ๋ฆฌ๊ณ ๋ฌผ๋ก ๋ชจ๋ ๋์์ธ์ ์ํด ์์ ๋ ์ ํธ๋ฆฌํฐ ํด๋์ค๋ค์ด์ง๋ง, ๊ทธ๋งํผ ์์ ๋๊ฐ ๋จ์ด์ง๋๋ค
์ฅ์ ์ผ๋ก๋..
๊ทธ๋๋ ์์ ์๋ฆฌ์์ ์คํ์ผ์ ๋ชจ๋ ํด๊ฒฐํ ์ ์๊ณ , ์์ ๋ ๋ชจ๋ ์คํ์ผ์ฉ ์ ํธ๋ฆฌํฐ ํด๋์ค๋ค์ด๋ผ ์๊ทผ ํธํ๊ฑด ๋ง์ต๋๋ค.
์ ํธ๋ฆฌํฐ ํด๋์ค๋ค์ ์ข ์ฐ๋ค๋ณด๋ฉด ์๊ทผํ ์ต์ํด์ ธ์ ๊ฝค ๋น ๋ฅด๊ฒ ์คํ์ผ์์
์ ์งํํ ์ ์์ต๋๋ค
์ง์ง ์ด๊ฒ๋ง ์ฐ๋ฉด์ ํ ๋ช ์ฃผ ์ง๋๋ฉด? ๋๋ ๋ฉฐ์น ๋ด๋ก? ์์ ํ ์์ฐ์ฑ์ด ์์ฒญ๋์ง ๊ฒ ๊ฐ๋ค๋ ๋๋์ด ๋ค์์ต๋๋ค
๊ทผ๋ฐ ์ด๊ฑด ๊ณง ๋จ์ ์ด ๋ ์ ์์ด์
์๋กญ๊ฒ ๋ฐฐ์์ผ ํ ๊ฒ ์๊ธด๋ค๋ ๋ป์ด๊ณ , ์ถ๊ฐ์ ์ธ ๋ฌ๋ ์ปค๋ธ๊ฐ ์กด์ฌํ๋ ์
์
๋๋ค
CSS๋ง ์๋ฉด ๋์ง ๋ ๊ฐ๊ฐ์ ์ ํธ๋ฆฌํฐ ํด๋์ค๋ค์ ์ธ์ฐ๋ ค๋ฉด ์ฑ์ฐ์ฆ๋ ์ ์์ด์
์ ๋ ์ปดํฌ๋ํธ์ ์ฌ์ฌ์ฉ์ฑ์ด ๋จ์ด์ง๋ค๊ณ ์๊ฐํ๋๋ฐ, ์ฌ์ค ๊ทธ๋ ์ง๋ ์์ ๊ฒ ๊ฐ์์. ์คํ๋ ค ๋ ์ฉ์ดํ ์๋ ์๊ฒ ๋ค๋ ์๊ฐ์ ํฉ๋๋ค
๋ฏธ๋ฆฌ ๊ณตํต๋ฒํผ๊ฐ์ ์ฌ์ฌ์ฉ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค์ด๋๊ณ , ์ด๊ฑธ ๋ถ๋ฆฌํด๋ ๋ค์์, ๋์ค์ ๊ฐ๋ค ์ฐ๊ณ ํ์์ ๋ฐ๋ผ ํด๋์ค์ด๋ฆ์ ๋ ๊ฑฐ๊ธฐ๋ค ๋ง๋ถ์ฌ์ ์คํ์ผ์ ์ปค์คํ
ํ ์๋ ์๊ฒ ์ต๋๋ค
CSS-in-JS ์ฑ๋ฅ์ ๋ํ ๊ดด์๋ฌธ์ ์ง์ง์ธ๊ฐ์?
CSS-in-JS๋ ํธํ์ง๋ง ์ต์ข
์ ์ผ๋ก๋ runtime์ ์ด๋ฅผ ๋ณํํด์ฃผ๋ ์์
์ด ํ์ํฉ๋๋ค
์ด๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ๋ค๊ณผ๋ ๋ค๋ฅด๊ฒ ์ฑ๋ฅ ์ค๋ฒํค๋๋ฅผ ์ ๋ฐํ ์ ์์ต๋๋ค
๋ผ๋ ์ด์ผ๊ธฐ๊ฐ ์์ด์, ํ๋ฒ ๊ฐ๋จํ ํ์ธํด๋ดค์ต๋๋ค.
๊ฐ๋จํ ์ฑ๋ฅ ํ ์คํธ๋ฅผ ์ํ ์ธํ
๊ฐ๋จํ ์ฝ๋๋ค์ ์์ฑํ ๊ฑด๋ฐ, ๋ณ ์ ๊ฒฝ์ฐ์ง ์๊ณ ๊ฒฐ๊ณผ๋ง ๋ณด์ ๋ ๋ฉ๋๋ค
import { useState } from "react";
export default function VanilaTest() {
const [isActive, setIsActive] = useState(false);
return (
<div>
<button onClick={() => setIsActive(prev => !prev)}>
Toggle Active State
</button>
<TestArea isActive={isActive} />
</div>
);
}
function TestArea({ isActive }) {
return (
<div className={`test-element ${isActive ? "active" : "inactive"}`}>
Vanila CSS Test
{isActive && <div className="status-badge">Active!!</div>}
</div>
);
}
.test-element {
width: 300px;
height: 200px;
background-color: lightgray;
border-radius: 10px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 20px;
font-weight: bold;
color: #333;
transition: all 0.3s ease;
}
.test-element.active {
background-color: lightcoral;
color: white;
}
.test-element.inactive {
background-color: lightblue;
color: darkblue;
}
.status-badge {
margin-top: 10px;
padding: 5px 10px;
background-color: orange;
color: white;
border-radius: 5px;
font-size: 14px;
}
๊ทธ๋ฅ vanila CSS๋ฅผ ์ฌ์ฉํ๋ VanilaTest
์ปดํฌ๋ํธ๋ฅผ ์์ ๊ฐ์ด ์์ฑํ๊ณ
import { useState } from "react";
import styled from "@emotion/styled";
export default function EmotionTest() {
const [isActive, setIsActive] = useState(false);
return (
<div>
<button onClick={() => setIsActive(prev => !prev)}>
Toggle Active State
</button>
<TestElement isActive={isActive}>
Emotion Test
{isActive && <StatusBadge>Active!!</StatusBadge>}
</TestElement>
</div>
);
}
const TestElement = styled.div`
width: 300px;
height: 200px;
background-color: ${props => (props.isActive ? "lightcoral" : "lightblue")};
border-radius: 10px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 20px;
font-weight: bold;
color: ${props => (props.isActive ? "white" : "darkblue")};
transition: all 0.3s ease;
`;
const StatusBadge = styled.div`
margin-top: 10px;
padding: 5px 10px;
background-color: orange;
color: white;
border-radius: 5px;
font-size: 14px;
`;
CSS-in-JS ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ธ emotion์ ์ฌ์ฉํ๋ EmotionTest
์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค์์ด์
๋น๊ต์ ๋์์ด ๋ ๊น ์ถ์ด ์ผ๋ถ๋ฌ ์คํ์ผ ์ค๋ ๋ง์ด ๋ฃ๊ณ , ์กฐ๊ฑด๋ถ ์คํ์ผ๋ ์ถ๊ฐํด๋ฒ๋ ธ์ต๋๋ค.
์ด์ ๋๋ฉด ์กฐ๊ฑด์ ๋๊ฐ๊ฒ ์ฃ ?
์, Tailwind๋ ๊ฐ์ด ํด๋ณด๊ณ ์ถ์ด์ ธ์ TailwindTest
๋ ๋ง๋ค์์ต๋๋ค
export default function TailwindTest() {
const [isActive, setIsActive] = useState(false);
return (
<div>
<button onClick={() => setIsActive(prev => !prev)}>
Toggle Active State
</button>
<TestArea isActive={isActive} />
</div>
);
}
function TestArea({ isActive }) {
return (
<div
className={`flex flex-col items-center w-[300px] h-[200px] rounded-lg shadow-lg justify-center text-xl font-bold transition-all duration-300 ${
isActive
? "bg-[lightcoral] text-white"
: "bg-[lightblue] text-[darkblue]"
}`}
>
Tailwind Test
{isActive && (
<div className="mt-2 px-4 py-2 bg-[orange] text-white rounded-lg text-sm">
Active!!
</div>
)}
</div>
);
}
์ฒ์์๋ ๋ฐ๋ก TestArea
๋ฅผ ๋ถ๋ฆฌํ์ง ์์๋๋ฐ,
๋์ค์ ์๊ฐํด๋ณด๋ Emotion์ ์ปดํฌ๋ํธ ํ๋ ๋ ๋บ ์
์ด๋๊น Emotion๊ฐ ๋ ๋ถ๋ฆฌํ๋ ค๋? ์ถ์ด์,
์คํ์ผ์ด ์ ์ฉ๋ ์์ญ์ Vanila์ Tailwind์์๋ ๋ณ๋์ ์ปดํฌ๋ํธ๋ก ๋ถ๋ฆฌํ์ต๋๋ค
์ด์ ์ด ์ปดํฌ๋ํธ๋ค์ ์ ๋นํ ์ ๋์ดํ์ต๋๋ค
function App() {
return (
<>
<VanilaTest />
<br />
<EmotionTest />
<br />
<TailwindTest />
</>
);
}
์ฑ๋ฅ ํ ์คํธํด๋ณด๊ธฐ
์ด์ React Dev Tools - Profiler๋ฅผ ์ผ๊ณ , ์ฒซ ๋ ๋๋ง์ FlameGraph๋ฅผ ์ดํด๋ด ์๋ค
VanilaTest, EmotionTest, TailwindTest
๊ฐ๊ฐ์ด ์ฌ์ด๋๊ฒ ์ด๊นจ๋๋ฌดํ๊ณ ์๋ค์
๊ทผ๋ฐ ๋ฑ๋ด๋ Emotion์ ์ด๊นจ๊ฐ ๋๋ฌด ๋์ต๋๋ค
์์ฒญ๋ ์ฐจ์ด๋ฅผ ๋ณด์ฌ์ฃผ๋ค์..
๋๋ฌด ๊ฐ๋จํ ์ฑ๋ฅํ
์คํธ๋ผ์ ์ ํํ ์ด๋์ ๋ ์์น์ ์ฐจ์ด๊ฐ ๋๋ค, ๋ฅผ ๊ฒฐ๋ก ์ง๊ธฐ๋ ์กฐ์ฌ์ค๋ฝ์ต๋๋ค๋ง
div (Styled)
๊ฐ ํ์คํ ๋ ๋๋ง ์ฑ๋ฅ์ด ์ ์ข์ ๊ฒ์ ์ ์ ์์ต๋๋ค
๋ฒํผ์ ํ ๊ธํด์ ๋ฆฌ๋ ๋๋ง ์ฑ๋ฅ ํ๋กํ์ผ๋ง๋ ํ๋ฒ ํด๋ณด๊ฒ ์ต๋๋ค
<Profiler>
๋ก ์ธ ๊ฐ์ ํ
์คํธ ์ปดํฌ๋ํธ๋ค์ ๊ฐ์ธ์ ํ๋กํ์ผ๋ง ๋ก๊ทธ๋ฅผ ๋ชจ์ ์ ์๋๋ฐ
์๋์ ๊ฐ์ด ์ฝ๋๋ฅผ ์ง์คฌ์ต๋๋ค.
// ์ฑ๋ฅ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ๊ฐ์ฒด (๊ฐ id ๋ณ๋ก ์ฑ๋ฅ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅ)
const performanceData = {};
// onRender ์ฝ๋ฐฑ ํจ์
function onRenderCallback(
id,
phase,
actualDuration,
baseDuration,
startTime,
commitTime
) {
// ํด๋น id์ ๋ํ ์ฑ๋ฅ ๋ฐ์ดํฐ๊ฐ ์์ผ๋ฉด ์ด๊ธฐํ
if (!performanceData[id]) {
performanceData[id] = {
count: 0,
totalActualDuration: 0,
minActualDuration: Infinity,
maxActualDuration: 0
};
}
// ํด๋น id์ ๋ํ ์ฑ๋ฅ ๋ฐ์ดํฐ๋ฅผ ์
๋ฐ์ดํธ
const data = performanceData[id];
data.count += 1;
data.totalActualDuration += actualDuration;
data.minActualDuration = Math.min(data.minActualDuration, actualDuration);
data.maxActualDuration = Math.max(data.maxActualDuration, actualDuration);
// ํ๊ท ๋ ๋๋ง ์๊ฐ ๊ณ์ฐ
const averageActualDuration = data.totalActualDuration / data.count;
const result =
`Profiler Data for ${id} (${phase} phase): \n` +
`Actual duration: ${actualDuration.toFixed(2)}ms \n` +
`Base duration: ${baseDuration.toFixed(2)}ms \n` +
`Total renders: ${data.count} \n` +
`Average actual duration: ${averageActualDuration.toFixed(2)}ms \n` +
`Min actual duration: ${data.minActualDuration.toFixed(2)}ms \n` +
`Max actual duration: ${data.maxActualDuration.toFixed(2)}ms \n`;
console.log(result);
}
function App() {
return (
<>
<Profiler id="vanila" onRender={onRenderCallback}>
<VanilaTest />
</Profiler>
<br />
<Profiler id="emotion" onRender={onRenderCallback}>
<EmotionTest />
</Profiler>
<br />
<Profiler id="tailwind" onRender={onRenderCallback}>
<TailwindTest />
</Profiler>
</>
);
}
์ด๋ ๊ฒ ํ๋ฉด onRender
props๋ก ๋ฑ๋กํ onRenderCallback
ํจ์๋ ๋งค๋ฒ ๋ ๋๋ง์ด ์ผ์ด๋ ๋๋ง๋ค ํธ์ถ๋๋ฉฐ
๊ฐ ์ปดํฌ๋ํธ์ id
์ ๋ฐ๋ผ ๊ฐ๊ธฐ ๋ฐ๋ก ์ ์ฅ๋๊ณ ์ ์ง๋ฉ๋๋ค
์ด์ ํ ๊ธ๋ฒํผ์ ๊ฐ๊ฐ 50๋ฒ์ฉ ๋๋ฅด๊ณ ์ฝ์๋ก๊ทธ๋ฅผ ๋ด
์๋ค
๋ ๋๋ง์ ํ๊ท ์ ์ผ๋ก ์์๋๋ ์๊ฐ(Average actual duration
)์..
- vanila CSS : 0.35ms
- Emotion : 0.48ms
- tailwind css : 0.27ms
Tailwind > Vanila CSS > Emotion ์์ผ๋ก ๋นจ๋๋ค์
์๊ฐ๋ณด๋ค Tailwind๊ฐ ์ข ๋น ๋ฆ
๋๋ค..
๊ทธ๋ฆฌ๊ณ ์๊ฐ๋ณด๋ค vanila CSS๊ฐ ์กฐ๊ธ ๋๋ฆด ๋๊ฐ ์๋ค์?
์ฌ๋ฐ๋ค์.. ์ฐ๊ตฌ๋ฅผ ์ข ๋ ํ๋ฉด ์ฌ๋ฐ์ ๊ฒ ๊ฐ์ต๋๋ค
์๋ฌดํผ ๊ฐ๋จํ ํ๊ฒฝ์์ ๊ฐ ๋ฐฉ๋ฒ๋ค์ ์ฑ๋ฅ์ ๋น๊ตํ๊ณ
CSS-in-JS๊ฐ ์ฑ๋ฅ์ด ์ ์ข๋ค๋ ๊ดด์๋ฌธ์ด ์ง์ง์ธ์ง ํ์ธํด๋ดค์ต๋๋ค
๊ฝค๋ ์ง์ง์ธ ๊ฒ์ฒ๋ผ ๋ณด์ด๋ค์. ํ์คํ ๋ฐํ์ ๋ณํ์ด ํ์ํ๋๊น ๊ทธ๋ด๋ง ํ๊ณ ์
๊ฐ๋จํ ์์ ๋ก ํ์ธํ๋๋ฐ, ํ๋ก์ ํธ๊ฐ ์ปค์ง์๋ก ํฐ ์ด์๋ก ๋ค๊ฐ์ฌ ์๋ ์๊ฒ ์ต๋๋ค
๊ทธ๋ฆฌ๊ณ ํน์ดํ ๊ฒ์, Emotion ์ผ์ด์ค์ ๋ํ ํ๋กํ์ผ๋ง ๊ฒฐ๊ณผ์์
Insertion
์ด๋ผ๋.. ์ ๊ฐ ์ถ๊ฐํ์ง๋ ์์ ์ปดํฌ๋ํธ๊ฐ ์์ต๋๋ค
์คํ์ค๋ฒํ๋ก์ฐ๋ฅผ ์ด์ง ์ฐพ์๋ดค๋๋ฐ, emotion์ ์คํ์ผ๋ง ์ํธ๋ฆฌํฌ์ธํธ์ ํด๋นํ๋ ์ปดํฌ๋ํธ๋ผ๊ณ ํด์
์ธ์ ๊ฐ ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฐ๋จํ ํ๋ฒ ๋ฏ์ด๋ณด๋๊ฒ๋ ์ฌ๋ฐ์ ๊ฒ ๊ฐ์ต๋๋ค.
๊ฒฐ๋ก ?
AI์น๊ตฌ์๊ฒ ์์ฝํด๋ฌ๋ผ๊ณ ํด๋ดค์ต๋๋ค.
๊ฒฐ๋ก ์..
์ ๋ผ๋ฉด
๋ค๋ฅธ ๋ณ๋์ ์์กด์ฑ ์์ด ๊ฐ๋ณ๊ฒ ๊ฐ๊ณ ์ถ๋ค๋ฉด CSS Modules๋ฅผ ์ ํํ๊ฒ ์ต๋๋ค. CSS์ ๊ณ ์ง์ ์ธ ๋ฌธ์ ๋ฅผ ์ถฉ๋ถํ ํด๊ฒฐํด์ค ์ ์์ด์
Emotion๊ฐ์ CSS-in-JS๋ ๋ณต์กํ ํ์
์ด ์์ ๋ ์ฌ์ฉํ๊ธฐ ์ข์ ๊ฒ ๊ฐ๋ค์. ๋ค๋ฅธ์ฌ๋๋ค ์ฝ๋๋ฅผ ์๋งจํฑํ๊ฒ ์์๋ณผ ์ ์๋๊ฒ ์ฅ์ ์
๋๋ค
ํนํ Emotion์ ์ ํจ๊ปํ ๋ ๋ํ ๊ฐ๋ ฅ(MUI ์คํผ์
)ํด์, ๋์ ๊ฐ์ด ์ฌ์ฉํ ๋ ์ฅ์ ์ด ๋ง์ต๋๋ค.
๋์ ์ ์ฑ๋ฅ์ ๊ทนํ๊น์ง ์๊ปด์ผ ํ๋ ํ๋ก์ ํธ๋ผ๋ฉด ์ฌ๊ณ ํ ํ์๊ฐ ์๊ฒ ์ต๋๋ค
๋ง์ฝ ๋์์ธ๊ฐ์๊ฑฐ์ ์ ๊ฒฝ์ธ ๊ฒจ๋ฅผ์ด ์์ด ๋น ๋ฅธ ๊ฐ๋ฐ์ด ํ์ํ๋ฉด, MUI๋ ๋ค๋ฅธ UI๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ฉด ์ข์ ๋ฏ ํฉ๋๋ค.
๋ง์ ๋นํธ์ธ ์ปดํฌ๋ํธ๋ก ๋น ๋ฅด๊ฒ ๊ฐ๋ ฅํ UI๋ฅผ ๊ตฌ์ฑํ ์ ์๊ฒ ๋์์ค๋๋ค
์ ๋นํ ํ์๋ค๊ณผ ์์ํด์ ํ๋ก์ ํธ์ ์ ์ ํ ํ
๋ง๋ง์ ๊ณ ๋ฅด๋ฉด ๋๊ฒ ์ฃ
์ ๋ ํด์ปคํคํ ๋ ๊ทธ๋์ MUI๋ฅผ ์ ํํ์ต๋๋ค.
Tailwind๋ก๋ ๋น ๋ฅด๊ฒ ๋์์ธ์ ํด๊ฒฐํ ์ ์์ต๋๋ค. ์ ์ด์ ๊ทธ๋ฌ๋ ค๊ณ ๋ง๋ค์ด์ก๊ณ ์
๊ทธ๋ฆฌ๊ณ ์์์ ์ดํด๋ณธ ๊ฒ์ฒ๋ผ, ์ฑ๋ฅ์ (vanila CSS๋ณด๋ค๋??) ๊ฝค ํฐ ์ด์ ์ด ์์ต๋๋ค
๋ฒ๋ค์ฌ์ด์ฆ๋ ์ด๋จ๊น? ์ถ์ด์ ์ด์ง ์ฐพ์๋ดค๋๋ฐ, ๋น๋์์ Tailwind ๋ด๋ถ์์ ํ์์๋ CSS๋ผ์ธ๋ค์ ์ ๋ฆฌํด์ฃผ๊ธฐ ๋๋ฌธ์ ๋ฒ๋ค ์ฌ์ด์ฆ๋ ๊ฒฝ๋์ด๋ผ๊ณ ํ๋ค์
๋งค์ฐ ๊นํธ์ฒ๋ผ ์ฌ์ฉํ ์ ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ์ต๋๋ค
๋์ ํ์
ํ ๋๋ ์์๋ณด๊ธฐ ํ๋ค ์๋ ์๊ฒ ๋ค์.
์ด๋ฌํ ์ ๋ค์ ๊ณ ๋ คํด์ ์ํฉ์ ๋ง๊ฒ ์ฌ์ฉํ์๋ฉด ์ข์ ๊ฒ ๊ฐ์ต๋๋ค
์ ๊ณ ๋ฏผ๋ค์ด ์กฐ๊ธ์ด๋๋ง ๋์์ด ๋์์ผ๋ฉด ํ๋ค์
์ํด.. ์๋ ์ด๋ ๊ฒ๊น์ง ๊ธธ๊ฒ ์ธ ์๊ฐ์ด ์๋์๋๋ฐ
์ฑ๋ฅ ํ
์คํธ ํ๋ฒ ํด๋ณด๋ ค๋ค๋ณด๋๊น ์์ฌ์ด ๋์ ๊ฝค ๊ธธ๊ฒ ์ผ์ต๋๋ค
๊ทธ๋๋ ์ฌ๋ฐ์๋ค์
์ด๋ง ๋ง์นฉ๋๋ค