왜 CSS in JS라고 안 하죠?

전 CSS in Rust 라이브러리를 만들고 있어서요. 이런 느낌의 라이브러리를 총칭하는 느낌으로 새 용어를 하나 만들었어요.

그 얘기를 왜 이제 꺼내요?

이 트윗을 보고 갑자기 쓰고 싶어져서 썼습니다. 그리고 별개로 요즘 제가 CSS in Rust 라이브러리를 만들고 있기도 합니다.

CSS in Code가 뭐가 좋아요?

강력합니다. less나 sass가 있는데도 강력하냐구요? 그럼요. 강력하죠.

Scoped

이런 라이브러리는 당연하겠지만 그 자체만으로 이름 충돌을 걱정하지 않아도 되는 자동 생성된 클래스 이름을 주는데, 사람이 읽기 쉬운 이름을 쓸 수 있으니 좋아요. CSS Modules<style scoped>가 있는데 왜 그러냐구요? 네 맞아요. 이건 요즘 기본 사양이죠.

With Component or Not

React와 같은 HTML in Code류 라이브러리를 쓰며 스타일을 관리할 때, CSS 파일도 열고 컴포넌트 파일도 열고 수정해야 하는 게 꽤 번거롭죠. 그렇다고 Vue처럼 Single File Component만 쓰면 좋은가 하면은 한 파일이 너무 길어져 가독성에 영향을 주고, CSS in Code 라이브러리는 매우 일관성 있게 관리할 수 있어요. 같은 파일에서도, 다른 파일에서도. import는 강력하니까요.

More Safe

클래스 이름 하나 잘못 써서 30분 삽질하는 것은 NEVER... 왜냐고요? 클래스 이름을 잘못 적으면 IDE도 로그도 빨갛게 오류를 띄워주니까요. 변수니까 가능한 일이죠. 더불어 쓰이지 않는 클래스 추적도 이미 있는 기술에 얹어갈 수 있어요. 변수 사용 분석 없는 IDE는 드물죠, 요즘은.
그리고, 라이브러리를 잘 고르면 타입 안전한 CSS를 만날 수 있어요. CSS in JS 류 라이브러리 중에는 오브젝트 리터럴을 지원하는 라이브러리가 있고, 그렇다면 당연히 타입 정의 파일을 넣는 것만으로 컴파일 타임에 안전성이 보장되는 거죠!

Dynamic Styles

개인적으로 그렇게 좋아하지는 않아요. 하지만 styled-components도 그렇고 prop을 받아서 스타일을 상태에 따라 동적으로 변경할 수 있는 기능을 넣어둔 라이브러리들이 많죠.

Same Advantages

전처리기나 후처리기들과 장점을 공유해요. 벤더 프리픽스 붙이기, 믹스인, 함수, 임포트, 코드 분리, 변수 등.

그래서 어떤 걸 써야 하는데?

일단 JS 커뮤니티 쪽에서 나온 개념이니까, CSS in JS 류 라이브러리만 논해볼까요. styled-components, emotion, astroturf, linaria 등등, 라이브러리가 너무 넘쳐나요! 각각의 라이브러리를 짧게 리뷰해보죠.

styled-components

styled-components는 Tagged Template Literal 대중화의 아버지라고 할 수 있죠. 아마 가장 잘 알려진 CSS in JS 라이브러리일 거에요. 문법도 아주 간단하죠. 직접 보자구요.

const buttonGray = 'hsl(230, 5%, 85%)';

const MyButton = styled.button`
  border: 1px solid black;
  background-color: ${buttonGray};
`;

export const MyComponent = () => (
  <div>
    <MyButton />
  </div>
)

저게 다에요. 참 쉽죠? 오브젝트 리터럴은 지원하지 않고, CSS 파일 추출도 지원하지 않지만 React 프로젝트에 정말 적용하기 쉬워요. 그리고 React Native를 만지게 된다면 만나게 될 가능성이 높다고 확신하고 있어요.

Emotion

Emotion도 상당히 괜찮은 라이브러리죠. 설치는 조금 귀찮지만 다양하고, 예쁜 코드를 쓸 수 있게 도와줘요. 설명만 하지 말고 보여달라고요? 넹 ㅠ

const TaggedTemplateLiteral = css`
  color: red;
`;
const ObjectLiteral = css({
  textDecoration: 'underline'
});

CSS 파일 추출도 지원해요. 아직 제대로 써보진 못했지만 써보고 싶은 라이브러리에요.

astroturf

astroturf는 못 들어보신 분들이 많을 것 같아요. 저도 몇 시간 전까진 몰랐거든요. 꽤 재미있는 지향점을 갖고 있는 라이브러리에요. JavaScript이기에 가능한, 그런 코드 한번 보시죠.

const margin = 10;
const height = 50;

const styles = css`
  .box {
    height: ${height}px;
    margin-bottom: ${margin}px;
  }
`;

const MyButton = styled('button')`
  color: black;
  border: 1px solid black;
  background-color: white;

  &.primary {
    color: blue;
    border: 1px solid blue;
  }

  &.color-green {
    color: green;
  }
`;
const BoxedGreenButton = () => (
  <div class={styles.box}>
    <Button primary color="green">
      A styled button
    </Button>
  </div>
);

“type-safe하게 쓰기 힘들어보이는데...?” 라는 말이 나오죠. 만약 정적 타입 언어였다면 저런 생각은 못 했을 거에요. 그냥 이런 생각도 있다는 느낌으로 받아들이면 될 듯 해요. 그와 별개로, 이런 구조(css 부분)를 채택한 덕분에 한 파일로 정적 CSS를 빼기 좋다고 해요. 이 라이브러리의 약팔이는 zero overhead. 정적 CSS로 다 빼둬서 런타임에 아무 것도 안 한다는 거죠.

linaria

linaria는 동적 스타일에 대해 꽤나 재미있는 접근을 택했어요. CSS Variable을 사용하자는 것이죠. CSS Variable을 바꾸는 것이 class를 여러 개 만드는 거나 인라인 스타일보다 낫지 않겠냐는 거죠. 상당히 괜찮은 접근이라고 생각해요. 그리고 linaria는 정적 CSS 파일 생성을 하고, 런타임에도 거의 제로 오버헤드에요. CSS in JS류 라이브러리가 다 비슷하게 생겨서 이번 거는 코드를 생략할게요.

결론

CSS in Code 류 라이브러리는 분명히 좋습니다. 다만, 좋다고 해서 제대로 된 분석 없이 막 적용하면 안되겠죠. 적재적소에 쓰이는 기술이 좋은 법입니다. 레이텍으로 써도 되는 문서 하나 쓰겠다고 preact parcel postcss docker ... 이렇게 기술 스택 쌓는 건 조금 과할지도 모르잖아요?


딱 이걸로 글을 쓰라고 그 트윗이 말하는 것 같았지.