안녕하세요. 오픈소스컨설팅에서 프론트엔드 개발자로 일하고 있는 Playce Dev팀 김기정입니다! 오늘은 제목처럼 웹 애플리케이션에 Emotion을 활용한 스타일을 추가하는 방법에 대해서 적어보려고 합니다.

자, 이제 시작해볼까요?

세상엔 수많은 애플리케이션이 존재합니다. 우리가 늘 보고 사용하던 애플리케이션이 스타일 없이 투박한 모습이라면 어떨까요?🤔 스타일이 없다면 무언가 부족하고 없어 보이는(?) 느낌이 강하게 들게 될 것입니다. 그만큼 시각적인 완성도를 높이기 위해서는 스타일 적용은 매우 중요한 일인데요. 이번 글에서는 Emotion을 이용하여 애플리케이션에 스타일을 입히는 방법에 대해 알아보도록 하겠습니다.😎


Emotion이란 무엇인가

Emotion은 Javascript로 CSS 스타일을 작성하기 위한 라이브러리입니다. nested selectors, media queries 등이 적용되어 작성이 간편하며, 동적 스타일 적용이 자유롭고 확장 및 재사용이 용이합니다. 스타일은 template literal 방식과 object 방식으로 작성할 수 있습니다. 작성된 스타일은 해당 컴포넌트가 렌더링 될 때만 적용한 스타일의 태그를 생성하며, 스타일 요소들은 자동으로 class 이름이 부여되어 중복이 발생할 염려가 없습니다. 공식 문서

애플리케이션에 스타일을 입혀보자

본격적으로 Emotion을 사용하여 컴포넌트들을 스타일링 해보겠습니다. Emotion을 사용하기 위한 방법에는 2가지가 있습니다. 첫 번째는 Framework Agnostic(framework를 사용하지 않는 것)이고 React와 함께 사용하는 것입니다. 우리는 React와 함께 사용하는 방법에 대해 자세히 알아보겠습니다.

💡  Framework Agnostic 방법을 짧게 써보자면,
@emotion/css 패키지를 설치(yarn add @emotion/css) 하고 아래와 같이 사용하면 됩니다.

import { css } from '@emotion/css'
.....
render (
       <div className={css({ width: 30, height: 30, color: 'red'})}/>
)
....

(@emotion/react 패키지의 css 와는 내부적으로 동작하는 방식이 다르다고 합니다.😏)

@emotion/styled

스타일을 주기 위한 첫 번째 방법은 styled 입니다. styled를 사용하기 위해서는 @emotion/styled 패키지를 설치해야 합니다.

yarn add @emotion/styled

@emotion/styled 패키지는 styled-component에서 영향을 받아 만들어진 패키지인 만큼 작성 방법이 styled-component와 매우 유사합니다. 스타일은 template literal방식과 object방식으로 작성할 수 있습니다.

컴파일 된 HTML코드를 살펴보면 화면에 렌더링 된 컴포넌트에 적용된 스타일 태그들이 생성되었고, 엘리먼트 class명이 자동으로 이름 중복없이 부여된 것을 확인할 수 있습니다.

props 넘겨주기

styled Component에 props를 넘겨주면 기존에 조건에 따라 스타일 변경을 해야할 때 사용하던 classNames.bind 를 사용하지 않고도 동적으로 스타일을 변경할 수 있습니다.

태그 변경하여 스타일 재사용하기

기존에 작성한 styled component의 tag를 변경하고 싶다면 withComponent를 이용합니다. 간단하게 스타일 재사용이 가능합니다.

컴파일 된 HTML코드를 살펴보면 divbutton이 같은 class명을 가지고 동일한 스타일이 적용된 것을 확인할 수 있습니다.

CSS selectors처럼 작성한 styled component 사용하기

@emotion/bable-plugin 패키지를 사용하면 CSS selectors처럼 다른 emotion styled component를 대상으로 선택할 수 있습니다.

yarn add @emotion/babel-plugin

@emotion/react

@emotion/react 패키지의 css prop을 활용하면 굳이 styled component를 만들지 않고도 스타일을 지정해 줄 수 있습니다.

yarn add @emotion/react

css prop를 사용하기 위해선 JSX Pragma를 작성해야 합니다. css prop을 사용하려는 코드 상단에 아래와 같이 작성해 줍니다.

/** @jsxImportSource @emotion/react */

import { css } from "@emotion/react";
💡  typescript 컴파일 옵션에 아래와 같이 jsxImportSource를 설정해 주어도 jsx pragma를 작성하지 않으면 에러가 발생합니다. react-scripts가 Typescript의 jsxImportSource를 옵션을 무시하고 있기 때문입니디. 현재(v5.0)까지 이슈가 해결되지 않았으니 jsx pragma를 꼭 설정해 주어야 합니다.  이슈 링크

// tsconfig.json
     {
        "compilerOptions": {
        ...,
       "jsxImportSource": "@emotion/react"
      },
...}

매번 번거롭게 pragma를 선언하고 싶지 않다면 Babel preset 설정을 해줘야 합니다.

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

자. 이제 css prop기능을 이용하여 스타일을 적용해 보겠습니다. inline style과 비슷해 보이지만 inline style과 달리 media query 및 pseudo selector, nested selector 등을 사용할 수 있습니다. 스타일은 template literal방식과 object방식으로 작성할 수 있습니다.

컴파일 된 HTML코드를 살펴보면 class 프로퍼티에 중복 없이 이름이 부여되어 스타일이 적용된 것을 확인할 수 있습니다. 기존 style 프로퍼티는 inline 스타일로 주입이 되어서 우선순위를 다루기 어렵고 재활용도 힘들지만, css prop기능을 활용하면 보다 쉽게 스타일 반영이 가능합니다.

여러 스타일 적용하기

여러 스타일을 적용하고 싶을 때는 array형식으로 작성합니다. array의 index가 클수록 우선순위가 높습니다.

컴파일 된 HTML코드를 살펴보면 두 개의 스타일을 넘겨주었지만 한 개의 class로 생성되었고, array 내에서 뒤에 작성한 스타일 요소가 적용된 것을 확인할 수 있습니다.

중첩 요소 선택하기

중첩된 요소를 선택할 때는 다음과 같이 사용합니다.

Label 설정하기

css에 label이라는 property가 추가되어 있습니다. 앞에서 Emotion은 자동으로 class 이름을 부여한다고 했는데요. label에 값을 입력하면 클래스명 끝에 추가 되어 class를 보다 쉽게 읽고 판단할 때 용이합니다.

💡  @emotion/babel-plugin 패키지를 사용하면 매번 입력하지 않아도 labeling을 할 수 있으며 커스터마이징도 가능합니다.

// .babel.rc
{
    "plugins": [
      [
          "@emotion",
            {
                "autoLabel": "dev-only",
                "labelFormat": "[local]",
             }
        ]
    ]
}

@emotion/react 패키지에는 css prop말고도 유용한 기능들이 더 있습니다.

Global

font-face나 전역에 베이스가 되는 스타일을 주고 싶을 때는 Global Style을 지정합니다.

Theme

emotion에서는 ThemeProvider를 제공해주고 있습니다. theme를 적용하기 위해서는 먼저 theme 속성에 들어갈 타입을 정의합니다. 그리고 정의한 Theme type에 맞추어 theme를 정의하고 정의한 theme를 App의 가장 top level에서 ThemeProvider 를 이용하여 공급해줍니다.

css prop과 styled로 정의된 StyledComponent를 확인해보면 다음과 같이 정의되어 되어있습니다.

따라서 방식에 따라 theme를 꺼내어 사용합니다. props에서 꺼내는 방식말고도 현재 테마를 값으로 제공하는 useTheme 훅을 사용하는 방법도 있습니다. theme가 업데이트되면 그에 따라 하위 구성 요소가 다시 렌더링됩니다.

마치며

기존 프로젝트에서 sass로 스타일 작업을 진행하다 보면 특별한 기능도 없는 컴포넌트의 클래스 이름을 지어야 할 때 네이밍에 대한 고민은 항상 따라왔습니다. 프로젝트가 커가면서 관리해야 할 많은 css 파일들이 생겨나고, 사용하지 않는 스타일 요소들을 찾기가 어려워졌습니다. 또한 중복되는 class명과 css 우선순위로 인해 스타일이 꼬이고 !important를 쓰게 되는 경우가 잦아지기도 했습니다.

emotion을 사용하면 필요한 컴포넌트가 렌더링 될 때만 스타일 태그를 생성하기 때문에 컴포넌트 위주인 프로젝트에 고려해 볼 만하다고 생각합니다. 컴포넌트 레벨로 관리하기도 편리하고 기존 프로젝트 스타일 적용 방식에서 느꼈던 어려움이 조금은 해소되리라 기대됩니다.😎

Home » Posts » Technology » Development » 웹 애플리케이션에 스타일 추가하기 with Emotion

Playce Dev팀의 긍정 아이콘, 프론트엔드 개발자 김기정입니다. 고민하고 생각하며 개발하는 시간이 가장 즐겁습니다!

Leave a Reply

Your email address will not be published. Required fields are marked *