styled-components, emotion 비교

2023. 2. 22. 22:57·TECH

styled-components, emotion 비교

프로젝트를 구축하기 전 CSS-in-JS로 유명한 두개 라이브러리 styled-components와 emotion을 비교하고
우리 환경에 맞는 라이브러리를 택하기 위해서 비교를 하게 되었다.

styled-components와 emotion 문법만 조금 다를 뿐 동일한 기능을 가지고 있어서 더 선택하기 힘들었던 것 같다.

 

트렌드


트렌드를 확인해 보면 비슷하게 사용되고 있는것을 볼 수 있다.

@emotion/core 10버전 -> @emotion/react 11버전

npm trends

 

크기


styled-components가 emotion에 비해 크기가 크지만 유의미한 차이는 아닌 것같다.

styled-components@5.3.6

https://bundlephobia.com/package/styled-components@5.3.6

@emotion/react@11.10.6

https://bundlephobia.com/package/@emotion/react@11.10.6

기본 문법


styled-components

컴포넌트 형식으로 사용되어 보기가 좋고, 의미를 부여할 수 있어서 컨텐츠를 확인하기도 수월하다 

 

import styled from 'styled-components';

const Wrapper = styled.div`
  border: 1px solid red;
`;

const Box = styled.div`
  background-color: blue;
  width: 100px;
  height: 100px;
`;

const App = () => {
  return (
    <Wrapper>
      <Box>
        박스입니다.
      </Box>
    </Wrapper>
  )
}

export default App;

emotion

/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react'

const wrapper = css`
  border: 1px solid red;
`;

const box = css`
  background-color: blue;
  width: 100px;
  height: 100px;
`;

const App = () => {
  return (
    <div css={wrapper}>
      <div css={box}>
        박스입니다.
      </div>
    </div>
  )
}

export default App;

emotion에서는 styled문법도 제공한다.

/** @jsxImportSource @emotion/react */
import styled from '@emotion/styled';

const Wrapper = styled.div`
  border: 1px solid red;
`;

const Box = styled.div`
  background-color: blue;
  width: 100px;
  height: 100px;
`;

const App = () => {
  return (
    <Wrapper>
      <Box>
        박스입니다.
      </Box>
    </Wrapper>
  )
}

export default App;

 

inline css


emotion는 인라인으로 css작성한 스타일을 class로 변경해 준다.

기존 inline으로 선언하지 못했던 media query, pseudo selector(가상 선택자), nested selector을 사용할 수 있다.

/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react'

const wrapper = css`
  border: 1px solid red;
`;

const App = () => {
  return (
    <div css={wrapper}>
      // 인라인으로 작성한 emotion css코드
      <div css={css`
        background-color: blue;
        width: 100px;
        height: 100px;
      `}>
        박스입니다.
      </div>
    </div>
  )
}

export default App;

브라우저 렌더링 화면
class가 적용되고 해당 클래스에 스타일이 적용되어있다.


hash 클래스 라벨링


CSS-in-JS 라이브러리는 자동으로 class에 hash를 붙임으로 충돌나지 않도록 해준다.
emotion, styled-components 모두 hash 라벨링을 제공한다.

emotion

https://emotion.sh/docs/labels
라벨링 방식을 제공하고 있다. css선언에 label속성을 넣으면 적용된다.

/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react'

const wrapper = css`
  border: 1px solid red;
  label: test-one;
`;

const box = css`
  background-color: blue;
  width: 100px;
  height: 100px;
  label: some-two;
`;

const App = () => {
  return (
    <div css={wrapper}>
      <div css={box}>
        박스입니다.
      </div>
    </div>
  )
}

export default App;

선언한 label속성값이 class 뒤에 적용된 걸 확인할 수 있다.

위에 라벨링을 제공하고 있지만 모든 스타일에 라벨링을 기재해야하는 번거로움과 컨벤션도 있어야하는 단점이 있을수있다.

babel 설정에서 labelFormat에 클래스명 규칙을 정하면 자동으로 생성하는 방법이 있다.
emotion labelFormat

labelFormat에서 제공하는 세가지 value

  • [local] - the name of the variable the result of the css or styled expression is assigned to. // 스타일 변수 명
  • [filename] - name of the file (without extension) where css or styled expression is located. //파일명
  • [dirname] - name of the directory containing the file where css or styled expression is located. // 파일경로
// babel.js
{
    "plugins": [
      [
          "@emotion",
            {
                "autoLabel": "dev-only",
                "labelFormat": "myapp-[dirname]-[local]-[filename]",
             }
        ]
    ]
}

labelFormat 적용된 클래스명

styled-components

아무 설정도 안하고 확인하면 해시값만 있는 클래스명을 확인할 수 있다.

styled-components의 Babel Macro를 사용하여 파일명_스타일명이 붙은 클래스명으로 확인 가능하다.

Babel Macro

import styled, { createGlobalStyle } from 'styled-components/macro'

 

jsx pragma


프리셋을 사용하거나 프라그마를 설정하면, 컴파일되는 jsx 코드는 react.createElement 대신에
emotion에서 제공하는 jsx 함수를 사용하게 된다.

Emotion은 jsx 파일에 JSX Pragma를 작성해줘야하는데

/** @jsxImportSource @emotion/react */

이부분이 번거롭다면 babel preset 세팅을 해주면 된다.

cra프로젝트라면 .babelrc 설정을 cra에서 막아두어서 eject를 진행하고 해야한다.

// .babelrc
{
  "presets": [
    "@emotion/babel-preset-css-prop",
  ]
}

 

composition


css cascading을 더 편리하게 해줄 수 있는 기능이다.

emotion

https://emotion.sh/docs/composition

아래 코드에서 className으로 나중에 선언 된 danger이 적용이 될 것 같지만
className 선언순서로 적용이되는것이 아닌 style태그 내 css선언 순서로 적용이 된다.

const App = () => {
  return (
    <div>
      <style>
        {`
          .danger {
            color: red;
          }

          .base {
            background-color: lightgray;
            color: turquoise;
          }
        `}
      </style>

      <div className="base danger">
        박스입니다.
      </div>
    </div>
  )
}

export default App;

emotion에서 제공하는 composition을 사용해서 우선순위를 정할 수 있습니다.

const danger = css`
  color: red;
`;

const base = css`
  background-color: darkgreen;
  color: turquoise;
`;

const App = () => {
  return (
    <div>
      <div css={[base, danger]}>
        텍스트1
      </div>
      <div css={[danger, base]}>
        텍스트2
      </div>
    </div>
  )
}

 

SSR


emotion

V10이전인 경우에만 설정이 필요하고 이상인경우는 SSR설정이 따로 필요없다고 나와있다.

styled-components

따로 설정이 필요하다.
styled components SSR

 

css extends


emotion, styled-components 라이브러리 모두 지원한다.

emotion

const btn = css`
  font-size: 20px;
  margin: 0 10px;
  border: 1px solid red;
`;

const blackBtn = css`
  ${btn}
  background-color: #000;
  color: #fff;
`

const App = () => {
  return (
    <div>
      <button css={btn}>버튼1</button>
      <button css={blackBtn}>버튼2</button>
    </div>
  )
}

styled-components

import styled from 'styled-components';

const Btn = styled.button`
  border: 1px solid red;
  margin: 0 10px;
  font-size: 20px;
  background: gray;
`;

const WhiteBtn = styled(Btn)`
  background-color: #fff;
  color: #000;
`;

const BlackBtn = styled(Btn)`
  background: #000;
  color: #fff;
`;

const App = () => {
  return (
    <div>
      <WhiteBtn>화이트 버튼</WhiteBtn>
      <BlackBtn>블랙 버튼</BlackBtn>
    </div>
  )
}

export default App;


media query


emotion, styled-components 거의 동일하다.

emotion

const breakpoints = [320,768,1024,1440];
const media = breakpoints.map(
  bp => `@media (min-width: ${bp}px)`
)
const btn = css`
  font-size: 20px;
  margin: 0 10px;
  border: 1px solid red;
  font-size: 30px;

  ${media[0]} { //@media (min-width: 320px)
    font-size: 40px;
  }

  ${media[1]} { //@media (min-width: 768px)
    font-size: 50px;
  }
`;

styled-components

const breakpoints = [320,768,1024,1440];
const media = breakpoints.map(
  bp => `@media (min-width: ${bp}px)`
)
const Btn = styled.button`
  font-size: 20px;
  margin: 0 10px;
  border: 1px solid red;
  font-size: 30px;

  ${media[0]} { //@media (min-width: 320px)
    font-size: 40px;
  }

  ${media[1]} { //@media (min-width: 768px)
    font-size: 50px;
  }
`;

 

props


emotion에서 props로 값을 내려서 처리하기가 조금 더 귀찮다.

styled-components가 편해보인다.

emotion

const btn = (props = {}) => css`
  font-size: 20px;
  margin: 0 10px;
  border: 1px solid red;
  font-size: 30px;
  background-color: ${props.bgColor ?? 'blue'};
`;

const blackBtn = css`
  ${btn()}
  background-color: #000;
  color: #fff;
`

const App = () => {
  return (
    <div>
      <button css={btn({bgColor: 'red'})}>버튼1</button>
      <button css={blackBtn}>버튼2</button>
    </div>
  )
}

styled-components

const Btn = styled.button`
  font-size: 20px;
  margin: 0 10px;
  border: 1px solid red;
  font-size: 30px;
  color: #fff;
  background-color: ${(props) => props.bgColor ?? 'blue'};
`;

const BlackBtn = styled.button`
  background-color: #000;
  color: #fff;
`

const App = () => {
  return (
    <div>
      <Btn bgColor="red">버튼1</Btn>
      <BlackBtn>버튼2</BlackBtn>
    </div>
  )
}



결론


두 라이브러리 모두 너무 편리해서 둘 중 하나를 고르긴 힘들었지만! emotion으로 결정했다.

emotion을 선택한 이유는 SSR설정없이 사용할 수 있다는 점과 composition을 더 편리하게 사용 할 수있다는 점이 큰 장점으로 보였다.

 




참고한 페이지
https://styled-components.com/
https://emotion.sh/docs/introduction

https://ideveloper2.dev/blog/2019-05-05--thinking-about-emotion-js-vs-styled-component/

https://velog.io/@bepyan/styled-components-%EA%B3%BC-emotion-%EB%8F%84%EB%8C%80%EC%B2%B4-%EC%B0%A8%EC%9D%B4%EA%B0%80-%EB%AD%94%EA%B0%80

https://80000coding.oopy.io/7ad296c7-8832-4951-9cf7-074a196d42ea

https://www.howdy-mj.me/css/emotionjs-intro

'TECH' 카테고리의 다른 글

styled-components로 theme적용하기 with Typescript  (0) 2023.02.22
styled-components 기본 문법  (0) 2023.02.22
redux-toolkit  (0) 2023.02.20
redux개념 정리  (0) 2023.02.16
tsconfig.json 기본세팅, d.ts, JSDoc  (0) 2023.02.14
'TECH' 카테고리의 다른 글
  • styled-components로 theme적용하기 with Typescript
  • styled-components 기본 문법
  • redux-toolkit
  • redux개념 정리
ssund
ssund
  • ssund
    ssund의 기술블로그
    ssund
  • 전체
    오늘
    어제
    • 분류 전체보기 (73)
      • TECH (22)
      • NOTE (40)
      • DAILY (7)
      • javascript (1)
      • 알고리즘 (0)
  • 블로그 메뉴

    • 홈
    • TECH
    • NOTE
    • DAILY
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    웹브라우저구성
    styled-components
    react state management
    global-style
    타입스크립트
    d.ts
    slidesPerGroup
    git배포
    JavaScript
    redux
    reat-head
    함수와 메서드차이
    reduxtoolkit
    Array.sort()
    React
    TypeScript
    call signatures
    배열요소순서
    커머스프로젝트
    theme-provider
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
ssund
styled-components, emotion 비교
상단으로

티스토리툴바