Emotion

yunbiyomi·2023년 11월 15일

📌 Emotion이란?

Javascript의 CSS-in-JS 라이브러리 중 하나로, 스타일을 자바스크립트 파일 내에서 정의하고 관리할 수 있게 해주는 도구이다. 이를 통해 컴포넌트 기반의 웹 애플리케이션에서 스타일을 효율적으로 다룰 수 있다.



🔷 특징

Tagged Template Literals

Tagged Template Literals을 사용해 스타일을 정의한다.
이를 통해 자바스크립트 파일 안에서 CSS를 작성하고 변수와 조건문을 활용하여 동적인 스타일 생성이 가능하다.

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

const container = css`
  color: black;
  font-size: 20px;
`;

CSS-in-JS

스타일을 자바스크립트 객체로 표현한다.
이를 통해 컴포넌트 스코프 내에서 스타일 충돌을 방지하고, 재사용 가능한 스타일을 만들 수 있다.

Styled Components

styled 함수를 통해 컴포넌트에 대한 스타일을 직접 정의하고, 이 스타일이 컴포넌트와 결합된다.

import styled from '@emotion/styled';

const Container = styled.div`
  color: black;
`;

퍼포먼스 최적화

스타일을 자동으로 최적화하여 불필요한 렌더링을 방지하고 높은 퍼포먼스를 유지할 수 있도록 지원한다.

SSR 지원

서버 사이드 렌더링을 지원하며, 서버와 클라이언트 간의 일관된 스타일을 유지할 수 있다.





🔷 설치

🌐 공식 홈페이지: https://emotion.sh/docs/introduction

공식 홈페이지에 들어가면 3개의 방식이 있다.


1. Framework Agnostic
프레임워크의 API나 규칙에 의존하지 않고 일반적인 방식으로 코드를 작성할 때 설치

npm i @emotion/css

< 사용 예시 >

import { css } from '@emotion/css'

const color = 'white'

render(
  <div
    className={css`
      padding: 32px;
      background-color: hotpink;
      font-size: 24px;
      border-radius: 4px;
      &:hover {
        color: ${color};
      }
    `}
  >
    Hover to change color.
  </div>
)

  1. React
    가장 기본적인 설치
npm i @emotion/react

< 사용 예시 >

import { css } from '@emotion/react'

const color = 'white'

render(
  <div
    css={css`
      padding: 32px;
      background-color: hotpink;
      font-size: 24px;
      border-radius: 4px;
      &:hover {
        color: ${color};
      }
    `}
  >
    Hover to change color.
  </div>
)

  1. Styled-components
    styled-components처럼 사용하고 싶을 때 설치
npm i @emotion/styled @emotion/react

< 사용 예시 >

import styled from '@emotion/styled'

const Button = styled.button`
  padding: 32px;
  background-color: hotpink;
  font-size: 24px;
  border-radius: 4px;
  color: black;
  font-weight: bold;
  &:hover {
    color: white;
  }
`

render(<Button>This my button component.</Button>)





🔷 실습

Emotion 사용법을 익히기위해 간단히 Google API를 통해 책을 검색하는 사이트를 만들어보려고 한다.

Global Style 설정

🔹참고 : https://emotion.sh/docs/globals

Global Style을 설정하는 것은 간단하다.
Global과 css를 import해주고
<Global styles={css``} /> 이러한 양식 안에 우리가 원래 사용하던 CSS 방식을 사용하면 된다.

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

const Layout = () => {
  return (
    <>
      <Global 
        styles={css`
          body {
            background-color: #F2F4F3;
            color: #0A0908;
            transition-duration: .2s;
            transition-property: background-color, color;
          }
          a {
            color: #0A0908;
            text-decoration: none;
          }
          ul {
            list-style: none;
            padding: 0;
          }
        `}
      />
      <Outlet />
    </>
  )
}



⛔ 에러 발생

Global Style 적용 했을 때에는 분명 제대로 잘 적용이 되었는데
Footer에 적용해보니 스타일이 적용되지 않았다.

      <button
        css={css`
          background-color: #F2F4F3;
          color: #0A0908;
          border: 1px solid #0A0908;
          padding: .6rem, 1.5rem;
          margin-left: 15px;
          border-radius: 3px;
          cursor: pointer;
          
          &:hover {
            transform: translate(-2px);
          }
      `}>
        Dark Mode
      </button>

맞게 잘 작성한 것 같은데 왜 그런지 찾아보다가 개발자 도구로 코드를 확인해보니

이런 문구들이 추가되어있었다.

이러한 현상은 리액트가 런타임 도중 해당 줄을 이해하지 못해서 발생한다고 한다.

두가지 해결 방법이 있는데

  1. Emotion이 React를 어떻게 가져와야 하는지 명시적으로 지정하는 방법
    코드에 아래의 코드를 추가해주면 해결 가능하다.
/** @jsxImportSource @emotion/react */
  1. styled-components 형식을 사용하는 방법
    위에 설치의 3번째 방식을 사용하면 해결 가능하다.

나는 1번째 방법을 사용하여 해결하였다.



왜 처음에 Global 스타일을 지정할때는 에러가 발생하지 않았을까❓

<Global />은 Emotion의 Global 스타일을 전역으로 적용하는 컴포넌트인데 이것은 JSX 문법을 사용하지만 특정 리액트 컴포넌트를 가져오는것은 아니기 때문에 오류가 발생하지 않는다.



Theme 설정

🔹참고 : https://emotion.sh/docs/theming

theme.js에

export const themLight = {
  text: "#221F1B",
  background: "#DED6CE"
}

export const themDark = {
  text: "#F2F4F3",
  background: "#5E503F"
}

이렇게 각 테마에 맞는 색을 지정해준 뒤
App.js로 돌아와 테마를 적용할 부분을 <ThemeProvider />을 이용해 감싸주면 된다.

function App() {
  const [isDark, setIsDark] = useState(false);
  return (
    <BrowserRouter>
      <ThemeProvider theme={isDark ? themDark : themLight}>
    	{...}
      </ThemeProvider>
    </BrowserRouter>
  );
}

그리고 useTheme() hook을 이용하여 theme의 속성들을 알맞은 자리에 넣어주면 끝이다.

const Layout = ({ isDark, setIsDark }) => {
  const theme = useTheme();
  return (
    <>
      <Global 
        styles={css`
          body {
            background-color: ${theme.background};
            color: ${theme.text};
      />
  )
}

footer만 보자면 이렇게 잘 적용된걸 볼 수 있다.





🔷 완성

🌐 완성 사이트: https://find-book-one.vercel.app/
🌳 Git: https://github.com/yunbiyomi/find-book

profile
새로움을 두려워 하지 않는 도전하는 프론트엔드 개발자👩‍💻

0개의 댓글