이번 프로젝트에 rebass 라는 React primitive ui component build with styled system
이라는 라이브러리를 사용해보고 정보와 사용 느낀점을 남깁니다.
rebass 란
React에서 사용할 수 있는 UI 원시 컴포넌트들을 지원하는 라이브러리로써 기존의 css-in-js
라이브러리에 styled-system
을 이용해서 만들어져 있습니다.
즉, css-in-js에 이런 styled-system
을 믹싱해서 원시 컴포넌트를 미리 만들어 둔 것이 rebass
입니다.
css-in-js : styled-component , @emotion
css-in-js (styled-component, @emotion) 장점
여기서는 별도의 css-in-js 들을 설명하진 않겠습니다. 대신 장점 몇 가지를 나열해 보겠습니다.
- 셀렉터의 스코프가 전역이 아닙니다. 이 말은, 셀렉터가 겹칠일이 없다는 것입니다.
- sass 문법을 사용할 수 있습니다. 즉, '&' 단어로 현재 컴포넌트를 나타낼 수 있고 이걸로 부모 , 형재 등등의 선택자들을 셀렉팅 할 수 있습니다.
- React Context API를 이용해 theme를 적용할 수 있습니다.
- 다이나믹하게 스타일링을 적용할 수 있습니다. 컴포넌트에 props를 전달해서 동적으로 스타일을 정의 할 수 있습니다. 또한 js 특정 값에 따라서 스타일을 쉽게 정의 내릴 수 있습니다.
무엇보다도 컴포넌트 베이스 디자인을 할 수 있고 작은 독립적인 단위로 UI 분할을 하는데 도움을 줍니다.
한곳 또한 한 페이지 이상 또는 자주 사용된다면 특정 스타일 또는 디자인을 갖고 있다면 클래스를 만들고 어플리케이션의 다른 영역에서 그 클래스를 사용하는 것보다 하나의 스타일된 컴포넌트를 만들고 특정 컴포넌트를 사용하는 것이 중복된 css를 줄이고 color 또는 공간을 조정하는 것 같은 UI를 약간 변경하는 데 필요한 시간을 줄입니다.
styled-system 이란
Styled System
은 constraint-based design system principles
에 영향을 받아 비주얼 디자인의 특정 영역 내에서 디자인 제약 스케일을 관리하기 위한 솔루션 입니다.
"디자인 시스템은 기본적으로 디자인과 코드로 구현 된 규칙, 제약 조건 및 원칙의 모음입니다." -Sylvee L.- '디자인 시스템'이란, 서비스를 만드는데 사용한 공통 컬러, 서체, 인터랙션, 각종 정책 및 규정에 관한 모든 컴포넌트를 정리해놓은 것을 뜻합니다. -배재민 디자이너-
예를 들면 폰트의 사이즈, 여백의 사이즈, 컬러, 기타 다른 시각적인 속성들을 theme object로 관리 할 수 있도록 도와줍니다. 이제는 구체적인 디자인 시스템을 포함하는 theme.js 를 사용해서 컴포넌트의 props를 셋팅해주게 됩니다.
또한 일관된 스타일을 적용 할 때 올바른 작업을 쉽게 수행 할 수있는 API를 제공하도록 합니다.
rebass 장점
rebass
는 system-styled
장점을 더욱 간단히 이용 하는 것이라, 아래 장점들은 styled-system
의 장점이 되기도 합니다.
- 가장 작고 견고한 Component 들을 제공합니다.
컴포넌트 개발시에 기본적으로 제공하는 (Box, Text, Image.. 등등의 컴포넌트를 미리 제공해 줍니다.)
import {Box, Text, Image} from 'rebass'
- 일관 된 컴포넌트의 props 개발
다음 유지보수시 서로 다른 개발자가 작성한 컴포넌트가 아래의 예시와 같다고 했을 때
<CustomButton1 type="thin"/>
<CustomButton2 thin/>
다양한 API 형식을 지니는 컴포넌트를 제작할 수 있으며 이는 곧 또다른 유지보수시 큰 시간을 들이게 됩니다.
반면 rebass를 사용한다면 새롭게 props 를 만들 필요가 없을 뿐더러 다른 개발자가 보아도 쉽게 이해 할 수 있습니다.
<CustomButton1 p={2} /> // padding 이 테마의 scale의 2번째 값을 적용한다.
<CustomButton2 p={3} /> // padding 이 테마의 scale의 3번째 값을 적용한다.
- 테마를 우선순위로 사용하면서 일관된 스타일을 유지
css-in-js 에서도 테마를 지원하지만 기본적으로 우선시 되지는 않습니다. 하지만 rebass 컴포넌트는 테마를 우선 적용하도록 되어있습니다.
- 확장성이 용이
css-in-js에서 사용하도록 하는 styled()
로 확장하는 컴포넌트는 기존 컴포넌트의 API가 복잡할수록 예측 가능하도록 확장하기가 어렵습니다. 반면 rebass로 확장을 하는 경우에는 예측 가능하도록 설계가 되어 있습니다.
import {Button} from 'rebass'
function CustomButton() {
return <Button sx={
color: 'point' // theme에 포인트 컬러
} />
}
<CustomButton /> // 일반적으로 color는 point 컬러
<CustomButton color={'red'} /> // red color로 수정
추후 theme를 잘 쓰기 위한 노력
스타일에 대한 적절한 추상화 작업이 필요합니다. 최대한 추상화로 정의 내릴 수 있는 디자인은 모두 theme에 녹여내는 작업이 필요 합니다.
디자인을 보고 더 이상 쪼갤 수 없는 스타일 요소들을 분류하고 한 스타일 요소에 최대 n개가 넘지 않는 선에서 추상화를 시킵니다.
ex) borderRadius 의 경우 smallRadius, mediumRadius, largeRadius
이렇게 theme.js 에 디자인 명세를 작성하면 페이지에 들어가는 컴포넌트들은 될 수 있으면 이 명세에 따르도록 만듭니다. 피치 못할 경우에는 각 컴포넌트에서 필요한 스타일을 추가 및 오버라이딩 해서 적용합니다.
- 디자인 가이드로 준 수치는 모두 theme.js 로 설정해 둔다.
- theme에 있는 수치들은 sx props로 셋팅한다.
- 보통은 atoms 단위에 있는 컴포넌트는 sx로 셋팅한다. ( 다른 컴포넌트에서 확장시 css props로 확장 )
- moleculos 이상부터는 공간부분을 대부분 theme에서 가져다 쓴다.
- 나머지는 css로 사용하되 json 또는 styled-component의 css helper를 이용하면 간단하게 이용할 수 있을 듯 싶다.
rebass + typescript
rebass와 typecript를 함께 썼을때 이슈로는 다음과 같습니다.
rebass는 css-in-js를 @emotion
기반으로 사용하고 styled-system
을 사용하는 것으로 github에서 보았습니다.
import styled from '@emotion/styled'
export const Box = styled('div', {
shouldForwardProp
})({
boxSizing: 'border-box',
margin: 0,
minWidth: 0,
},
base,
variant,
sx,
props => props.css,
compose(
space,
layout,
typography,
color,
flexbox,
),
)
interface BoxKnownProps
extends BaseProps,
StyledSystem.SpaceProps,
StyledSystem.LayoutProps,
StyledSystem.FontSizeProps,
StyledSystem.ColorProps,
StyledSystem.FlexProps,
StyledSystem.OrderProps,
StyledSystem.AlignSelfProps,
SxProps {
variant?: StyledSystem.ResponsiveValue<string>;
tx?: string;
};
export interface BoxProps extends BoxKnownProps, Omit<React.HTMLProps<HTMLDivElement>, keyof BoxKnownProps> {}
export const Box: React.FunctionComponent<BoxProps>;
하지만 다른 컴포넌트에서 @emotion/core
를 import 할 경우 css에 대한 충돌이 발생 합니다.
@emotion/core
에서 사용하는 css type 은
declare global {
namespace JSX {
/**
* Do we need to modify `LibraryManagedAttributes` too,
* to make `className` props optional when `css` props is specified?
*/
interface IntrinsicAttributes {
css?: InterpolationWithTheme<any>
}
}
}
rebass 의 css type을 살펴보면
import * as StyledComponents from 'styled-components';
export interface BaseProps extends React.RefAttributes<any> {
as?: React.ElementType;
css?: StyledComponents.CSSObject | StyledComponents.FlattenSimpleInterpolation | string;
}
여기서 rebass의 css props는 왜 StyledComponents 를 아직도 type으로 지정하는지는 아직 파악이 안됩니다.
rebass 느낀점
디자이너가 있다면 어느정도 디자인에 대한 system
을 만들어 두고 시작하면 좀 더 손쉽게 쓸 수 있을거 같습니다.
여기서 디자인 system
은 간단하게 디자인 가이드 정도 생각하면 될 듯 싶습니다.
스타일 어디까지를 테마로 뺴두어야 할지의 경계를 정하지 못한다면 theme.js가 자칫 의미가 없어질 수 있습니다.
장점을 정리해보면 다음과 같습니다.
- 테마를 우선순위로
- 일관된 props ( 모양과 행동으로 구체적인 props를 갖는게 좋음.)
- 컴포넌트의 계층 구조를 손쉽게 생각할 수 있게 해줌.
- 컴포넌트 확장에 용이
아쉬웠던 점
css-in-js 들에는 develop 할 경우 css 네이밍을 개발자가 정해놓은 룰에 따라서 네이밍을 붙여주기도 합니다.
특히 @emotion
에서는 https://emotion.sh/docs/babel-plugin-emotion 를 사용하면 css 네이밍을 붙여줍니다.
이는 개발자 도구에서도 어느 컴포넌트에서 렌더링이 되었는지 한눈에 알아 볼 수 있습니다.
rebass
에서@emotion/styled
를 사용하고 있어서 위 플러그인을 사용함.
하지만 rebass
에서는 다음의 경우에만 css 네이밍을 붙여 줍니다.
- props로 css 속성이 들어간 컴포넌트 : babel config에 정해진 룰대로 자동으로 css 네이밍을 붙여줍니다.
- sx props 안에 label property가 존재하는 경우 : label의 값으로 css 네이밍을 붙여줍니다.
styled component로 비슷하게 만들어 보기
추가적으로 테마를 사용하지 않을 경우에 styled component 모듈로도 이렇게 primitive UI Component를 만들어 볼 수 있을 것이다.
해서 한번 도전해 보았다.
쉬운 Atom
의 Box Component
는 다음과 같이 만들 수 있을 꺼 같습니다.
import React from "react";
import styled, { FlattenSimpleInterpolation } from "styled-components";
type BoxProps = {
children?: React.ReactNode;
css?: FlattenSimpleInterpolation;
};
type BoxStyledProps = {
css?: FlattenSimpleInterpolation;
};
const BoxStyled = styled.div<BoxStyledProps>`
${props => (props.css ? props.css : "")}
`;
function Box({ children, css }: BoxProps) {
return <BoxStyled css={css}>{children}</BoxStyled>;
}
export default Box;
참고
styled-system 사용법 : https://varun.ca/styled-system/
styled-component와 styled-system을 함께 사용했을때 이점 : https://medium.com/styled-components/build-better-component-libraries-with-styled-system-4951653d54ee
styled-system 신조 : https://jxnblk.com/blog/the-three-tenets-of-styled-system/
디자인 시스템 1 : https://medium.muz.li/what-is-a-design-system-1e43d19e7696
디자인 시스템 2 : https://medium.com/sketch-app-sources/design-system-principles-service-design-c3e439666b97