CSS-in-JS가 무엇인지 모를때부터, 부트캠프를 통해 styled-components를 사용했었다. 배민에서는 어떻게 사용하는지도 궁금해서 개인적으로 흥미있는 장이었다!
CSS-in-JS
CSS-in-JS와 인라인 스타일의 차이점
CSS-in-JS는 CSS-in-CSS보다 더 강력한 추상화 수준을 제공한다. CS-in-JS를 활용하면 자바스크립트로 스타일을 선언적이고 유지보수 할 수 있게 표현할 수 있다.
흔히 인라인 스타일과 헤깔릴 수 있는데 두 방식의 차이점은 아래와 같다.
import React from 'react';
import styled from 'styled-components';
const textStyles = {
color: 'white',
};
const CssInJs = () => {
return (
<div>
<div style={textStyles}>예시2</div>
<StyledComponentsEx>CSS-in-JS</StyledComponentsEx>
</div>
);
};
export default CssInJs;
const StyledComponentsEx = styled.div`
color: white;
background-color: black;
`;
<div style={{ color: 'white' }}>인라인2</div>
<style>
.hash136s21 {
color:white;
}
</style>
<div class='hash123s21'>CSS-in-JS</div>
인라인 스타일은 DOM노드에 속성으로 스타일을 추가한 반면에 CSS-in-JS는 DOM 상단에 style태그를 추가했다.
CSS-in-JS의 몇 가지 장점은 아래와 같다.
- 컴포넌트로 생각할 수 있다 : CSS-in-JS는 스타일을 컴포넌트 단위로 추상화하여 생각할 수 있게 해준다.
- 부모와 분리할 수 있다 : CSS에는 명시적으로 정의하지 않은 경우 부모 요소에서 자동으로 상속되는 속성이 있다.
- 스코프를 가진다 : CSS는 하나의 전역 네임스페이스를 가지기기 때문에 선택자 충돌을 피하기 어렵다. 이를 방지할 수 있음
- 자동으로 벤더 프리픽스가 붙는다 : 브라우저 호환성을 향상해줌
- 자바스크립트와 CSS사이에 상수와 함수를 쉽게 공유할 수 있다.
CSS-in-JS의 등장 배경
스타일링 라이브러리는 크게 두 가지로 나눌 수 있다.
CSS Preprocessor sass/scss less stylus |
CSS in JS styled-components emotion |
웹 애플리케이션의 UI를 구성하는 데에도 CSS를사용하고 웹 개발에 컴포넌트/모듈 방식이 적용됨에 따라 CSS Modules를 시작으로 자바스크립트에서 CSS를 생성하는 방식이 도입되고 있다.
크시르토퍼 쉬도가 CSS의 7가지 문제점을 제기했다 그리고 그에 대한 해결책으로 CSS-in-JS를 개념을 제시했다
- 글로벌 네임스페이스 : 모든 스타일이 전역 공간을 공유하므로 중복되지 않는 CSS 클래스 이름을 고민해야함
- 의존성 : CSS의 의존성과 자바스크립트의 의존성이 달라서 사용하지 않는 스타일이 포함되거나 꼭 필요한 스타일이 누락되는 문제가 생긴다.
- 불필요 코드 제거 : 기능 추가 수정 삭제 과정에서 불필요한 CSS를 삭제하기 힘들다.
- 최소화 : 클래스 이름을 최소화하기 힘들다.
- 상수 고융 : 자바스크립트와 상태 값을 공유할 수 없다. (현재는 CSS Variable이 도입됨)
- 비결정적 해결 : CSS 로드 순서에 따라 스타일 우선순위가 달라진다.
- 고립 : CSS의 외부 수정 관리하기 어렵다(캡슐화)
물론 CSS-in-JS를 적용하기 위해서는 별도의 라이브러리를 설치해야하고, 런타임에 스타일을 생성하기 위한 동작이 필요하기 때문에 CSS-in-CSS에 비해 성능적인 측면이 떨어질 수 있다.
하지만 동적인 대규모 웹 앱에서 컴포넌트 기반으로 개발할 떄 생산성을 높일 수 있다.
CSS-in-JS 사용하기
대부분의 CSS-in-JS은 사용방식이 유사한데, 템플릿 리터럴을 활ㅇ요해서 동적인 스타일을 정의하면 된다. 먼저 props의 타입을 정의하고, 이 props를 활용해서 동적인 스타일링을 구현한다.
또한 variant props의 유형에 따라 다른 스타일을 적용하고 싶다면 css함수를 사용하여 스타일을 정의하고 variant 값에 따라 맵 객체를 생성하여 사용할 수도 있다. (emotion 기준)
type ButtonRadius = 'xs' | 's' | 'm' | 'l';
export const buttonRadiusStyleMap:Record<ButtonRadius, SerializedStyles>={
xs:css`
border-radius:${radius.extra_small}
`,
// ...
}
그리고 유틸리티 함수를 활용하여 중복 타입 선언을 피할 수 있다.
interface BadCase {
height?: string;
isFull?: boolean;
}
const Component = styled.div<BadCase>`
height: 100;
margin: 0;
${({ isFull }) =>
isFull &&
css`
margin: 0 -15px;
`}
`;
const GoodCase = styled.div<Pick<Props, 'height' | 'isFull'>>``;
'독서' 카테고리의 다른 글
우아한 타입스크립트 with React -13장 타입스크립트와 객체 지향 (0) | 2024.03.25 |
---|---|
우아한 타입스크립트 with React -12장 프로젝트 관리 (0) | 2024.03.25 |
우아한 타입스크립트 with React -10장 상태 관리 (0) | 2024.03.17 |
우아한 타입스크립트 with React - 9장 훅 (0) | 2024.03.14 |
우아한 타입스크립트 with React -8장 JSX에서 TSX로 - 2 (0) | 2024.03.09 |