KHCDS 성공 기원 1일차
24/06/17 - 이든/ KHCDS 성공 기원 1일차
Intro
-
발표하기 전에 이전에 다뤘던 FSD는 다가오는 문제(디자인 시스템)가 더 급하다는 자기합리화를 하며…
머나먼 미래로,,,(아직 리펙을 못했어요ㅠㅠ)
-
번역 배포 전가하기는 실패로…(IP No answer…)
오늘 발표자료는 FEconf영상, 유료 강의, ‘이든 뇌피셜’의 결합입니다..
디자인 시스템
차크라: 오픈소스를 활용하는 개발자들이 유연하게 사용할 수 있는 라이브러리
스펙트럼: 어도비 제품군에 사용될 목적
디자인 토큰
Figma Variables을 진실의 원천으로 해서 출처를 한 곳으로 통일하자
아토믹 디자인이 혼란스러운 이유
컴포넌트만을 분류해서 달성하려 하면 실패한다
- 형태적 Atomic을 제공하는 스타일시트
- 기능적 Atomic을 제공하는 Headless 컴포넌트
분리해서 바라봐야 무엇이 Atom인가에 대한 혼란이 사라진다.
디자인 시스템의 구조는?
- 원칙 : 디자인과 개발의 핵심 가치 및 지침 (ex. chakra디자인 원칙)
- 테마 : 색상, 타이포그래피, 그리드, 스페이싱 같은 디자인 요소에 대한 지침 ⇒ CSS Variable을 이용해서 모든 css 프레임 워크 내에서 동작하도록 css로 제공 (ex. 어도비 디자인 시스템)
- 컴포넌트 : 버튼, 입력란, 탭, 모달 등 재사용 가능한 UI요소의 라이브러리 ⇒ React 기반으로 (Next, Remix, …) ⇒ zero-runtime stylesheet를 사용 (uanilla-extract) ⇒ 기능(headless ui)과 형태(디자인 토큰)를 분리
- 패턴 : 여러 컴포넌트를 결합하여 만들어진 복잡한 사용자 인터페이스 요소 ⇒ 합성 컴포넌트로 구현
- 도구 및 유틸리티 : 디자인 시스템을 실제 제품에 통합하기 위한 도구와 플러그인
- 문서화 : 디자인 시스템의 모든 요소를 사용하는 방법 문서화 ⇒ 스토리북
- 가이드라인 : 좋은 사용성, 접근성 등의 가이드와 권장사항들
- 프로세스 및 워크플로우 : 디자인 시스템 업데이트, 확장하는 것에 대한 프로세스(검토, 승인, … ) ⇒ 모노레포
디자인을 코드로
테마는 어떻게 만들까?
라이브러리를 만들때 어려운 것은 타겟이 불명확해서 여러 상황을 고려해야 한다
commonJS VC ES module
JS VC TS
즉, x.cjs, x.mjs, type.d.ts 를 만들어 줘야한다.
라이브러리는 브라우저(핫리로딩, 플러그인, …)와 달리 모듈 번들러의 속도, 최적화에 포커스를 맞춰야 한다.
따라서 css Variable을 통해서 각각의 테마를 모듈로 만들어서 모듈 번들러를 통해 빌드시에 생성하면 좋을 듯
TMI)
모듈 번들러로 esbuild를 사용하면 빠르게 빌드할 수 있다.
- esbuild는 매우 빠른 빌드 속도를 가지고 있다. (webpack 5보다 100배 정도 빠르다고 소개하고 있음)
- go로 작성됨
- 코드 파싱, 출력, 소스맵 생성 등을 병렬로 처리함
- 불필요한 데이터 변환, 할당 과정이 없음
- vite도 사전 번들링을 esbuild 기반으로 동작함
- 근데 인프라, 플러그인들의 제약이 있어서 product빌드시에는 rollup 사용한다고 함
현재 우리는 css variable을 통해 변수를 만들고 사용하고 있다.
하지만 매번 사용할 때 이 변수명을 기억해서 string으로사용해야 하는불편함이 있다.
⇒ 이거를 JS object로 만들어서 사용하면 추론도 되고 가독성도 향상될 것이다.
⇒ 이랬을경우 문제 동일한 속성을 css, js이렇게 관리의 주체가 두곳으로 분산되기 때문에 유지보수가 불편하다
⇒ 이거를 해결하기 위해 js기반으로 css를 만들도록 스크립트를 작성할 수 있다.
⇒ 매도 먼저 맞는게 덜 아플 수 있다ㅎ
-
스트립트 작업 예시
// color token (lightColor.js) export const whiteAlpha = { 50: "rgba(255, 255, 255, 0.04)", 100: "rgba(255, 255, 255, 0.06)", 200: "rgba(255, 255, 255, 0.08)", 300: "rgba(255, 255, 255, 0.16)", 400: "rgba(255, 255, 255, 0.24)", 500: "rgba(255, 255, 255, 0.36)", 600: "rgba(255, 255, 255, 0.48)", 700: "rgba(255, 255, 255, 0.64)", 800: "rgba(255, 255, 255, 0.80)", 900: "rgba(255, 255, 255, 0.92)", }; export const blackAlpha = { 50: "rgba(0, 0, 0, 0.04)", 100: "rgba(0, 0, 0, 0.06)", 200: "rgba(0, 0, 0, 0.08)", 300: "rgba(0, 0, 0, 0.16)", 400: "rgba(0, 0, 0, 0.24)", 500: "rgba(0, 0, 0, 0.36)", 600: "rgba(0, 0, 0, 0.48)", 700: "rgba(0, 0, 0, 0.64)", 800: "rgba(0, 0, 0, 0.80)", 900: "rgba(0, 0, 0, 0.92)", };
// js object -> css variable 을 위한 스크립트 import * as theme from "../dist/index.js"; import fs from "fs"; // 만들 형식 : theme.css // :root { // --gray-900: #171923 // } // 정규표현식으로 카멜케이스 => 변경 const toCssCasting = (str) => { ... }; // 원하는 형태로 key : value 매핑 const cssVariables = (colorValue) => Object.entries(colorValue) .map(([mainKey, mainValue]) => Object.entries(mainValue) .map( ([subKey, subValue]) => `--${toCssCasting(mainKey)}-${toCssCasting(subKey)}: ${subValue};` ) .join("\n") ) .join("\n"); const generateThemeCssVariables = () => { const cssString = []; Object.entries(theme.vars).forEach(([key, value]) => { const selector = ":root"; if (key === "colors") { Object.entries(value.$static).forEach(([colorKey, colorValue]) => { if (colorKey === "light") { return cssString.push(`${selector} {\n${cssVariables(colorValue)}\n}`); } if (colorKey === "dark") { const selectorDark = selector + " .theme-dark"; return cssString.push(`${selectorDark} {\n${cssVariables(colorValue)}\n}`); } return; }); return; } return cssString.push(`${selector} {\n${cssVariables(value)}\n}`); }); return cssString; }; const generateThemeCSS = () => { const variables = generateThemeCssVariables(); fs.writeFileSync("dist/themes.css", [...variables].join("\n")); }; generateThemeCSS();
// build결과물 (light.d.ts) export declare const whiteAlpha: { 50: string; 100: string; 200: string; 300: string; 400: string; 500: string; 600: string; 700: string; 800: string; 900: string; }; export declare const blackAlpha: { 50: string; 100: string; 200: string; 300: string; 400: string; 500: string; 600: string; 700: string; 800: string; 900: string; };
// build결과물 (theme.css) :root { --black-alpha-50: rgba(0, 0, 0, 0.04); --black-alpha-100: rgba(0, 0, 0, 0.06); --black-alpha-200: rgba(0, 0, 0, 0.08); --black-alpha-300: rgba(0, 0, 0, 0.16); --black-alpha-400: rgba(0, 0, 0, 0.24); --black-alpha-500: rgba(0, 0, 0, 0.36); --black-alpha-600: rgba(0, 0, 0, 0.48); --black-alpha-700: rgba(0, 0, 0, 0.64); --black-alpha-800: rgba(0, 0, 0, 0.80); --black-alpha-900: rgba(0, 0, 0, 0.92); --white-alpha-50: rgba(255, 255, 255, 0.04); --white-alpha-100: rgba(255, 255, 255, 0.06); --white-alpha-200: rgba(255, 255, 255, 0.08); --white-alpha-300: rgba(255, 255, 255, 0.16); --white-alpha-400: rgba(255, 255, 255, 0.24); --white-alpha-500: rgba(255, 255, 255, 0.36); --white-alpha-600: rgba(255, 255, 255, 0.48); --white-alpha-700: rgba(255, 255, 255, 0.64); --white-alpha-800: rgba(255, 255, 255, 0.80); --white-alpha-900: rgba(255, 255, 255, 0.92);
참고
당근 디자인시스템 youtube : https://youtube.com/watch?v=obQvttzgSzY&si=16cyK-wslzVv8P4t
1편 : https://yozm.wishket.com/magazine/detail/2537/ 2편 : https://yozm.wishket.com/magazine/detail/2538/
패캠 유료강의(당근 디자인 시스템 참여하신 분) headless ui : https://headlessui.com/
쿠키런 복잡한ui 제어 : https://youtube.com/watch?v=Hv_PhrfwerQ&si=OpjA6VwkmcUXcYrh flex 디자인시스템 : https://youtube.com/watch?v=21eiJc90ggo&si=g1QmQL0hbuBZTPzQ
댓글남기기