중간 프로젝트에서 Emotion을 사용했었는데 기본적인 기능들만 사용하였고,
강력하고 편리한 심화 기능들을 잘 다루지 못해서 아쉬웠다.
특히, 반복되는 스타일을 재사용하지 못해서 코드가 쓸데없이 길어졌던 것 같다.
SASS의 경우 @mixin을 사용하면 이를 손쉽게 해결할 수 있었는데,
Emotion에서는 어떤 기능을 활용해 스타일을 재사용할 수 있을까? 그것이 궁금하다.
그 외에도 Emotion의 심화 기능들을 공부하여 이번 최종 프로젝트에서 잘 활용하고 싶다.
그런데 솔직히 말해, 나는 사실 Emotion을 별로 사용하고 싶지 않다.
스토리북과의 호환 문제, babel 설정 등 환경 구성을 할 때 여러모로 불편하기 때문이다.
하지만 팀원 대다수가 Emotion에 익숙하므로 나 혼자 다른 도구를 사용할 순 없는 일이다.
별로 좋아하지는 않지만, 잘 다룰 수 있도록 노력해야겠다.
1. 동적 스타일 구성하기
You can create dynamic styles that are based on props and use them in styles.
css 함수를 통해 props에 따라 동적으로 스타일 만들기.
스타일 재사용에도 유용할 것 같다.
예전에는 객체로 만들어 스타일을 적용했었는데 사용이 훨씬 편리하다.
import styled from '@emotion/styled'; import { css } from '@emotion/react'; type dynamicStyleProps = { color: string; }; const dynamicStyle = ({ color }: dynamicStyleProps) => css` color: ${color}; `; const Container = styled.div` ${dynamicStyle} `; const backgroundBlue = css` background-color: blue; `; const Emotion = () => { return ( <Container color="red"> happy <span css={backgroundBlue}>hello</span> </Container> ); }; export default Emotion;
import styled from '@emotion/styled'; import { css } from '@emotion/react'; import type { NextPage } from 'next'; const Home: NextPage = () => { return ( <> <Box backgroundColor="blue" color="white"> hello </Box> <span css={fontColor('red')}>red</span> </> ); }; const fontColor = (color: string) => css` color: ${color}; `; interface BoxProps { backgroundColor: string; color: string; } const Box = styled.div<BoxProps>` width: 100px; height: 100px; background-color: ${({ backgroundColor }) => backgroundColor}; ${({ color }) => color && fontColor(color)} `; export default Home;

다만, css 함수를 바로 사용하려 하면 오류가 발생한다.
css를 prop으로 전달 시 타입 오류 발생

해결안
- @emotion/babel-plugin, @emotion/babel-preset-css-prop 추가 설치
- tsconfig.json에 아래 옵션 추가

해결되었다. 더 이상 타입 오류가 발생하지 않는다.

역시 Emotion은 babel 설정도 해야하고 여러모로 불편하다.
이런 것들은 Emotion 측에서 오류가 없도록 깔끔하게 처리해야 하는 것 아닌가?
…하는 생각이 들면서도, 여러가지 복잡한 사정이 있을거라고 생각하며 이해해야겠다.
그래도 이렇게 라이브러리 세팅을 잘 하는 것도 개발자의 역량이니 인내심을 가져야겠다.
2. 스타일 혼합
css 함수는 기본적으로 mixin을 제공한다.
이를 사용하여 다양한 스타일을 조합할 수 있다.
import { css } from '@emotion/react'; const pinkColor = css` color: hotpink; `; const defaultStyle = css` font-size: 52px; `; const mixedTextStyles = css` ${defaultStyle} ${pinkColor} `; function Emotion() { return <div css={mixedTextStyles}>헬로우</div>; } export default Emotion;
3. 스타일 확장
기존의 스타일을 확장하는 것도 물론 가능하다.
이전에도 알고 있었던 것이지만 다시 정리해보았다.
import styled from '@emotion/styled'; const App = () => ( <> <Button>버튼</Button> <BlueButton>파란버튼</BlueButton> </> ); const Button = styled.button` outline: none; border: none; border-radius: 50%; `; const BlueButton = styled(Button)` background-color: blue; `; export default App;
4. withComponent
Sometimes you want to create some styles with one component but then use those styles again with another component, the withComponent method can be used for this.
예: button 태그에 적용한 스타일을 a 태그에 적용하고 싶을 때 사용한다.
import styled from '@emotion/styled'; const Button = styled.button` color: red; `; const A = Button.withComponent('a'); const Emotion = () => { return ( <A href="https://github.com/emotion-js/emotion" target="_blank"> Emotion on GitHub </A> ); }; export default Emotion;
5. Customizing prop forwarding
By default, Emotion passes all props (except for
theme
) to custom components and only props that are valid html attributes for string tags. You can customize this by passing a custom shouldForwardProp
function.You can also use @emotion/is-prop-valid to filter out props that are not valid as html attributes.
props에 대한 유효성 검사 & 필터링을 할 수 있다.
@emotion/is-prop-valid를 추가 설치해야 한다.
import isPropValid from '@emotion/is-prop-valid'; import styled from '@emotion/styled'; const H1 = styled('h1', { shouldForwardProp: (prop) => isPropValid(prop) && prop !== 'color', })((props) => ({ color: props.color, })); const Emotion = () => { return <H1 color="red">This is lightgreen</H1>; }; export default Emotion;
더 알아보기
- SASS의 믹스인과 유사한 기능은 Emotion에서 무엇인가? (스타일 재사용)
- styledComponent를 가리키는 type도 있는가? ⇒ StyledComponent