styled-components 를 emotion 으로 변환하기

HYl·2022년 3월 28일
20

지금까지는 CSS-in-JS 인, styled-components 를 사용해왔었다. 최근에 emotion 으로 사용하는 분들이 점점 늘어가는 추세인 것 같아서 나도 이번 기회에 emotion에 대하여 알아보려한다.
styled-components와 매우 비슷하여 배움에 있어서는 큰 어려움이 없어보였으나, 직접 부딪혀 봐야 알 것 같다.

기존에 styled-components로 반응형 레이아웃을 구현해놓은 것이 있었는데, 이것을 emotion 으로 볼 것이고, 전역적으로 사용될 css 인 globalStylestheme 역시 emotion 으로 대체하여 볼 것이다.

아래와 같은 순서로 글을 작성해보려 한다.

  • styled-components 와 emotion 의 차이점
  • styled-components 를 emotion 으로 변환하기
      1. global styles
      1. theme
      1. 반응형 레이아웃

emotion 전체 코드 Github


styled-components 와 emotion 의 차이점

https://blog.songc.io/react/react-js-in-css/
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

세계 인지도는 emotion 이 높고, 국내에서는 아직 styled-component 가 우위에 있다.
번들 크기로는 emotion이 styled-components 보다 작다. 성능상으로는 유의미하게 차이가 나지는 않는다.

또한, emotion에서는 서버 사이드 렌더링 에 따로 서버쪽에 설정을 하지 않아도 된다 는 장점이 있다. 서버 사이드 렌더링 설정 시, emotion에서는 별도의 설정 없이 작동되는 반면, styled-components설정이 필요하는 번거로움이 있다.


Global Styles

styled-components

import { createGlobalStyle } from 'styled-components';
import reset from 'styled-reset';

const GlobalStyle = createGlobalStyle`
  ${reset}

  html {
    font-size: 16px;    
  };
  
  body {  
    font-family: 'Noto Sans KR', sans-serif;
  } 

  select,
  input, 
  button,
  textarea {
    border: 0;
    outline: 0 !important;
  }
`;

export default GlobalStyle;

emotion

// src/styles/global

import React from 'react';
import { Global, css } from '@emotion/react';

const style = css`
  html {
    font-size: 16px;
  }

  body {
    font-family: 'Noto Sans KR', sans-serif;
  }

  select,
  input,
  button,
  textarea {
    border: 0;
    outline: 0 !important;
  }
`;

const GlobalStyle = () => {
  return <Global styles={style} />;
};

export default GlobalStyle;
  • emotion 에서 Global, css 를 import 한다.
  • Global 태그를 생성 후, styles 으로 global css 를 넣어준다.

index.tsx

import React from 'react';
import { render } from 'react-dom';

import GlobalStyle from '@src/styles/global';
import theme from '@src/styles/theme';
import { ThemeProvider } from '@emotion/react';

render(
    <ThemeProvider theme={theme}>
      <GlobalStyle />
    </ThemeProvider>,
  document.querySelector('#app'),
);

Theme

styled-components

import styled, { css } from 'styled-components';

const fontSizes = {
  xxs: '12px',
  xs: '13px',
  sm: '14px',
  base: '16px',
  md: '18px',
  lg: '24px',
};

const colors = {
  black: '#000',
  dark: '#191a20',
  primary: '#3f4150',
  secondary: '#8c8d96',
};

const theme = {
  fontSizes,
  colors,
};

export default theme;

emotion

  • TypeScript 사용 시에, theme.d.ts 을 생성하여 type 을 지정해주어야 한다.
// theme.ts

import { DefaultTheme } from '@emotion/react';

const theme: DefaultTheme = {
  fontSizes: {
    xxs: '12px',
    xs: '13px',
    sm: '14px',
    base: '16px',
    md: '18px',
    lg: '24px',
  },
  colors: {
    black: '#000',
    dark: '#191a20',
    primary: '#3f4150',
    secondary: '#8c8d96',
  },
};

export default theme;
// theme.d.ts

import '@emotion/react';

declare module '@emotion/react' {
  export interface DefaultTheme {
    fontSizes: {
      xxs: string;
      xs: string;
      sm: string;
      base: string;
      md: string;
      lg: string;
    };
    colors: {
      black: string;
      dark: string;
      primary: string;
      secondary: string;
    };
  }
}

Responsive Layout

Styled Components 반응형 레이아웃 Commit 내역

Emotion + TypeScript 반응형 레이아웃 Commit 내역

utils/media

styled-components

styled-media-query 라이브러리를 사용하여 tablet, desktop 사이즈를 나누었다.

import { generateMedia } from 'styled-media-query'
import { theme } from '../index'

export const media = generateMedia({
  ...theme.breakpoints,
})

emotion

Emotion 문서를 참고하여, tablet, desktop breakpoints 를 설정하였다.

const breakpoints = [768, 1200];

export const media = breakpoints.map((bp) => `@media (min-width: ${bp}px)`);

Grid/styles

styled-components

위에서 styled-media-query 를 사용하여 media를 구현하였던 것을 사용하였다. tablet 과 desktop 으로 나누어 css 를 적용할 수 있다.

export const StyledContainer = styled.div`
 width: 100%;
 padding: 0 5px;
 margin: 0 auto;
 
 ${media.greaterThan('tablet')`
   max-width: 1020px;
   padding: 0 30px;
 `}
 
 ${media.greaterThan('desktop')`
   max-width: 1140px;
   padding: 0;
 `}
`;

emotion

export const StyledContainer = styled.div`
  width: 100%;
  padding: 0 5px;
  margin: 0 auto;
  ${media[0]} {
    max-width: 1020px;
    padding: 0 30px;
  }
  ${media[1]} {
    max-width: 1140px;
    padding: 0;
  }
`;

마치며

emotion 을 아직 제대로 학습하지 않아, 코드 구현이 미숙하지만 포트폴리오를 진행하며 꾸준히 배울 생각이다. styled-components, emotion 둘다 장점과 단점이 각각 존재하는 것 같다. 그래서 아직까지는 어떤 것이 더 좋은지는 잘 모르겠으나, 회사에 입사하였을 때 만약 emotion 을 사용한다고 할 수도 있으니 코드 구현시에 거부감이 들지않게 미리 배워놓는 것이 좋을 것 같다.

profile
꾸준히 새로운 것을 알아가는 것을 좋아합니다.

0개의 댓글