본문 바로가기
개발 기록/front - react

Emotion 라이브러리 - React 프로젝트의 디자인 관리

by jeong11 2024. 12. 30.
반응형

 

※ 체크리스트

① Emotion 라이브러리의 개념과 CSS-in-JS 방식의 장점을 이해하기

② Emotion을 활용해 React 프로젝트에 스타일링을 적용하는 방법을 학습하기

③ Emotion의 고급기능(동적 스타일링, 테마, 애니메이션) 익히기

 

1. Emotion

1-1. Emotion 정의

Emotion : CSS-in-JS 방식의 강력한 스타일링 라이브러리, JavaScript 코드 내에서 스타일을 작성하고 컴포넌트 별로 적용할 수 있다 

 

1-2. Emotion의 특징

1) CSS와 JavaScript의 통합 :

스타일과 로직을 한 파일에 작성 가능하다 

 

2) 동적 스타일링 지원

props와 상태에 따라 스타일 변경이 가능하다

 

3) 높은 성능

스타일이 필요한 시점에만 동적으로 생성과 적용이 가능하다 

 

4) 다양한 스타일링 방식 지원

css 함수, styled API, 객체 스타일링 방식을 지원한다 

 

 

2. Emotion 기본 사용법

2-1. 설치

npm install @emotion/react @emotion/styled

 

2-2. 사용법

css 함수를 사용한 스타일 적용, styled API를 사용하는 스타일링 방식 두 가지가 있다 

 

1) css  함수 사용

css 함수는 Emotion의 기본 스타일링 방식 중 하나로,  

CSS-in-JS 방식으로 스타일을 작성해 해당 스타일을 컴포넌트의 css prop에 직접 전달한다 

 

① 사용법 예시 

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

const buttonStyle = css`
	background-color: blue;
	color: white;
	padding: 10px 20px;
	border: none;
	border-radius: 5px;
	cursor: pointer;

	&:hover {
    	background-color: darkblue;
	}
	`;
    
function App() {
	return <button css={buttonStyle}>Click Me</button>
}

export default App;

● css  스타일 코드를 템플릿 리터럴(' ') 안에 작성한다 

● Emotion은 css prop을 사용해 스타일을 전달할 수 있다 

 

② 장점 : 

특정 스타일을 여러 컴포넌트에 재사용하기 쉽고 기존 스타일 객체와 결합하기도 용이하다 

 

2) styled API 사용

HTML 요소 또는 React 컴포넌트를 기반으로 새로운 스타일 컴포넌트를 생성한다 

 

① 사용법 예시

import styled from '@emotion/styled';

const Button = styled.button'
	background-color: blue;
	color: white;
	padding: 10px 20px;
	border: none;
	border-radius: 5px;
	cursor: pointer;
    
	&:hover {
		background-color: darkblue;
	}
';

function App() {
	return <Button>Click Me</Button>
}

export default App;

특정 HTML 태그(button, div, p 등)을 래핑하여 스타일을 가진 새로운 컴포넌트를 만든다 

 

② 장점 : 

HTML 태그가 아닌 React 컴포넌트를 래핑하여 더 높은 재사용성을 제공한다 

코드가 깔끔하고 가독성이 좋다 

 

3) css 함수와 styled API의 차이점과 활용

특징 css 함수 styled API
스타일 재사용 재사용 가능(스타일 변수를 여러 곳에 전달) 재사용 가능(컴포넌트를 여러 곳에서 사용)
가독성 JSX 코드가 스타일과 함께 섞일 수 있다 스타일 코드와 컴포넌트 구조가 더 명확하다 
동적 스타일링 스타일 내부에서 props를 사용할 때 약간 복잡할 수 있다 props를 통해 동적 스타일링이 간편하다
추천 사용 사례 간단한 컴포넌트 또는 동적 스타일 적용 시 재사용 가능한 컴포넌트 스타일링 시 사용

 

 

3. Emotion의 동적 스타일링과 고급 기능을 한 프로젝트에서 실행해보며 해당 내용을 공부해보겠다 

3. Emotion의 동적 스타일링과 고급기능

3-1. 동적 스타일링 적용

1단계 : props 기반 스타일링

styled API에서 props를 사용해 동적으로 스타일 변경 

// props 기반 동적 스타일링
const Button = styled.button`
	background-color: ${(props) => (props.primary ? 'blue' : 'gray')};
	color: white;
	padding: 10px 20px;
	border: none;
	border-radius: 5px;
	cursor: pointer;
    
	&:hover {
    	background-color: ${(props) => (props.primary ? 'darkblue' : 'darkgray')};
	}
`;

function App() {
	return (
		<div>
			<Button primary>Primary Button</Button>
			<Button>Secondary Button</Button>
		</div>
	);
}

 

2단계 : 객체 스타일링

css 함수에서 객체 형태로 스타일 정의

// 객체 스타일링
const buttonStyle = {
	background: 'blue',
	color: 'white',
	padding: '10px 20px',
	border: 'none',
	borderRadius: '5px',
	cursor: 'pointer',
	'&:hover': {
    
	},
};

function App() {
	return <button css={buttonStyle}>Click Me</button>
}

 

 

3-2. 고급 기능 스타일링 적용

1단계 : 글로벌 스타일

Global 컴포넌트를 사용해 전역 스타일 정의 

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

const globalStyle = css`
	body { 
		margin: 0;
		font-family: Arial, sans-serif;
		background-color: #f0f0f0;
	}
`;

function App() {
	return (
		<Global styles={globalStyle} />
		<h1>Emotion</h1>
	);
}

export default App;

 

2단계 : 테마 기반 스타일링

ThemeProvider를 사용해 테마 적용 

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

const theme = {
	primary: 'blue',
	secondary: 'gray',
};

const Button = styled.button`
	background-color: ${(props) => props.theme.primary};
	color: white;
	padding: 10px 20px;
`;

function App() {
	return (
		<ThemeProvider theme={theme}>
			<Button>Styled Button</Button>
		</ThemeProvider>
    );
}

export default App;

 

3단계 : 애니메이션

keyframes를 사용해 애니메이션 적용

import { keyframes } from '@emotion/react';
import styled from '@emotion/styled';

const fadeIn = keyframes`
	from {
		opacity: 0;
	}
	to {
		opacity: 1;
	}
`;

const AnimatedDiv = styled.div`
	animation: ${fadeIn} 2s ease-in-out;
`;

function App() {
	return <AnimatedDiv>Fading In</AnimatedDiv>;
}

 

3-3. 전체 코드 및 실행

1) 프로젝트 생성

npx create-react-app react-emotion-styling

 

2) Emotion 라이브러리 설치

npm install @emotion/react @emotion/styled

설치 완료!

 

3) App.js 코드 수정 

App.js 파일 화면

* 전체 코드

/** @jsxImportSource @emotion/react */
import { css, Global, keyframes } from '@emotion/react';
import styled from '@emotion/styled';
import { ThemeProvider } from '@emotion/react';

// 1. 고급 기능 스타일링 적용 - 1단계 : 글로벌 스타일 정의
const globalStyle = css`
	body {
		margin: 0;
		font-family: Arial, sans-serif;
		background-color: #f0f0f0;
	}
`;

// 2. 고급 기능 스타일링 적용 - 2단계 : 테마 정의
const theme = { 
	primary: 'blue',
	secondary: 'gray',
};

// 3. Emotion의 동적 스타일링 적용 - 1단계 : props 기반 동적 스타일링
const Button = styled.button`
	background-color: ${(props) => (props.primary ? props.theme.primary : props.theme.secondary)};
	color: white;
	padding: 10px 20px;
	border: none;
	border-radius: 5px;
	cursor: pointer;
    
	&:hover {
    	background-color: ${(props) => (props.primary ? 'darkblue' : 'darkgray')};
	}
`;

// 4. Emotion의 동적 스타일링 적용 - 2단계 : 객체 스타일링 
const buttonStyle = {
	backgroundColor: 'blue',
	color: 'white',
	padding: '10px 20px',
	border: 'none',
	borderRadius: '5px',
	cursor: 'pointer', 
	'&:hover': {
    	backgroundColor: 'skyblue',
	},
};

// 5. 고급 기능 스타일링 적용 - 3단계 : 애니메이션 적용
const fadeIn = keyframes`
	from {
		opacity: 0;
	} 
	to {
		opacity: 1;
	}
`;

const AnimatedDiv = styled.div`
	animation: ${fadeIn} 2s ease-in-out;
	margin: 20px 0;
`;

function App() {
	return (
    	// 테마 기반 스타일 적용
		<ThemeProvider theme={theme}>
			{/* 글로벌 스타일 적용*/}
			<Global styles={globalStyle} />
			<h1 css={{ textAlign: 'center' }}>Emotion Demo</h1>
        	
			{/* 동적 스타일링 적용 - 1단계 : props 기반 스타일링 */}
			<div css={{ textAlign: 'center', marginBottom: '20px' }}>
				<Button primary>Primary Button</Button>
				<Button style={{ marginLeft: '10px' }}>Secondary Button</Button>
			</div>
            
			{/* 동적 스타일링 적용 - 2단계 : 객체 스타일링 */}
			<div css={{ textAlign: 'center' }}>
				<button css={buttonStyle}>Click Me</button>
			</div>
            
			{/* 애니메이션 */}
			<AnimatedDiv css={{ textAlign: 'center' }}>Fading In Animation</AnimatedDiv>
            
		</ThemeProvider>
	);
}

export default App;

 

4) 실행

npm start

 

5) 화면 및 결과 

프로젝트 실행 Emotion styling

① 글로벌 스타일 : Global 컴포넌트를 사용해 전역 스타일(body 배경 컬러, 폰트 등) 설정해주었다 

② 테마 기반 동적 스타일링 : ThemeProvider를 사용해 primary와 secondary 색상을 전달하며 props를 활용해 버튼 스타일이 동적으로 변경된다 

③ 객체 스타일링 : css 함수 대신 객체 형태로 스타일을 정의하여 버튼에 적용한다

④ 애니메이션 : keyframes로 정의한 페이드 인 애니메이션을 AnimatedDiv 컴포넌트에 적용한다 

 

● 페이지 상단에 Emotion Demo 표시 

● 두 개의 버튼 : Primary Button, Secondary Button(props 기반 스타일링)

● 객체 스타일로 만든 버튼 : Styled with Object

● 페이드 인 애니메이션 효과를 가진 텍스트 Fading In Animation

 

 

4. 실습 과제

4-1. 실습 목표

① Emotion을 사용해 Card 컴포넌트를 생성하고 제목과 내용을 스타일링하기

② props를 활용해 primary 및 secondary 버튼 스타일을 동적으로 변경하기

③ 테마를 정의하여 컬러, 폰트 스타일을 중앙에서 관리하기 

 

 4-2. React 프로젝트 준비

1) 프로젝트 생성

cmd 명령창으로 실행

npx create-react-app react-emotion-practice

 

2)  Emotion 라이브러리 설치

명령창을 켠 김에 여기서 emotion 설치도 진행

npm install @emotion/react @emotion/styled

 

 

4-3. 코드 구현

* 사용 프로그램 : VSCode

 

1)  계획 : App.js만 수정할 예정 

 

2)  App.js에서 모든 구현이 가능한 이유

ⓘ Emotion의 유연성 : styled와 css를 활용해 한 파일에서 모든 스타일을 작성할 수 있음 

ThemeProvider : 테마를 최상위에서 정의하여 모든 하위 컴포넌트에 스타일을 쉽게 전달할 수 있음 

글로벌 스타일 : Global로 공통 스타일을 설정해, 추가적인 CSS 파일이 필요하지 않음

 

3) 코드 작성

> App.js 수정 

스타일 정의들
return 값 부분

* 전체 코드

// App.js
/** @jsxImportSource @emotion/react */
import { css, Global } from '@emotion/react';
import styled from '@emotion/styled';
import { ThemeProvider } from '@emotion/react';

// 1. 글로벌 스타일 정의
const globalStyle = css`
	body {
		margin: 0;
		font-family: 'Arial', sans-serif;
		background-color: #f9f9f9;
	}
`;

// 2. 테마 정의
const theme = {
	colors: {
		primary: '#007bff',
		secondary: '#6c757d',
		text: '#212529',
		background: '#ffffff',
	},
	fonts: {
		main: 'Arial, sans-serif',
	},
};

// 3. Card 컴포넌트 스타일
const Card = styled.div`
	background-color: ${(props) => props.theme.colors.background};
	border: 1px solid ${(props) => props.theme.colors.secondary};
	border-radius: 8px;
	padding: 16px;
	margin: 16px;
	box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
	text-align: center;
    
	h2 { 
		color: ${(props) => props.theme.colors.primary};
		margin-bottom: 8px;
	}
    
	p {
		color: ${(props) => props.theme.colors.text};
		font-size: 16px;
	}
`;

// 4. Button 컴포넌트 스타일
const Button = styled.button`
	background-color: ${(props) => (props.primary ? props.theme.colors.primary : props.theme.colors.secondary)};
	color: #fff;
	padding 10px 20px;
	border: none;
	border-radius: 5px;
	cursor: pointer;
	font-size: 14px;
	margin: 0 8px;
    
	&:hover {
		background-color: ${(props) => (props.primary ? '#0066b3' : 'skyblue')};
    }
`;

// 5. App 컴포넌트
function App() {
	return (
		<ThemeProvider theme={theme}>
			{/* 글로벌 스타일 적용 */}
			<Global styles={globalStyle} />
        
			{/* Card 컴포넌트 */}
			<Card>
				<h2>Emotion Card</h2>
				<p>This is a card styled with Emotion and theming</p>
				<div>
					{/* 동적 버튼 스타일링 */}
					<Button primary>Primary Button</Button>
					<Button>Secondary Button</Button>
				</div>
			</Card>
		</ThemeProvider>
	);
}

export default App;

 

 

4-4. 실행 

npm start

 

1) 화면 

npm 스타트
마우스 hover
오른쪽 버튼에 마우스를 올렸을 때

 

2) 설명

① Card 컴포넌트 : 

제목 : 파란색(primary color) 

배경 : 흰색

 

② Buttons 

● Primary 버튼 : blue background 

● Secondary 버튼 : 회색 background 

 

 

+ git에 REACT-EMOTION-STYLING과 REACT-EMOTION-PRACTICE로 업로드! 

 

 

※ 정리

① Emotion과 styled Components의 공통점과 차이점은 ? 

→ Emotion과 styled Components는 CSS-in-JS 라이브러리로, JavaScript 코드 내에서 CSS 스타일을 작성할 수 있다 

공통점

CSS-in-JS 방식 : 컴포넌트 단위로 스타일을 작성 

스타일 동적 처리 : props를 사용해 스타일을 동적으로 변경할 수 있다 

지원 브라우저 : 최신 브라우저와 IE11 이상을 지원한다 

SSR 지원 : 서버사이드 렌더링(SSR) 지원한다 

 

차이점

특징 Emotion Styled Components
유연성 다양한 스타일링 접근법을 지원
(css, styled, Global, keyframes 등)
styled 기반 API만 제공
퍼포먼스 Emotion은 런타임 최적화 및 정적 추출 기능이 존재 > 퍼포먼스가 우수함   런타임이 빠르지만 Emotion의 정적 추출에는 뒤처질 수 있음
파일 크기 더 작은 패키지 크기를 가지고 있으며 필요에 따라 모듈만 설치 가능함
(@emotion/react , @emotion/styled)
styled Components는 Emotion보다 상대적으로 패키지 크기가 더 큼
스타일링 방식 css 함수를 통해 객체 스타일링과 클래식 CSS 문자열 스타일링을 지원함  CSS 문자열 스타일링 방식만 제공함 
테마 사용 테마 지원(ThemeProvider) 과 사용자 정의가 유연함  테마 지원은 있지만 Emotion처럼 다양한 방식으로 접근하지 못함 
커뮤니티 및 에코시스템 styled Components보다 상대적으로 작은 사용자 기반을 가지고 있지만, 최근 들어 빠르게 성장 중  넓은 커뮤니티와 오래된 에코시스템을 가지고 있음 

 

 

② Emotion은 대규모 프로젝트에서 어떻게 사용할 수 있을까? 

→ 성능 최적화와 유연한 설정이 필요한 대규모 프로젝트에서 관리성과 재사용성을 극대화할 수 있다 

→ 사용 방법 

▶ 1. 글로벌 스타일과 테마 관리 (Global 스타일 정의, ThemeProvider 활용)

const theme = {
	colors: {
		primary : '#007bff',
		secondary: '#6c757d',
	},
	spacing: {
		small : '8px',
		medium : '16px',
		large : '24px',
	}, 
};

<ThemeProvider theme={theme}>
	<App />
</ThemeProvider>

 

▶ 2. 컴포넌트 기반 스타일링 : Emotion의 styled를 사용해 기본 컴포넌트를 만들어 재사용한다 

const PrimaryButton = styled.button`
	background-color : ${(props) => props.theme.colors.primary};
	padding : ${(props) => props.theme.spacing.medium};
	color : white;
`;

 

▶ 3. 동적 스타일링 : 컴포넌트에 props를 전달해 스타일을 동적으로 변경 

const Button = styled.button`
	background-color: ${(props) => (props.primary ? props.theme.colors.primary : props.theme.colors.secondary)};
`;

 

▶ 4. 모듈화된 스타일링 : 각 컴포넌트의 스타일을 별도의 파일에 저장하고 컴포넌트에 필요할 때만 로드

// styles/button.js
export const buttonStyle = css`
	background-color: blue;
	color: white;
`;

// Button.jsx
import { buttonStyle } from './styles/button';
function Button() {
	return <button css={buttonStyle}>Click Me</button>;
}

 

▶ 5. 코드 스플리팅

- Emotion은 코드 스플리팅을 지원하여, 필요한 스타일만 번들에 포함되도록 최적화함 

- 정적 CSS 추출을 사용해 런타임에서 스타일 생성 비용을 줄일 수 있음 

 

▶ 6. SSR(Server-Side-Rendering)

- Emotion은 서버사이드 렌더링을 지원하며 Next.js 같은 프레임워크와 쉽게 통합이 가능함 

 

 

 

☞ Emotion은 CSS와 JavaScript를 통합해 강력한 스타일링 도구를 제공한다 

☞ css 함수, styled API, 글로벌 스타일 및 테마 등 다양한 기능을 활용해 스타일을 관리할 수 있다

☞ 동적 스타일링과 성능 최적화에 강점을 가지며, React 프로젝트에 적합한 CSS-in-Js 솔루션이다 

반응형