CSS-in-JS를 잘 써보자.

NB·2021년 4월 18일
3
post-thumbnail
post-custom-banner

일반 CSS를 사용하는 것과 CSS-in-JS를 사용하는 것 중에 어떤 것이 더 성능에 좋은가? 라고 물어보면 여기(Real-world CSS vs. CSS-in-JS performance comparison)에서는 이렇게 대답하고 있다.


  • JS 양이 적음 == 더 빠른 사이트

그럼에도 불구하고 우리는 왜 CSS-in-JS를 사용할까? 그리고 CSS-in-JS 방식을 사용한다면 어떻게 효율적으로 사용할 수 있을까?


TLDR:

결론부터 말하자면 완벽한 정답은 없습니다! 그저 어떤 것을 우선시하냐에 따라서 적절히 선택하면 될 뿐입니다!



CSS-in-JS만의 장점은 무엇인가?

하나의 프로젝트를 CSS를 직접 작성해서 html에 등록하면 물론 제일 큰 장점은 파일이 캐싱이 되고, 이미 스타일이 등록되어있기 때문에 스타일 변화에 대해서 빠르게 반응한다는 점이 있다. 하지만 경험해본 사람은 알겠지만 각자 다른 스타일을 지정하기 위해서 다른 클래스 명을 적는 것이 여간 힘든 것이 아니다. 그렇기 때문에 BEM Convention과 같은 CSS 방법론이 탄생했다고 생각한다.

CSS 변수명을 기억하기 힘든 코드 길이

몇천 줄의 CSS에서 겹치지 않는 변수명을 작성하기란 체계적인 규칙을 정해놓지 않는다면 정말 힘들다!

우리는 겹치지 않는 변수명을 짓기 위해서 규칙을 정하고 머리를 쓰고 싶지는 않거나 이 과정을 최소화하고 싶어 한다! 그렇다면 CSS-in-JS는 어떻게 스타일 코드를 관리할까?
대표적인 예로 Styled Components를 예시로 들면 각 컴포넌트마다 Javascript 코드 내에 작성하게 된다.

Styled Components로 작성한 예시 코드
다음과 같이 Javascript에 스타일 코드를 함께 작성할 수 있다.

import styled from 'styled-components

const Logo = () => {
  return (
    <a href="/">
      <Img src="/images/logo.png" alt="" />
    </a>
  );
}

const Img = styled.img`
  width: auto;
  height: 40px;
`;

export default Logo

위 코드처럼 각 컴포넌트마다 분리해서 작성하게 되면, 가장 큰 문제였던 스타일 네이밍에 대한 관리 포인트를 제거할 수 있다! (물론 모든 CSS-in-JS 라이브러리들이 전부 이 방식을 택한다는 것은 아니다. 어디까지나 예시일 뿐이다.) 이로 인해서 사람들은 이제 CSS도 깔끔하게 모듈화하여 생산성을 높이게 되었다!

특히나 사람들이 가장 많이 사용하고 있다는 Styled Component는 매우 환상적이다!
JS에서 변수를 CSS로 집어넣어서 동작하게 만들 수도 있다. 하지만 모든 것에는 장점만 있는 것이 아닌 것처럼 이 방식도 몇 가지의 문제가 존재한다. 바로 CSS의 거대한 스타일 코드가 Javascript 번들로 옮겨졌다는 문제이다. 이 말은 즉 초기 Javascript 파일을 로드하는 것에 큰 비용이 든다는 것을 이야기한다. 그래서 이제 사람들은 다른 방법에 대해서 생각하고 개발하기 시작한다.



Runtime? Buildtime?

아래 통계는 2020년 기준으로 사용되는 라이브러리 순위이다.
[2019~2020 CSS-in-JS 사용량 통계] - The State of CSS Survey

2019년에서 2020년 사이 CSS-in-JS 사용률

CSS-in-JS는 크게 두 가지 방법으로 작동하게 된다. 위 통계에서 가장 많이 사용되는 Styled ComponentsCSS Modules를 대표적으로 보면 전자는 Run-time 방식으로 동작하며, 후자는 Build-time 방식으로 동작한다. 두 방식의 차이점을 보자면, 런타임 방식은 JS에서 변수를 스타일 내부로 직접 넣어서 사용할 수 있다.

Styled Components를 이용한 JS 변수를 스타일에 적용시키는 예시 코드

import styled from 'styled-components'

const Button = ({ active }) => {
  return <Btn active={active}>버튼</Btn>
}

const Btn = styled.button`
  background-color: ${props => props.active
    ? 'blue'
    : 'silver'
  };
`;

export default Button

하지만, 스타일이 동적인 변수에 의존하게 되어 해당 컴포넌트가 리렌더링 될 시, 동적으로 CSS를 생성시켜서 해당 요소에 적용하게 된다. 그렇기에 화려한 인터렉션이 많은 사이트에서는 오히려 퍼포먼스가 저하되는 상황이 발생할 수도 있다.

그렇다면, 이번에는 CSS Modules를 코드로 예시를 보자.

CSS Modules를 사용한 예시 코드
먼저 컴포넌트에 적용할 CSS 파일을 Component명.module/css 로 생성시켜준다.

/* Button.module.css */
.submit {
  color: red;
}


그리고 작성한 CSS파일을 import하여 className으로 등록해주면 적용된다.

/* Button.jsx */
import styles from './Button.module.css'

const Button = () => {
  return <button className={styles.submit}>제출</button>;
}

export default Button

빌드타임 방식은 개발자가 프로젝트를 빌드를 하게 되면 위와 같이 작성된 CSS를 하나로 모아, 다음과 같이 빌드된 CSS 파일로 떨궈지게 된다. 서비스 사용자는 초기에 1번만 CSS 파일을 로드함으로써 위의 경우에서 퍼포먼스가 저하되는 경우는 발생하지 않는다.

그렇다면 빌드타임 방식이 항상 좋은 것인가? 라고 묻는다면 그렇지 않다. 만약 컴파일된 CSS 파일이 방대하다면 사용자는 해당 CSS 파일이 로드될 때까지 첫 번째 페인트가 실행되지 않아 사용자는 빈 화면만 바라보고 있을 것이다.



어떤 라이브러리 사용할까?

개발자 경험이 우선적이고 프로젝트가 큰 규모가 아니라면 런타임 방식의 라이브러리도 충분하다. 하지만 사용자 경험이 우선적이고 성능을 좀 더 생각한다면 빌드타임 방식의 라이브러리도 생각해봐야 한다. 그렇지만 어느 다지선다처럼 한 가지를 고르라는 것이 아니다. 어떠한 라이브러리를 1개로 고정해서 사용하기보다는 2개의 라이브러리를 사용하는 방법도 있다. 하지만 이 방법은 라이브러리 관리 포인트가 하나 더 증가하는 것이기 때문에 좀 더 신중해질 필요가 있다.

또한, LinariaCompiled와 같은 라이브러리는 Styled Component 처럼 JS내에 CSS를 작성하지만, 컴파일하게 되면 CSS 파일로 따로 최적화하여 추출해주는 작업도 해주고 있다. 본인도 글을 작성하면서 여러 가지의 라이브러리들을 알아보면서 정말 흥미롭다고 생각하고 있으며 다음 프로젝트에는 적용할 의사가 매우 있다!

물론 사람들이 많이 사용하는 라이브러리를 사용하는 것이 좋을 수도 있다. 레퍼런스가 풍부하며, 그만큼 안정성이 높다는 것이기 때문에. 그렇지만 정말 성능을 생각한다면 다른 방법들도 복합적으로 적용하면 더 뛰어난 퍼포먼스를 보여주는 사이트를 만들 수 있지 않을까 생각해본다.



🔖 읽어주셔서 감사합니다. 피드백은 언제나 환영입니다!


참고자료

  1. CSS-in-JS(Styled Components) vs CSS-inCSS(CSS Modules) 성능 비교 - bono
  2. Real-world CSS vs. CSS-in-JS performance comparison - Tomas Pustelnik
  3. How to increase CSS-in-JS performance by 175x - Dominic Tobias
  4. The tradeoffs of CSS-in-JS - Oleg Isonen
  5. The styled-components Happy Path - Josh Comeau
profile
𝙄 𝙖𝙢 𝙖 𝙛𝙧𝙤𝙣𝙩𝙚𝙣𝙙 𝙙𝙚𝙫𝙚𝙡𝙤𝙥𝙚𝙧 𝙬𝙝𝙤 𝙚𝙣𝙟𝙤𝙮𝙨 𝙙𝙚𝙫𝙚𝙡𝙤𝙥𝙢𝙚𝙣𝙩. 👋 💻
post-custom-banner

0개의 댓글