들어가며
기존에는 styled-components로 스타일링을 작성했었고, 이를 가져와 사용했습니다.
import styled from 'styled-components';
export const Wrapper = styled.div`
display: flex;
justify-content: center;
width: 100%;
height: 70px;
background: #fff;
box-shadow: 0 4px 15px 0 rgba(0, 0, 0, 0.15);
`;
export const ContentWrapper = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
height: 100%;
max-width: 1080px;
`;
각 스타일을 담당하는 태그들에 이름이 붙여져서 가독성은 좋았지만 반응형, 다크모드 등 다양한 처리를 할 때 불편함이 있어서, 가독성을 살리면서도 쉽게 스타일링을 붙일 수 있는 방법은 없을까 고민했습니다. 🤔
Utility-first css ?
utility-first CSS는 각 class가 담당할 스타일을 미리 정의하고 필요한 class들을 조합해서 적용하는 식으로 사용할 수 있습니다.
예시
width과 padding으로 간단한 예시를 들어보자면 아래와 같습니다.
- w-full : width: 100%; 와 동일하게 적용한다.
- pl-3 : padding-left 값을 '3'에 해당하는 정의된 속성에 따라 적용한다.
- w-24: width 값을 '24'에 해당하는 정의된 속성에 따라 적용한다.
tailwindcss는 이러한 utility-first CSS를 기반으로 만들어진 프레임워크인데요,
다크모드, 반응형 등을 클래스 이름만으로 정의해줄 수 있습니다.
<p className='bg-slate-900 text-white py-2 text-sm text-center'>
{"저는 p 태그 입니다."}
</p>
또한 기본 속성이 아니더라도 커스텀을 통해 원하는 속성을 정의해줄 수 있어 사용에 편리하다는 느낌을 받았습니다.
/** @type {import("tailwindcss").Config} */
module.exports = {
content: ['./src/**/*.{js,ts,jsx,tsx}'],
theme: {
extend: {
spacing: { // 지정해준 커스텀 속성들
70: '70px',
72: '72px',
100: '100px',
1080: '1080px',
},
maxWidth: {
1080: '1080px',
},
},
},
plugins: [],
};
✅ twin.macro
이렇게 tailwindcss는 여러 장점이 있지만 인라인으로 클래스 이름을 주입해야해서 코드가 깔끔해지지 않을 수 있다는 것, 구조의 의도를 알기가 어렵다는 것이 개인적으로는 큰 단점으로 느껴졌습니다. 그러나, twin.macro를 사용하면 CSS-in-JS와도 함께 tailwindcss를 사용할 수 있습니다.
그렇다면 styled-components? emotion?
styled-components과 emotion이 비슷한 기능을 제공해주고 있습니다. 번들 사이즈는 둘 다 비슷한데, emotion에서 더 편한 css props 기능을 제공해주고 있기 때문에 tailwindcss + emotion 조합을 사용해보도록 합시다.
Installation
GitHub - ben-rogerson/twin.examples: Packed with examples for different frameworks, this repo helps you get started with twin a
Packed with examples for different frameworks, this repo helps you get started with twin a whole lot faster. - GitHub - ben-rogerson/twin.examples: Packed with examples for different frameworks, th...
github.com
위 링크에 CRA + emotion + twin 조합에서의 간략한 이용 방법이 담겨 있으니, 참고하시면 좋을 것 같아요.
$ npm install twin.macro tailwindcss @emotion/react @emotion/styled
혹은
$ yarn add twin.macro tailwindcss @emotion/react @emotion/styled
tailwindcss 시작하기
다음과 같은 명령어로 tailwindcss에 필요한 config 파일들을 만들어낼 수 있습니다.
$ npx tailwindcss init -p
그 후, 내용물들의 경로를 지정해줍니다. src안에 소스코드들이 있으므로 아래와 같이 작성해줬습니다.
📂 tailwind.config.js
/** @type {import("tailwindcss").Config} */
module.exports = {
content: ['./src/**/*.{js,ts,jsx,tsx}'],
theme: {},
plugins: [],
};
그 다음, global하게 적용되는 css 파일에 다음과 같이 작성하면 준비 끝!
📂 global.css or index.css
@tailwind base;
@tailwind components;
@tailwind utilities;
twin config 추가하기 (optional)
a) Either in babel-plugin-macros.config.js:
// babel-plugin-macros.config.js
module.exports = {
twin: {
preset: 'emotion',
},
}
b) Or in package.json:
// package.json
"babelMacros": {
"twin": {
"preset": "emotion"
}
},
컴포넌트 작성 예시
emotion 혹은 styled-components를 작성했던 것처럼 tw를 이용해 가독성 좋게 작성할 수 있습니다.
import tw from 'twin.macro';
export const Wrapper = tw.div`
flex justify-center
w-full h-70
bg-white shadow-md
`;
export const ContentWrapper = tw.div`
flex justify-between items-center
w-full h-full
max-w-1080
`;
📂 tailwind.config.js
아래와 같이 커스텀 옵션 필요하면 추가할 수 있고, 이제 기본 속성에 정의되지 않아 h-[70px]와 같이 사용되었던 클래스 이름을 h-70처럼 사용할 수 있게 됩니다.
/** @type {import("tailwindcss").Config} */
module.exports = {
content: ['./src/**/*.{js,ts,jsx,tsx}'],
theme: {
extend: {
spacing: {
70: '70px',
72: '72px',
100: '100px',
1080: '1080px',
},
maxWidth: {
1080: '1080px',
},
},
},
plugins: [],
};
또한 필요에 따라 다음과 같이 twin.macro의 기본 타입을 지정해 적용해줄 수도 있습니다.
📂 types/twin.d.ts
// 'twin.macro'에서 가져온 함수와 '@emotion/styled'에서 가져온 함수를 사용할 수 있도록 import합니다.
import 'twin.macro';
import styledImport from '@emotion/styled';
import { css as cssImport } from '@emotion/react';
import { CSSInterpolation } from '@emotion/serialize';
// 'twin.macro' 모듈을 확장하여 Emotion 관련 함수들을 사용할 수 있도록 선언합니다.
declare module 'twin.macro' {
// 'css' 함수를 'cssImport' 함수와 동일한 타입으로 사용할 수 있도록 합니다.
const css: typeof cssImport;
// 'styled' 함수를 'styledImport' 함수와 동일한 타입으로 사용할 수 있도록 합니다.
const styled: typeof styledImport;
}
// 'react' 모듈을 확장하여 React 요소의 타입을 확장합니다.
declare module 'react' {
// DOMAttributes 인터페이스에 'tw'와 'css' 속성을 추가합니다.
interface DOMAttributes<T> {
// 'tw' 속성은 문자열 값을 가질 수 있습니다. 이는 'twin.macro'의 특별한 스타일링 기능을 사용할 때 사용됩니다.
tw?: string;
// 'css' 속성은 Emotion의 스타일 객체를 가질 수 있습니다.
css?: CSSInterpolation;
}
}
📂 package.json
// ...
"include": [ "src", "types" ]
Results
마무리하며
tailwindcss와 twin.macro를 사용해본 결과, 문법에 익숙해지는 순간부터는 확실히 작업 속도에 대한 장점을 얻을 수 있었습니다. 또한 Next.js와 같이 서버 사이드 렌더링을 많이 사용하는 현재 CSS-in-JS의 필요성에 대해서도 많은 논의가 있는 요즘, 필요한 상황마다 적절히 쓸 수 있게 여러 툴을 사용해보는 것도 괜찮은 것 같아요.
결론은.. 프로젝트 사이즈가 많이 커지기 전에 마이그레이션해서 다행이고, styled-compenents와 인터페이스가 꽤나 비슷했던 탓인지 편한 이주였던 것 같습니다.
'프로젝트 기록' 카테고리의 다른 글
[React-draggable-selector] 셀렉터 라이브러리 제작하기 (4) - v2.1.1 업데이트 (2) | 2023.08.24 |
---|---|
[React-draggable-selector] 셀렉터 라이브러리 제작하기 (3) - npm 배포하기 (0) | 2023.08.16 |
[React-draggable-selector] 셀렉터 라이브러리 제작하기 (2) - 코드 톺아보기 (0) | 2023.08.16 |
[React-draggable-selector] 셀렉터 라이브러리 제작하기 (1) - 개요 및 기능탐색 (0) | 2023.08.12 |
[Meetable] Draggable-time-selector 구현기 (with REACT, TS) (4) | 2023.08.01 |