지금까지 여러방법으로 스타일링을 진행하였다. 가장 일반적인 방법으로는 CSS, Module CSS, SaSS 그리고 요즘들어 가장 간편하게 사용하고 있는 TailwindCSS, 마지막으로 간단하게 JS파일에 작성하는 Styled Components가 있었다.
코드를 작성하다보면 항상 느꼈던 점이 있다. Tailwind CSS
는 Utlity Fisrt컨셉을 가진 프레임워크라 내가 원하는 디자인에 대해 찾아서 그대로 작성만 하면 돼서 정말 편하게 사용했다. 하지만, 태그안의 className에 모두 작성을 하다보니 은근 코드가 길어지고 가독성이 떨어졌었다.
반면, Styled Components (or Emotion)
를 사용할 때는 하나의 파일 안에서 별도의 코드로 스타일링을 작성할 수 있다는 장점이 있지만, 일반적인 CSS 문법을 이용해야해서 내가 원하는 디자인을 구현하려면 Tailwind에 비해서 접근성이 떨어졌었다.
그래서, TailwindCSS 와 Styled Components를 합친 기능은 없을까 라는 생각을 하게 되었고, twin marco
가 나의 고민을 해결해 줄 것 같다.
👍 twin marco
공식 문서에 따르면 다음과 같이 소개한다.
: The magic of Tailwind with the flexibility of css-in-js.
(css-in-js의 유연성과 Tailwind의 마법같은 기능들?)👉 공식문서
간단하게 말하면, Styled Components
와 Emotion
기능에 TailwindCSS
도 사용이 가능하다고 알면 될거 같다. 자세한 사용법은 직접 코드를 작성하며 알아보자~
twin marco는 emotion
, styled-component
라이브러리에 대해 의존성을 가지기 때문에 별도의 설치가 필요하고, 설정해야할 것들이 꽤 있다.
✅ Install
"dependencies": {
"@emotion/react": "^11.10.5",
"@emotion/styled": "^11.10.5",
"styled-components": "^5.3.6"
},
"devDependencies": {
"@babel/core": "^7.20.5",
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.18.6",
"@emotion/babel-preset-css-prop": "^11.10.0",
"@tailwindcss/typography": "^0.5.8",
"babel-loader": "^9.1.0",
"babel-plugin-macros": "^3.1.0",
"babel-plugin-twin": "^1.1.0",
"tailwindcss": "^3.2.4",
"twin.macro": "^3.1.0",
"typescript": "^4.9.4",
"webpack": "^5.75.0",
"webpack-cli": "^5.0.1",
"webpack-dev-server": "^4.11.1"
},
✅ Preset
// babelrc
{
"presets": [
"@babel/preset-env",
["@babel/preset-react", { "runtime": "automatic" }],
"@emotion/babel-preset-css-prop",
"@babel/preset-typescript"
],
"plugins": ["babel-plugin-twin", "babel-plugin-macros"]
}
// package.json
"babelMacros": {
"twin": {
"preset": "emotion"
}
}
✅ .d.ts 파일
// types/twin.d.ts
import 'twin.macro'
import { css as cssImport } from '@emotion/react'
import styledImport from '@emotion/styled'
import { CSSInterpolation } from '@emotion/serialize'
declare module 'twin.macro' {
// The styled and css imports
const styled: typeof styledImport
const css: typeof cssImport
}
declare module 'react' {
// The tw and css prop
interface DOMAttributes<T> {
tw?: string
css?: CSSInterpolation
}
}
💡 d.ts 파일
타입스크립트 선언 파일 d.ts는 타입스크립트 코드의 타입 추론을 돕는 파일.예를 들어, 전역 변수로 선언한 변수를 특정 파일에서 import 구문 없이 사용하는 경우 해당 변수를 인식하지 못합니다. 그럴 때 아래와 같이 해당 변수를 선언해서 에러가 나지 않게 할 수 있습니다.
✅ tsconfig.json
// tsconfig.json
{
"compileOptions:{
...
"jsxImportSource": "@emotion/react"
},
"include":["types"]
}
✅ tailwind.config.js
// tailwind.config.js
module.exports = { // 사용자 설정 및 지원하지 않는 기능 가져오기
theme: {
extend: {
colors: {
electric: "#db00ff",
ribbon: "#0047ff",
},
},
},
plugins: [],
};
✅ Emotion
// 1️⃣ SSR에서 별도의 설정 없이 동작 가능
// 2️⃣ typescript로 자동 타입지정
type ThemeType = keyof typeof themes;
type SizeType = keyof typeof size;
// 3️⃣ css props를 결합하여 복잡한 스타일링을 진행
<div css={[style, themes[theme], sizes[size]]} />
// 4️⃣ css props 기능
const themes = {
primary: css`
color: red;
`,
secondary: css`
color: blue;
`
}
const sizes = {
small: css`
fontSize: 0.75rem;
`,
medium: css`
fontSize: 1rem;
`
}
✅ Styled Components
const Circle = styled.div`
width: 5rem;
height: 5rem;
background: ${props => props.color || 'black'};
border-radius: 50%;
${props =>
props.huge &&
css`
width: 10rem;
height: 10rem;
`}
`;
function App() {
return <Circle color="red" huge />;
}
✅ Tailwind CSS
<button class="py-2 px-4 rounded-lg shadow-md text-white bg-blue-500">
Click me
</button>
👉 [React] emotion과 styled-component의 차이
👉 styled-components 과 emotion, 도대체 차이가 뭔가?
👉 Emotion 공식문서
👉 Styled Components 공식문서
👉 Tailwind CSS 공식문서
✅ taildwind CSS
+ 일반 CSS
조합
import tw, { css } from "twin.macro";
const styles = {
test: [tw`bg-green-400`, css`font-size: 30px`]
};
...
<button css={styles.test}>버튼</button>
✅ props 기능
const styles = { // 타입 지정
container: ({ hasBackground }: { hasBackground: boolean }) => [
tw`bg-red-400 items-center justify-center`,
hasBackground && tw`bg-green-400`,
]
};
...
// boolean값에 따른 조건부 스타일 지정
<div css={styles.container({ hasBackground: true })}>
...
</div>
✅ 컴포넌트 단위 스타일링
// component/Button.tsx
import tw, { styled, css, theme } from "twin.macro";
interface ButtonProps { // 타입 지정
variant?: "primary" | "secondary";
isSmall?: boolean;
}
const Button = styled.button(({ variant, isSmall }: ButtonProps) => [
// 1️⃣ 공통 버튼 스타일 설정
tw`px-8 py-2 rounded transform duration-75`,
// 2️⃣ 변형 스타일 설정
tw`hocus:(scale-105 text-yellow-400)`,
// 3️⃣ props에 따른 조건부 스타일 설정
variant === "primary" && tw`bg-black text-white border-black`,
// 4️⃣ 일반 CSS + Tailwind CSS 조합 가능
variant === "secondary" && [
css`
background-color: red;
`,
tw`border-2 border-yellow-600`,
],
// 5️⃣ props에 따른 조건부 스타일 설정
isSmall ? tw`text-sm` : tw`text-lg`,
// 6️⃣ tailwind.config.js에서 설정해놓은 값 가져오기
css`
color: ${theme`colors.white`};
`,
]);
export default Button;
// index.tsx
const Home = () => (
<>
<Button variant="primary">dd</Button>
<Button variant="secondary">dd</Button>
</>
);
아직까지는 익숙하지 않아서 조금은 스타일 구현 속도가 느리다. 하지만, 직접 사용해보고나니 훨씬 깔끔하게 사용할 수 있을 것 같다. 다른 스타일의 버튼을 구현할 때마다 늘 하나하나 스타일을 입혀줬는데 공통된 스타일도 지정 가능하고, props 기능들, tailwind 와 css를 조합하여 사용한다는 장점들이 존재해서 이번 기회에 진행 중인 프로젝트에 적용시켜봐야겠다!