Skip to content

Commit baab7ed

Browse files
committed
post : TailwindCSS 같은 디자인시스템 구축하기
1 parent 8d37472 commit baab7ed

File tree

2 files changed

+357
-1
lines changed

2 files changed

+357
-1
lines changed
Lines changed: 356 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,356 @@
1+
---
2+
title: TailwindCSS 같은 디자인시스템 구축하기
3+
date: 2023-04-21
4+
description: 디자인토큰을 만들고 class기반 디자인시스템을 구축해봅니다.
5+
category: other
6+
---
7+
8+
---
9+
10+
<div className="mokcha">
11+
<div className="mokcha-container">
12+
<h2>INDEX</h2>
13+
<a href="#1" className="mokcha-container__list">
14+
1. 디자인 시스템이란 뭐죠?
15+
</a>
16+
<a href="#2" className="mokcha-container__list">
17+
2. 디자인 토큰의 종류
18+
</a>
19+
<a href="#3" className="mokcha-container__list">
20+
3. TailwindCSS같은 디자인시스템 구축하기
21+
</a>
22+
</div>
23+
</div>
24+
25+
---
26+
27+
<h2 id="1"></h2>
28+
29+
<br></br>
30+
31+
<h2 id="1" className={`dark:text-white text-center`}>
32+
<div>1. 디자인 시스템이란 뭐죠?</div>
33+
</h2>
34+
35+
<br></br>
36+
37+
디자인 시스템은 간단하게 말해서 `MUI`, `TailwindCSS` 같은 통일된 디자인 색상, 타이포그래피, 여백, 그림자 등을 한곳에서 정리 및 관리를 통해서 디자이너, 개발자 간의 협업할 때 통합, 생산성을 높이기 위해서 사용되는 것이라고 생각하시면 됩니다. 이떄 색상, 타이포그래피... 등등을 정의한 CSS 변수를 <b>디자인 토큰</b>이라고 합니다.
38+
39+
<br></br>
40+
41+
<a
42+
className={`dark:text-white`}
43+
target="_blank"
44+
id="link"
45+
href="https://www.lightningdesignsystem.com/design-tokens/"
46+
>
47+
lightningdesignsystem design-tokens
48+
</a>
49+
50+
<a
51+
className={`dark:text-white`}
52+
target="_blank"
53+
id="link"
54+
href="https://m3.material.io/styles/color/overview"
55+
>
56+
https://m3.material.io/styles/color/overview
57+
</a>
58+
59+
<br></br>
60+
61+
위 사이트는 여러 회사에서 정의한 디자인 토큰을 설명하는 페이지입니다. 이렇게 회사마다 회사의 통일된 디자인을 유지보수하기 위해서 디자인 토큰을 정의하고 그것을 바탕으로 완성된 디자인 시스템을 사용합니다.
62+
63+
---
64+
65+
<h2 id="2"></h2>
66+
67+
<br></br>
68+
69+
<h2 id="2" className={`dark:text-white text-center`}>
70+
<div>2. 디자인 토큰의 종류</div>
71+
</h2>
72+
73+
<br></br>
74+
75+
회사마다 디자인 토큰의 정의하는 개념과 기준이 사람마다 다르지만 대체로 디자인 토큰을 3가지로 나누어 집니다.
76+
77+
<h3 className={`dark:text-white`}>1. Global tokens</h3>
78+
<br></br>
79+
80+
<div className="ml-div">
81+
82+
`Global tokens`는 가장 작은 단위의 디자인입니다. 예를 들어서 색상, 폰트 크기, 폰트 간격... 등등이 존재합니다. Global tokens를 어떤 곳에서는 `Foundation`이라고도 명칭 하기도 합니다.
83+
84+
```css
85+
--blue-300: blue // Global tokens;;
86+
```
87+
88+
</div>
89+
90+
<br></br>
91+
<h3 className={`dark:text-white`}>2. Alias tokens</h3>
92+
<br></br>
93+
94+
<div className="ml-div">
95+
96+
`Alias tokens`은 원자 단위의 Global tokens의 별칭을 지어주는 것입니다. 예를들어서
97+
98+
```css
99+
--blue-300 : blue // Global tokens
100+
101+
--background-color : var(--blue-300) // Alias tokens
102+
```
103+
104+
가장 기본이 되는 blue 색상은 Global tokens이 되며 Global tokens을 사용해 --background-color라는 Alias tokens을 생성할 수 있습니다.
105+
106+
</div>
107+
108+
<br></br>
109+
<h3 className={`dark:text-white`}>3. Components tokens</h3>
110+
<br></br>
111+
112+
<div className="ml-div">
113+
114+
`Components tokens`은 좀 더 확장된 개념인데 --background-color라는 Alias token을 사용해 특정 컴포넌트를 명시하는 이름으로 할당합니다.
115+
116+
```CSS
117+
--background-color : var(--blue-300) // Alias tokens
118+
119+
--btn-background-color : var(--background-color) // Components tokens
120+
```
121+
122+
--background-color 토큰을 사용해 btn 컴포넌트에서 쓰이는 Components tokens을 생성합니다.
123+
124+
</div>
125+
126+
---
127+
128+
<h2 id="3"></h2>
129+
130+
<br></br>
131+
132+
<h2 id="3" className={`dark:text-white text-center`}>
133+
<div>3. TailwindCSS같은 디자인시스템 구축하기</div>
134+
</h2>
135+
136+
<br></br>
137+
138+
간단하게 제가 구축한 디자인 시스템의 <b>순서</b>를 설명해겠습니다.
139+
140+
<br></br>
141+
142+
<div className={`step-by-step`}>
143+
144+
<h3>디자인 시스템 구축 순서</h3>
145+
146+
1. CSS 변수들을 사용해 디자인 토큰을 만듭니다.
147+
148+
2. 완성된 디자인 토큰 변수들을 style 태그 `:root` 안에 한 줄씩 작성해 head 태그 안에 삽입합니다.
149+
150+
3. 해당 디자인 토큰들을 가지고 css class를 생성합니다.
151+
152+
4. 완성된 class를 태그의 class에 삽입해 디자인을 적용합니다.
153+
154+
</div>
155+
156+
<br></br>
157+
<br></br>
158+
159+
<b>이제는 실제로 구축해 보겠습니다.</b>
160+
161+
<br></br>
162+
<h3 className={`dark:text-white`}>1. css 변수들을 사용해 디자인 토큰을 생성</h3>
163+
<br></br>
164+
165+
```ts:cssVariables.ts showLineNumbers
166+
export const cssVariables: CSSVariables = {
167+
168+
// Global token
169+
static_colors: {
170+
black: "#000000",
171+
white: "#ffffff",
172+
gray300: "#f6f6f6",
173+
blue600: "#0056b3",
174+
blue800: "#1f3764",
175+
},
176+
scale_font_sizes: {
177+
size10: "0.625rem",
178+
...
179+
}
180+
..
181+
.
182+
}
183+
184+
// Alias token & Components token
185+
cssVariables.semantic_colors = {
186+
background: cssVariables.static_colors.gray300,
187+
text: cssVariables.static_colors.black,
188+
btn_background: cssVariables.static_colors.blue800,
189+
btn_background_hover: cssVariables.static_colors.blue600,
190+
btn_text: cssVariables.static_colors.white,
191+
};
192+
.
193+
.
194+
195+
```
196+
197+
- cssVariables 객체안에 Global token을 할당합니다.
198+
199+
- Global token을 이용해 Alias token, Components token 들을 생성합니다.
200+
201+
<br></br>
202+
<h3 className={`dark:text-white`}>2. css 변수를 style태그안 :root 안 삽입</h3>
203+
<br></br>
204+
205+
```ts:injectCSSVariables.utils.ts showLineNumbers
206+
function createStyleTag(variables: CSSVariables): HTMLStyleElement {
207+
const styleTag = document.createElement("style");
208+
let root = ":root {\n";
209+
210+
for (const category in variables) {
211+
for (const variableName in variables[category]) {
212+
const replacedCategory = category.replace(/_/g, "-");
213+
const replacedVariableName = variableName.replace(/_/g, "-");
214+
const cssVariableName = `--${replacedCategory}-${replacedVariableName}`;
215+
const cssVariableValue = variables[category][variableName];
216+
root += ` ${cssVariableName}: ${cssVariableValue};\n`;
217+
}
218+
}
219+
220+
styleTag.textContent = root + "}";
221+
return styleTag;
222+
}
223+
224+
export default function injectCSSVariables(variables: CSSVariables): void {
225+
const styleTag = createStyleTag(variables);
226+
document.head.appendChild(styleTag);
227+
}
228+
229+
injectCSSVariables(cssVariables)
230+
```
231+
232+
- injectCSSVariables 함수에 css 토큰 객체를 매개변수로 실행합니다.
233+
234+
- createStyleTag함수로 style 태그를 생성합니다.
235+
236+
- cssVariables.ts 에서는 <b>"-"(하이픈)</b>을 사용할수없어서 <b>"\_"(언더바)</b>를 사용했기때문에 css규칙을 지키기 위해 정규표현식으로 하이픈을 언더바로 변환합니다.
237+
238+
- 최종적으로 `:root { --semantic-colors-background ... }` 형태로 저장됩니다.
239+
<br></br>
240+
241+
- styleTag를 <b>document.head</b>에 삽입합니다.
242+
243+
삽입된 토큰들 👇
244+
245+
<img
246+
width="50%"
247+
src="https://user-images.githubusercontent.com/75124028/232970681-7a6b5541-bd23-4349-9256-c043a2e9a146.png"
248+
/>
249+
250+
<br></br>
251+
<h3 className={`dark:text-white`}>3. css 클래스 생성</h3>
252+
<br></br>
253+
254+
```css:typography.css
255+
.semantic-typography-h1 {
256+
font-size: var(--semantic-typography-h1-font-size);
257+
font-weight: var(--semantic-typography-h1-font-weight);
258+
line-height: var(--semantic-typography-h1-line-height);
259+
letter-spacing: var(--semantic-typography-h1-letter-spacing);
260+
}
261+
262+
.semantic-typography-h2 {
263+
font-size: var(--semantic-typography-h2-font-size);
264+
font-weight: var(--semantic-typography-h2-font-weight);
265+
line-height: var(--semantic-typography-h2-line-height);
266+
letter-spacing: var(--semantic-typography-h2-letter-spacing);
267+
}
268+
...
269+
..
270+
.
271+
```
272+
273+
- css변수를 사용해 class를 생성합니다
274+
275+
<br></br>
276+
<h3 className={`dark:text-white`}>4. 실제 사용</h3>
277+
<br></br>
278+
279+
```ts:components/Layout/Header showLineNumbers
280+
export default function Header({ title }: HeaderProps) {
281+
return (
282+
<Styled.HeaderContainer>
283+
<Styled.HeaderTitle className="semantic-typography-title3-regular">
284+
{title}
285+
</Styled.HeaderTitle>
286+
</Styled.HeaderContainer>
287+
);
288+
}
289+
```
290+
291+
위 코드는 실제로 제가 기업의 사전과제중 구현해 사용한 실제 코드입니다.
292+
293+
이렇게 디자인 class를 적용했을때 크롬 개발자 도구로 검사하게되면 적용이 된 모습을 볼수 있습니다. 👇
294+
295+
<div className={`flex flex-col justify-center`}>
296+
<img
297+
src="https://user-images.githubusercontent.com/75124028/232972878-3c9a16b0-260b-47b3-bdf6-40f51f6ed5c5.png"
298+
width="100%"
299+
/>
300+
<img
301+
src="https://user-images.githubusercontent.com/75124028/232972885-cc696043-a782-49d6-bbf6-06fcb22a9968.png"
302+
width="100%"
303+
/>
304+
</div>
305+
306+
📌 참고로 `letter-spacing` 같은경우 아직 토큰을 생성 하지 않았습니다.
307+
308+
이렇게 tailwind와 같은 유틸리티 디자인 시스템을 구축 및 사용해보았습니다. 이렇게 사용하게 되면 컴포넌트 페이지에서 해당 엘리먼트가 어떤 식으로 생겼는지 실제 렌더링하지 않고도 이름에 명확히 명시가 되어있기 때문에 가독성이 좋아집니다. 중복된 코드들도 많이 줄어들게 되고요. 하지만 이런 class를 많이 사용하게 될 경우 또한 코드가 길어지기 때문에 좀 더 개선해야 한다고 생각합니다.
309+
310+
<br></br>
311+
312+
참고로 제가 디자인 토큰을 생성할때 사용한 css 변수 값들은 당근마켓 seed-design을 참고했습니다.
313+
314+
<a
315+
className={`dark:text-white`}
316+
target="_blank"
317+
id="link"
318+
href="https://github.com/daangn/seed-design/blob/main/packages/stylesheet/global.css"
319+
>
320+
https://github.com/daangn/seed-design/blob/main/packages/stylesheet/global.css
321+
</a>
322+
323+
---
324+
325+
<br></br>
326+
327+
<b>참고 문서</b>
328+
329+
<br></br>
330+
331+
<a
332+
className={`dark:text-white`}
333+
target="_blank"
334+
id="link"
335+
href="https://spectrum.adobe.com/page/design-tokens/"
336+
>
337+
https://spectrum.adobe.com/page/design-tokens/
338+
</a>
339+
340+
<a
341+
className={`dark:text-white`}
342+
target="_blank"
343+
id="link"
344+
href="https://gsretail.tistory.com/20"
345+
>
346+
https://gsretail.tistory.com/20
347+
</a>
348+
349+
<a
350+
className={`dark:text-white`}
351+
target="_blank"
352+
id="link"
353+
href="https://yozm.wishket.com/magazine/detail/1619/"
354+
>
355+
https://yozm.wishket.com/magazine/detail/1619/
356+
</a>

0 commit comments

Comments
 (0)