리액트 스타일링 - 전통적인 방식

#CSS #React

전통적인 방식

리액트 컴포넌트의 스타일을 지정하는 방법은 여러가지가 있는데, 전통적인 방식(CSS 파일 활용)으로는 인라인 스타일, 글로벌 스타일, CSS 모듈 세 가지로 나눌 수가 있다.

인라인 스타일

인라인 스타일(inline style)은 JSX 요소의 style 속성에 직접 스타일 객체를 지정하는 방식입니다.

인라인 스타일style 속성에 값을 직접 지정하는 방법이다. 이 때 style 속성의 값은 객체로 넣어야하고, 속성 이름은 카멜 케이스로, 값은 문자열로 적어야한다.

export default function App() {
	return (
		<button style={ { backgroundColor: 'red' } }>스타일 버튼</button>
	);
}

style 객체는 변수로 분리하여 return 문 바깥으로 뺄 수도 있다.

export default function App() {
	const styles = { backgroundColor: 'red' };
	return (
		<button style={ styles }>스타일 버튼</button>
	);
}

글로벌 스타일

글로벌 스타일(global style)이란 .css 확장자를 가진 파일에 CSS 코드를 작성하고, 이를 컴포넌트에서 import해 적용하는 방식입니다. 일반적으로 외부 스타일이라고 합니다.

글로벌 스타일별도의 .css 파일에 style을 지정하여 import 해서 사용하는 방법이다. 이 때 import한 css의 style은 리액트 앱 전역에 적용된다. 따라서 보통 main.tsx에서 .css 파일을 import하여 style이 적용되는 범위를 알기 쉽게 한다.

// App.css
.btn { background-color: red; }

// App.tsx
import './App.css' 

export default function App() {
	return (
		<button className='btn'>스타일 버튼</button>
	);
}

CSS 모듈

CSS 모듈(CSS module)은 파일 확장자가 .module.css로 끝나는 파일에 스타일을 작성한 뒤 이를 컴포넌트에서 불러와 사용하는 방식입니다.

CSS 모듈별도의 .module.css 파일에 style을 지정하여 import 해서 사용하는 방법이다. 글로벌 스타일과 다른 점은 style의 적용 범위가 전역이 아니라, import한 컴포넌트(로컬 스코프)라는 것이다. CSS 모듈을 쓰면 클래스 이름이 고유한 이름으로 자동으로 변환된다(빌드 시점에 클래스명 뒤에 고유한 해시값이 붙는다, 런타임에 확인 가능). 이를 통해 런타임에는 다른 컴포넌트와 클래스 네임이 중복되지 않아 로컬 스코프를 가질 수 있는 것이다. .module.css 파일은 .tsx 파일과 같은 이름으로 만드는 것이 관례이다. (ex. App.tsx - App.module.css)

// App.module.css
.btn { background-color: red; }

// App.tsx
import styles from './App.module.css' 

export default function App() {
	return (
		<button className={ styles.btn }>스타일 버튼</button>
	);
}

classnames

글로벌 스타일이나 CSS 모듈을 사용할 때 상황에 따라 클래스 이름을 조건부로 적용해야 하는 경우가 많습니다.classnames는 리액트를 포함한 자바스크립트 프레임워크에서 CSS 클래스 이름을 동적으로 조합하고 관리할 수 있게 도와주는 라이브러리입니다.

classnames문자열을 공백을 포함해 합쳐서 클래스 이름으로 반환해주는 npm 라이브러리로, 글로벌 스타일과 CSS 모듈을 사용할 때 활용하면 유용하다.

글로벌 스타일에서는 classnames는 문자열 합성 기능을 사용하여 바로 적용한다.

// App.tsx
import classNames from 'classnames'
import'./App.css' 

export default function App() {
	return (
		<button className={ classNames('btn', 'is_active') }>스타일 버튼</button>
	);
}

문자열 마다 조건을 넣는 것도 가능하다.

import classNames from 'classnames'
import './App.css' 

export default function App() {
	const isActive = true;
	return (
		<button className={ classNames('btn', { 'is_active': isActive }) }>스타일 버튼</button>
	);
}

CSS 모듈을 사용할 때는 classnames의 bind 패키지를 활용한다. bind 메서드를 사용하면 CSS 모듈 객체를 classNames 함수에 전달할 수 있다.

CSS 모듈 객체.module.css 확장자를 가진 CSS 파일을 컴포넌트에서 import 할 때 생성되는 객체를 의미합니다. 이 객체에는 정의된 클래스 이름이 키로, 고유한 해시가 적용된 클래스명이 값으로 들어 있습니다.

CSS 모듈은 런타임에 클래스 이름이 고유한 이름으로 변환이 되므로, 변환이 되기 전 클래스 명을 조합해서는 동작하지 않는다. 그래서 CSS 모듈 객체를 classnames/bind 패키지에 있는 bind 함수에 전달한다. CSS 모듈 객체와 bind 함수를 사용하면 컴포넌트 별로 고유한 이름을 가진 클래스의 이름을 조합할 수 있다.

import classNames from 'classnames/bind'
import styles from './App.module.css' 

export default function App() {
	const cx = classNames.bind(styles)
	const isActive = true;
	return (
		<button className={ cx('btn', { 'is_active': isActive }) }>스타일 버튼</button>
	);
}