이 글은 Udemy의 【한글자막】 React 완벽 가이드 2025 with React Router & Redux 를 수강하고 정리한 내용입니다.
🎈 바닐라 CSS 스타일 컴포넌트에 스코핑 방법
리액트에서 바닐라 CSS를 사용하는 경우, CSS가 리액트 컴포넌트에 스코프가 자동으로 적용되지 않습니다. 이는 CSS가 전역적으로 적용되기 때문에, 컴포넌트가 여러 개 있을 때 스타일이 서로 충돌할 수 있습니다.
즉, 같은 페이지에 존재하는 A 컴포넌트와 B 컴포넌트가 존재한다고 할때, A 컴포넌트의 스타일에 필요한 css가 B컴포넌트의 스타일에 영향을 미칠 수 있습니다. 이를 해결하기 위해서 리액트 컴포넌트에 CSS를 스코프(scope)하기 위해 몇가지 방법을 소개해드리겠습니다.
1️⃣ style Prop 사용하여 Inline(인라인)으로 css 적용하기
style Prop을 사용해서 CSS를 자바스크립트 객체로 작성하여 JSX에서 스타일을 적용할 수 있습니다. 이 방법을 통해 간단한 스타일링이나, 동적인 스타일 변경을 할 때 사용 가능 합니다.
style Prop 기본 사용법
- CSS 속성 이름은 camelCase로 작성
- 값은 문자열 또는 숫자로 작성
function App() {
return (
<div>
<button
style={{
backgroundColor: 'red', // 고정된 색상
color: 'white',
padding: '10px 20px',
border: 'none',
cursor: 'pointer'
}}
>
Click me!
</button>
</div>
);
}
export default App;
- 동적 스타일링 가능
import React, { useState } from 'react';
function App() {
// useState 훅을 사용하여 isClicked 상태를 정의합니다. 초기 값은 false입니다.
const [isClicked, setIsClicked] = useState(false);
// 버튼 클릭 시 호출되는 함수입니다. 상태를 반전시켜 isClicked 값을 변경합니다.
const handleClick = () => {
setIsClicked(prev => !prev); // 이전 상태의 반대로 값을 변경합니다.
};
// 버튼 스타일을 동적으로 생성합니다. isClicked 상태에 따라 배경색이 바뀝니다.
const buttonStyle = {
backgroundColor: isClicked ? 'green' : 'red', // 상태에 따라 배경색을 green 또는 red로 설정
color: 'white',
padding: '10px 20px',
border: 'none',
cursor: 'pointer'
};
return (
<div>
{/* label 태그는 버튼을 설명하는 텍스트를 포함합니다.
isClicked 상태에 따라 'clicked' 클래스를 동적으로 추가 */}
<label className={`label ${isClicked ? 'clicked' : ''}`}>Button</label>
{/* 버튼은 style prop을 사용하여 동적으로 스타일을 적용하고,
클릭 시 handleClick 함수가 호출되어 isClicked 상태가 변경됩니다. */}
<button style={buttonStyle} onClick={handleClick}>
{/* 버튼 텍스트는 isClicked 상태에 따라 'Clicked' 또는 'Click me!'로 변경 */}
{isClicked ? 'Clicked' : 'Click me!'}
</button>
</div>
);
}
export default App;
style Prop 사용 시 장점
- 컴포넌트 내에서 간편한 스타일링
- 동적 스타일 적용
- 외부 라이브러리 의존성 없음
style Prop 사용 시 단점
- 스타일 재사용 어려움
- 성능 이슈
- 매번 새로운 스타일 객체가 생성되어 리렌더링 성능에 영향을 미칠 수 있다.
- 복잡한 스타일링에 한계
- 스타일 객채와 jsx의 상태와 강한 의존성
2️⃣ CSS Module 사용하기
CSS Modules은 CSS 클래스 이름을 자동으로 고유하게 만들어주는 방법입니다. 이를 통해 각 컴포넌트에서 사용하는 CSS가 전역에 영향을 미치지 않게 할 수 있습니다.
- create-react-app을 사용하면, CSS Modules는 기본적으로 지원됩니다. .module.css 확장자를 사용하면 됩니다.
Button.module.css
/* Button.module.css */
.button {
background-color: green;
color: white;
padding: 10px;
}
Button.js
// Button.js
import React from 'react';
import styles from './Button.module.css';
function Button() {
return <button className={styles.button}>Click me!</button>;
}
export default Button;
위의 코드에서 Button.module.css는 CSS Module을 사용하여 자동으로 고유한 클래스 이름을 생성합니다. styles.button을 사용하여 클래스 이름을 적용하면, 해당 CSS가 다른 컴포넌트의 스타일에 영향을 미치지 않습니다.
3️⃣ Styled Components
CSS-in-JS 방식을 사용하는 라이브러리입니다.
말 그대로 CSS 코드를 자바스크립트 안에 작성할 수 있게 해줍니다. 그리고 중요한 건, 작성한 스타일이 해당 컴포넌트에만 적용된다는 점입니다.
즉, 스타일이 자동으로 스코프(scope)되어 다른 컴포넌트와 충돌하지 않도록 해줍니다.
styled-component 설치
npm install styled-components
사용 방법 예시
// Button.jsx
import styled from 'styled-components';
const StyledButton = styled.button`
background-color: #4caf50;
color: white;
padding: 10px 16px;
border: none;
border-radius: 5px;
cursor: pointer;
&:hover {
background-color: #45a049;
}
`;
function Button({ children }) {
return <StyledButton>{children}</StyledButton>;
}
export default Button;
이렇게 하면 StyledButton은 내부적으로 고유한 클래스명을 생성하고, 이 스타일은 다른 컴포넌트와 절대 충돌하지 않습니다. 마치 컴포넌트 하나하나가 스타일 영역을 가지는 것처럼 작동합니다.
props로 동적 스타일 처리하기
styled-components는 props를 받아서 CSS 값을 동적으로 지정할 수 있습니다.
const Input = styled.input`
background-color: ${({ invalid }) => $invalid ? "#fed2d2" : "#d1d5db"};
color: ${({ invalid }) => $invalid ? "#ef4444" : "#374151"};
`
<Input $invalid={emailNotValid} />
이런 방식으로 유효성 검증에 따라 스타일을 다르게 보여줄 수 있어 사용자 경험을 향상시킬 수 있습니다.
💡$ 접두사는 왜 쓰는 걸까? styled-components는 $로 시작하는 props는 자동으로 필터링해서 DOM에 전달하지 않도록 처리해줍니다. $invalid는 오직 스타일링에서만 사용되고, 실제 HTML 속성에는 포함되지 않기 때문에 불필요한 경고 없이 안전하게 스타일을 제어할 수 있습니다.
중첩 스타일, @media, hover 등의 사용법
styled-components는 일반 CSS 문법을 거의 그대로 사용할 수 있기 때문에, 다음과 같은 고급 기능들도 자연스럽게 적용할 수 있습니다.
✅ 중첩 선택자 (&)
const Header = styled.header`
padding: 2rem;
background-color: #f0f0f0;
& h1 {
font-size: 2rem;
margin-bottom: 1rem;
}
& p {
color: #555;
}
`
&는 해당 styled 컴포넌트 자신을 가리킵니다. 위 예제는 Header 안의 h1과 p에 각각 스타일을 주는 방법입니다.
✅ 미디어 쿼리 (@media)
const Header = styled.header`
margin-bottom: 2rem;
@media (min-width: 768px) {
margin-bottom: 4rem;
}
`
스크린 크기에 따라 스타일을 다르게 적용할 수 있습니다. 일반 CSS에서 하던 방식 그대로 작성하면 됩니다.
✅ Pseudo 선택자 (예: :hover, :focus)
const Button = styled.button`
background-color: #4caf50;
color: white;
&:hover {
background-color: #45a049;
}
`
hover 상태도 마찬가지로 &:hover와 같이 작성하면 됩니다. &는 항상 해당 요소 자신을 의미합니다. 빈칸 없이 이어서 써야 pseudo 선택자로 인식됩니다.
장점
- 스타일 충돌 걱정 X: 자동으로 고유 클래스 생성
- props로 동적 스타일 처리 가능
- 컴포넌트 기반의 스타일링
- 기존 CSS 문법 대부분 사용 가능
- 구조화된 스타일 관리가 쉬움
주의할 점
- 런타임에서 CSS를 처리하므로, 매우 큰 프로젝트에서는 퍼포먼스 이슈 가능성 있음
- CSS가 JS 내부에 있어 초반엔 낯설 수 있음
4️⃣ Tailwind
Tailwind CSS는 유틸리티 퍼스트(Utility-First) CSS 프레임워크입니다.
기존의 class="btn primary" 같은 추상적인 클래스명 대신, class="bg-blue-500 text-white p-4 rounded"처럼 직관적인 유틸리티 클래스들을 조합해서 스타일을 만듭니다.
설치 방법
프로젝트에 Tailwind 설치 (예: Vite 기준)
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
설정 파일 (tailwind.config.js) 예시
module.exports = {
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
theme: {
extend: {},
},
plugins: [],
}
전역 CSS 파일 설정 (index.css 등)
@tailwind base;
@tailwind components;
@tailwind utilities;
사용법
1️⃣ 기본 사용법
Tailwind는 미리 정의된 수많은 클래스들로 구성되어 있어서, 따로 .css 파일 없이도 className을 통해 바로 스타일을 만들 수 있습니다.
<button className="bg-blue-500 text-white font-bold py-2 px-4 rounded">
로그인
</button>
위 예시처럼 bg-blue-500, text-white, px-4, rounded 등은 각각의 스타일 속성 하나에 대응하는 클래스입니다.
2️⃣ 접두어로 반응형 디자인 구성
sm:, md:, lg: 같은 접두어만 붙이면 화면 크기에 따라 반응형 스타일링이 가능합니다.
<div className="text-base md:text-xl lg:text-2xl">
스크린 크기에 따라 글자 크기 변화
</div>
- 기본은 text-base
- 768px 이상(md): text-xl
- 1024px 이상(lg): text-2xl
이처럼 미디어 쿼리도 직관적인 접두어로 처리할 수 있습니다.
3️⃣ 접두어로 가상 선택자 처리
마우스를 올렸을 때, 클릭했을 때, 포커스됐을 때 등 가상 선택자도 접두어로 처리합니다.
<button className="bg-blue-500 hover:bg-blue-600 focus:ring-2 active:scale-95">
상호작용 가능한 버튼
</button>
- hover:bg-blue-600: 마우스를 올리면 배경색 변경
- focus:ring-2: 포커스 시 ring 효과
- active:scale-95: 클릭 시 약간 작아지는 애니메이션
Tailwind의 진짜 강점은 반응형 접두어 + 상태 접두어를 조합해서 사용할 수 있다는 점입니다.
<button className="bg-blue-500 hover:bg-blue-600 md:hover:bg-green-500">
반응형 hover 버튼
</button>
- 작은 화면에서는 hover:bg-blue-600
- md 이상에서는 hover:bg-green-500
이렇게 화면 크기와 상태를 동시에 고려한 스타일도 아주 간결하게 구현할 수 있습니다.
자주 쓰는 클래스 예시
목적 클래스 예시
배경색 | bg-red-500, bg-gray-100 |
글자 색 | text-white, text-gray-800 |
마진/패딩 | m-4, mt-2, p-6, px-4 |
폰트 스타일 | font-bold, text-xl, tracking-wide |
정렬 | flex, justify-between, items-center |
버튼 꾸미기 | hover:bg-blue-700, rounded, shadow |
장점 및 단점
- 스타일 충돌 걱정 없음 (클래스를 직접 조합)
- 반응형, 상태 변화도 직관적인 클래스 조합
- 따로 CSS 파일 안 만들어도 돼서 빠름
- ⚠️ 하지만 클래스가 너무 많아지면 가독성이 떨어질 수도 있음
- → clsx, classnames, 컴포넌트 분리로 해결 가능
🎯 팁: 클래스 너무 길어져 가독성이 떨어져요🥵
이럴 땐 Tailwind와 함께 clsx 또는 classnames 라이브러리를 활용하거나, 컴포넌트 단위로 분리해서 관리하는 방법도 있어요.
npm install clsx
import clsx from 'clsx';
const buttonClass = clsx(
'bg-blue-500',
'text-white',
'font-bold',
'py-2',
'px-4',
'rounded',
{ 'opacity-50': isDisabled }
);
도움이 되셨다면 ❤️ 좋아요와 댓글로 피드백 주세요!
궁금한 점이 있다면 언제든지 질문 환영입니다 😄
지금까지 읽어주셔서 감사합니다!
'Programming > React' 카테고리의 다른 글
[React] Tailwind 사용하여 스타일링 하기 (0) | 2025.04.23 |
---|---|
[React] Styled Components 사용하기 (0) | 2025.04.23 |
[React] CSS Module 사용하기 (0) | 2025.04.23 |
[React] style Prop 사용하여 Inline(인라인)으로 css 적용하기 (0) | 2025.04.23 |
[React] 커스텀 훅(Custom Hook) (0) | 2025.04.22 |