2025. 4. 1. 00:58ㆍFrameworks/React
React 컴포넌트 스타일링 방법
React 애플리케이션에서는 다양한 방식으로 컴포넌트에 스타일을 적용할 수 있습니다. 각 방식은 고유한 장단점이 있으므로, 프로젝트의 요구사항과 팀의 선호도에 따라 적절한 방식을 선택하는 것이 중요합니다.
1. 인라인 스타일 (Inline Styling)
인라인 스타일은 JSX 요소에 직접 style 속성을 사용하여 스타일을 적용하는 방식입니다.
기본 사용법
function Button({ primary }) {
return (
<button
style={{
backgroundColor: primary ? 'blue' : 'gray',
color: 'white',
padding: '10px 15px',
borderRadius: '4px',
border: 'none',
cursor: 'pointer',
}}
>
버튼
</button>
);
}
장점
- 별도의 CSS 파일이나 설정 없이 빠르게 스타일 적용 가능
- JavaScript 변수와 조건을 직접 사용할 수 있어 동적 스타일링 용이
- 컴포넌트 스코프 내에서만 적용되므로 스타일 충돌 없음
단점
- 코드가 복잡해지고 가독성이 떨어짐
- CSS의 일부 기능(미디어 쿼리, 의사 클래스 등) 사용 불가
- 대규모 애플리케이션에서는 유지보수가 어려움
- 인라인 스타일은 브라우저 렌더링 최적화에 불리할 수 있음
동적 스타일링 예시
function Button({ primary, disabled }) {
// 스타일 객체를 변수로 정의
const buttonStyle = {
backgroundColor: primary ? 'blue' : 'gray',
color: 'white',
padding: '10px 15px',
borderRadius: '4px',
border: 'none',
cursor: disabled ? 'not-allowed' : 'pointer',
opacity: disabled ? 0.6 : 1,
};
return (
<button style={buttonStyle} disabled={disabled}>
버튼
</button>
);
}
2. CSS 파일 임포트 (Regular CSS)
가장 전통적인 방식으로, 별도의 CSS 파일을 만들고 컴포넌트에서 임포트하여 사용합니다.
기본 사용법
/* Button.css */
.button {
padding: 10px 15px;
border-radius: 4px;
border: none;
cursor: pointer;
}
.primary {
background-color: blue;
color: white;
}
.secondary {
background-color: gray;
color: white;
}
.disabled {
opacity: 0.6;
cursor: not-allowed;
}
// Button.js
import React from 'react';
import './Button.css'; // CSS 파일 임포트
function Button({ primary, disabled, children }) {
const buttonClass = `button ${primary ? 'primary' : 'secondary'} ${disabled ? 'disabled' : ''}`;
return (
<button className={buttonClass} disabled={disabled}>
{children}
</button>
);
}
export default Button;
장점
- 익숙한 CSS 문법을 그대로 사용 가능
- CSS의 모든 기능(미디어 쿼리, 애니메이션 등) 사용 가능
- 디자이너와 협업이 용이함
- 브라우저 캐싱 활용 가능
단점
- 전역 네임스페이스를 공유하므로 클래스 이름 충돌 가능성 있음
- 컴포넌트와 스타일 간의 명시적 연결이 없음
- 대규모 애플리케이션에서 네이밍 규칙 관리 필요 (BEM 등)
- 동적 스타일링에 JavaScript 로직 추가 필요
3. CSS 모듈 (CSS Modules)
CSS 모듈은 CSS 파일을 JavaScript 모듈처럼 사용하여 로컬 스코프를 갖게 하는 방식입니다. Create React App에서는 기본적으로 지원됩니다.
기본 사용법
/* Button.module.css */
.button {
padding: 10px 15px;
border-radius: 4px;
border: none;
cursor: pointer;
}
.primary {
background-color: blue;
color: white;
}
.secondary {
background-color: gray;
color: white;
}
.disabled {
opacity: 0.6;
cursor: not-allowed;
}
// Button.js
import React from 'react';
import styles from './Button.module.css'; // CSS 모듈 임포트
function Button({ primary, disabled, children }) {
const buttonClass = `${styles.button} ${primary ? styles.primary : styles.secondary} ${disabled ? styles.disabled : ''}`;
return (
<button className={buttonClass} disabled={disabled}>
{children}
</button>
);
}
export default Button;
장점
- 클래스 이름이 자동으로 고유해져 스타일 충돌 방지
- 일반 CSS의 모든 기능 사용 가능
- 컴포넌트와 스타일 간의 명시적 연결
- 기존 CSS 지식을 그대로 활용 가능
단점
- 동적 스타일링에는 여전히 추가 로직 필요
- 클래스 조합이 복잡해질 수 있음
- 전역 스타일과 혼합하여 사용할 때 주의 필요
클래스 조합 유틸리티 사용
import React from 'react';
import classNames from 'classnames/bind';
import styles from './Button.module.css';
const cx = classNames.bind(styles);
function Button({ primary, disabled, children }) {
return (
<button
className={cx('button', {
primary: primary,
secondary: !primary,
disabled: disabled
})}
disabled={disabled}
>
{children}
</button>
);
}
export default Button;
4. Styled Components
CSS-in-JS 라이브러리의 대표적인 예로, JavaScript 내에서 스타일을, 그리고 직접 스타일이 적용된 컴포넌트를 생성합니다.
설치
npm install styled-components
기본 사용법
import React from 'react';
import styled from 'styled-components';
// 스타일이 적용된 버튼 컴포넌트 생성
const StyledButton = styled.button`
padding: 10px 15px;
border-radius: 4px;
border: none;
cursor: ${props => props.disabled ? 'not-allowed' : 'pointer'};
opacity: ${props => props.disabled ? 0.6 : 1};
background-color: ${props => props.primary ? 'blue' : 'gray'};
color: white;
&:hover {
background-color: ${props => props.primary ? 'darkblue' : 'darkgray'};
}
`;
function Button({ primary, disabled, children }) {
return (
<StyledButton primary={primary} disabled={disabled}>
{children}
</StyledButton>
);
}
export default Button;
장점
- JavaScript와 CSS 로직을 함께 사용하여 강력한 동적 스타일링 가능
- 컴포넌트 단위로 스타일 캡슐화
- 실제 사용된 스타일만 DOM에 주입
- props를 통한 변수 전달이 간편함
- 의사 클래스, 미디어 쿼리 등 CSS 기능 완벽 지원
단점
- 별도의 라이브러리 설치 필요
- 런타임에 스타일 계산으로 초기 로딩 성능에 영향 가능
- CSS 문법이지만 JavaScript 문자열 내에 작성되어 IDE 지원이 제한적일 수 있음
- 기존의 스타일 시스템과 통합이 어려울 수 있음
테마 사용 예시
import React from 'react';
import styled, { ThemeProvider } from 'styled-components';
// 테마 정의
const theme = {
colors: {
primary: '#0070f3',
secondary: '#666666',
disabled: '#999999',
text: {
light: '#ffffff',
dark: '#333333'
}
},
spacing: {
small: '8px',
medium: '16px',
large: '24px'
}
};
// 테마를 사용하는 버튼 컴포넌트
const StyledButton = styled.button`
padding: ${props => props.theme.spacing.small} ${props => props.theme.spacing.medium};
border-radius: 4px;
border: none;
cursor: ${props => props.disabled ? 'not-allowed' : 'pointer'};
opacity: ${props => props.disabled ? 0.6 : 1};
background-color: ${props =>
props.disabled ? props.theme.colors.disabled :
props.primary ? props.theme.colors.primary : props.theme.colors.secondary};
color: ${props => props.theme.colors.text.light};
&:hover {
filter: brightness(90%);
}
`;
function Button({ primary, disabled, children }) {
return (
<StyledButton primary={primary} disabled={disabled}>
{children}
</StyledButton>
);
}
// 앱에 테마 적용
function App() {
return (
<ThemeProvider theme={theme}>
<div className="app">
<h1>Styled Components 테마 예제</h1>
<Button primary>기본 버튼</Button>
<Button>보조 버튼</Button>
<Button primary disabled>비활성화 버튼</Button>
</div>
</ThemeProvider>
);
}
export default App;
5. Emotion
Emotion은 Styled Components와 유사한 CSS-in-JS 라이브러리이지만, 더 가볍고 유연한 API를 제공합니다.
설치
npm install @emotion/react @emotion/styled
기본 사용법
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react';
import styled from '@emotion/styled';
// css 속성 사용
const buttonStyle = css`
padding: 10px 15px;
border-radius: 4px;
border: none;
cursor: pointer;
`;
const primaryStyle = css`
background-color: blue;
color: white;
&:hover {
background-color: darkblue;
}
`;
const secondaryStyle = css`
background-color: gray;
color: white;
&:hover {
background-color: darkgray;
}
`;
// css prop 사용
function ButtonWithCssProp({ primary, children }) {
return (
<button
css={[
buttonStyle,
primary ? primaryStyle : secondaryStyle
]}
>
{children}
</button>
);
}
// styled 사용
const StyledButton = styled.button`
padding: 10px 15px;
border-radius: 4px;
border: none;
cursor: ${props => props.disabled ? 'not-allowed' : 'pointer'};
opacity: ${props => props.disabled ? 0.6 : 1};
background-color: ${props => props.primary ? 'blue' : 'gray'};
color: white;
&:hover {
background-color: ${props => props.primary ? 'darkblue' : 'darkgray'};
}
`;
function Button({ primary, disabled, children }) {
return (
<StyledButton primary={primary} disabled={disabled}>
{children}
</StyledButton>
);
}
export { Button, ButtonWithCssProp };
장점
- Styled Components와 유사하지만 더 가볍고 빠름
- css prop을 사용한 인라인 스타일 지원
- 객체 스타일과 문자열 스타일 모두 지원
- 서버 사이드 렌더링 지원이 우수함
단점
- Styled Components와 마찬가지로 런타임 오버헤드 가능성
- 별도의 라이브러리 설치 필요
- 기존 CSS 시스템과의 통합 어려움
6. Tailwind CSS
유틸리티 우선(utility-first) 접근 방식의 CSS 프레임워크로, 사전 정의된 클래스를 조합하여 스타일을 구성합니다.
설치
npm install tailwindcss postcss autoprefixer
npx tailwindcss init -p
구성
// tailwind.config.js
module.exports = {
content: [
"./src/**/*.{js,jsx,ts,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
/* index.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
기본 사용법
function Button({ primary, disabled, children }) {
const baseClasses = "px-4 py-2 rounded focus:outline-none";
const variantClasses = primary
? "bg-blue-500 hover:bg-blue-600 text-white"
: "bg-gray-500 hover:bg-gray-600 text-white";
const stateClasses = disabled
? "opacity-50 cursor-not-allowed"
: "cursor-pointer";
return (
<button
className={`${baseClasses} ${variantClasses} ${stateClasses}`}
disabled={disabled}
>
{children}
</button>
);
}
export default Button;
장점
- 사전 정의된 클래스를 사용하여 빠른 개발 가능
- 일관된 디자인 시스템 적용 용이
- CSS 파일 크기 최적화 (사용된 스타일만 포함)
- 반응형 디자인, 다크 모드 등 쉽게 구현 가능
단점
- HTML이 클래스 이름으로 복잡해질 수 있음
- CSS 작성에 익숙한 개발자에게는 러닝 커브 존재
- 복잡한 컴포넌트의 경우 클래스 관리가 어려워질 수 있음
- 기본 설정으로는 커스터마이징에 제한이 있을 수 있음
컴포넌트 추상화 예시
// 버튼 컴포넌트 추상화
function Button({ primary, disabled, size = "md", children }) {
const baseClasses = "rounded focus:outline-none transition-colors";
// 크기별 클래스
const sizeClasses = {
sm: "px-2 py-1 text-sm",
md: "px-4 py-2",
lg: "px-6 py-3 text-lg"
};
// 타입별 클래스
const variantClasses = primary
? "bg-blue-500 hover:bg-blue-600 text-white"
: "bg-gray-500 hover:bg-gray-600 text-white";
// 상태별 클래스
const stateClasses = disabled
? "opacity-50 cursor-not-allowed"
: "cursor-pointer";
return (
<button
className={`${baseClasses} ${sizeClasses[size]} ${variantClasses} ${stateClasses}`}
disabled={disabled}
>
{children}
</button>
);
}
// 사용 예시
function App() {
return (
<div className="p-4 space-y-4">
<Button primary size="sm">작은 버튼</Button>
<Button primary>중간 버튼</Button>
<Button primary size="lg">큰 버튼</Button>
<Button disabled>비활성화 버튼</Button>
</div>
);
}
클래스 조합 도구 사용
import React from 'react';
import classNames from 'classnames';
function Button({ primary, disabled, size = "md", className, children }) {
const buttonClasses = classNames(
"rounded focus:outline-none transition-colors",
{
// 크기별 클래스
"px-2 py-1 text-sm": size === "sm",
"px-4 py-2": size === "md",
"px-6 py-3 text-lg": size === "lg",
// 타입별 클래스
"bg-blue-500 hover:bg-blue-600 text-white": primary,
"bg-gray-500 hover:bg-gray-600 text-white": !primary,
// 상태별 클래스
"opacity-50 cursor-not-allowed": disabled,
"cursor-pointer": !disabled
},
// 추가 클래스
className
);
return (
<button className={buttonClasses} disabled={disabled}>
{children}
</button>
);
}
export default Button;
7. CSS 프레임워크 & UI 라이브러리
완성된 컴포넌트와 스타일을 제공하는 라이브러리를 사용하여 개발 시간을 단축할 수 있습니다.
주요 UI 라이브러리
- Material-UI (MUI)
- Google의 Material Design 구현체
- 풍부한 컴포넌트 제공
- 커스터마이징 가능
- Ant Design
- 기업용 애플리케이션에 적합
- 완성도 높은 컴포넌트 제공
- 중국 기반의 디자인 시스템
- Chakra UI
- 접근성 중심
- 모던하고 심플한 디자인
- React의 최신 기능 활용
- Bootstrap (react-bootstrap)
- 가장 널리 알려진 CSS 프레임워크의 React 구현체
- 그리드 시스템과 기본 컴포넌트 제공
- 익숙한 디자인 시스템
Material-UI 예시
import React from 'react';
import Button from '@mui/material/Button';
import { ThemeProvider, createTheme } from '@mui/material/styles';
// 테마 커스터마이징
const theme = createTheme({
palette: {
primary: {
main: '#0070f3',
},
secondary: {
main: '#666666',
},
},
});
function App() {
return (
<ThemeProvider theme={theme}>
<div className="app">
<h1>Material-UI 예제</h1>
<Button variant="contained" color="primary">
기본 버튼
</Button>
<Button variant="outlined" color="secondary">
아웃라인 버튼
</Button>
<Button variant="contained" color="primary" disabled>
비활성화 버튼
</Button>
</div>
</ThemeProvider>
);
}
export default App;
장점
- 빠른 개발 속도
- 디자인 시스템 일관성 유지
- 접근성, 반응형 등 고려된 설계
- 테스트 완료된 안정적인 컴포넌트 사용
단점
- 번들 크기 증가 가능성
- 커스터마이징 제한 또는 복잡성
- 프로젝트의 특화된 디자인이 필요한 경우 부적합할 수 있음
8. CSS 전처리기 (Preprocessors)
Sass, Less와 같은 전처리기는 CSS를 더 효율적으로 작성할 수 있는 추가 기능을 제공합니다.
Sass (SCSS) 설치
Create React App에서 Sass를 사용하려면:
npm install sass
기본 사용법
// Button.scss
$primary-color: #0070f3;
$secondary-color: #666666;
$disabled-opacity: 0.6;
.button {
padding: 10px 15px;
border-radius: 4px;
border: none;
cursor: pointer;
// 중첩 규칙
&.primary {
background-color: $primary-color;
color: white;
&:hover {
background-color: darken($primary-color, 10%);
}
}
&.secondary {
background-color: $secondary-color;
color: white;
&:hover {
background-color: darken($secondary-color, 10%);
}
}
&.disabled {
opacity: $disabled-opacity;
cursor: not-allowed;
pointer-events: none;
}
}
// 믹스인
@mixin button-size($padding-y, $padding-x, $font-size) {
padding: $padding-y $padding-x;
font-size: $font-size;
}
.button-sm {
@include button-size(5px, 10px, 0.875rem);
}
.button-md {
@include button-size(10px, 15px, 1rem);
}
.button-lg {
@include button-size(15px, 20px, 1.25rem);
}
// Button.js
import React from 'react';
import './Button.scss';
import classNames from 'classnames';
function Button({ primary, disabled, size = "md", className, children }) {
const buttonClasses = classNames(
'button',
{
'primary': primary,
'secondary': !primary,
'disabled': disabled,
[`button-${size}`]: size
},
className
);
return (
<button className={buttonClasses} disabled={disabled}>
{children}
</button>
);
}
export default Button;
장점
- 변수, 믹스인, 함수 등으로 코드 재사용성 증가
- 중첩 규칙으로 더 명확한 구조 작성 가능
- 수학 연산, 조건문 등 프로그래밍적 기능 사용 가능
- CSS 파일 모듈화 및 관리 용이
단점
- 추가 설정 및 컴파일 단계 필요
- 과도한 중첩은 오히려 가독성을 해칠 수 있음
- 모든 브라우저 호환성을 위한 추가 설정 필요할 수 있음
스타일링 방식 선택 가이드
각 스타일링 방식은 프로젝트의 요구사항, 팀의 선호도, 개발 속도 등에 따라 선택되어야 합니다. 다음은 상황별 추천 스타일링 방식입니다:
소규모 프로젝트 또는 빠른 프로토타이핑
- CSS 파일 임포트: 간단하고 빠르게 시작 가능
- Tailwind CSS: 빠른 개발 속도와 일관된 디자인
중규모 프로젝트
- CSS 모듈: 스타일 충돌 없이 컴포넌트 단위 스타일링
- Styled Components / Emotion: 동적 스타일링이 많은 경우
- UI 라이브러리 + 커스텀 스타일: 개발 속도와 커스터마이징 균형
대규모 프로젝트
- CSS-in-JS + 테마 시스템: 일관된 디자인 시스템 적용
- Sass + CSS 모듈: 체계적인 스타일 관리
- Tailwind + 컴포넌트 추상화: 재사용 가능한 UI 시스템 구축
팀 역량에 따른 선택
- 디자이너와 협업이 많은 경우: CSS 파일 임포트, Sass, UI 라이브러리
- JavaScript 개발자 중심팀: CSS-in-JS (Styled Components, Emotion)
- 빠른 학습 곡선 필요: CSS 모듈, Tailwind CSS
실전 스타일링 팁
1. 일관된 디자인 시스템 구축
// theme.js (CSS-in-JS 사용 시)
export const theme = {
colors: {
primary: '#0070f3',
secondary: '#666666',
success: '#28a745',
danger: '#dc3545',
warning: '#ffc107',
info: '#17a2b8',
light: '#f8f9fa',
dark: '#343a40',
},
typography: {
fontFamily: '"Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
fontSize: {
small: '0.875rem',
medium: '1rem',
large: '1.25rem',
xlarge: '1.5rem',
},
fontWeight: {
light: 300,
normal: 400,
bold: 700,
},
},
spacing: {
xs: '0.25rem',
sm: '0.5rem',
md: '1rem',
lg: '1.5rem',
xl: '2rem',
},
breakpoints: {
xs: '0px',
sm: '576px',
md: '768px',
lg: '992px',
xl: '1200px',
},
shadows: {
sm: '0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24)',
md: '0 3px 6px rgba(0,0,0,0.15), 0 2px 4px rgba(0,0,0,0.12)',
lg: '0 10px 20px rgba(0,0,0,0.15), 0 3px 6px rgba(0,0,0,0.10)',
},
// ... 기타 디자인 토큰들
};
2. 반응형 디자인 구현
// styled-components 사용 시
import styled from 'styled-components';
const ResponsiveContainer = styled.div`
padding: ${({ theme }) => theme.spacing.md};
/* 미디어 쿼리 사용 */
@media (min-width: ${({ theme }) => theme.breakpoints.sm}) {
padding: ${({ theme }) => theme.spacing.lg};
}
@media (min-width: ${({ theme }) => theme.breakpoints.lg}) {
max-width: 1140px;
margin: 0 auto;
}
`;
// 함수를 사용한 미디어 쿼리 추상화
const media = {
sm: (styles) => `@media (min-width: 576px) { ${styles} }`,
md: (styles) => `@media (min-width: 768px) { ${styles} }`,
lg: (styles) => `@media (min-width: 992px) { ${styles} }`,
xl: (styles) => `@media (min-width: 1200px) { ${styles} }`
};
const Card = styled.div`
padding: 1rem;
background: white;
border-radius: 4px;
box-shadow: ${({ theme }) => theme.shadows.sm};
${media.sm(`
padding: 1.5rem;
`)}
${media.lg(`
padding: 2rem;
max-width: 800px;
margin: 0 auto;
`)}
`;
3. 다크 모드 지원
// 다크 모드 테마 구현 (styled-components)
import React, { useState, useEffect } from 'react';
import { ThemeProvider } from 'styled-components';
const lightTheme = {
body: '#FFFFFF',
text: '#333333',
background: '#F8F9FA',
primary: '#0070f3',
// ... 기타 색상
};
const darkTheme = {
body: '#121212',
text: '#E0E0E0',
background: '#1E1E1E',
primary: '#90CAF9',
// ... 기타 색상
};
function ThemeWrapper({ children }) {
const [isDarkMode, setIsDarkMode] = useState(false);
// 시스템 설정 감지
useEffect(() => {
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
setIsDarkMode(mediaQuery.matches);
const handler = (e) => setIsDarkMode(e.matches);
mediaQuery.addEventListener('change', handler);
return () => mediaQuery.removeEventListener('change', handler);
}, []);
// 테마 전환 함수
const toggleTheme = () => {
setIsDarkMode(!isDarkMode);
};
const theme = {
...(isDarkMode ? darkTheme : lightTheme),
toggleTheme,
isDark: isDarkMode,
};
return <ThemeProvider theme={theme}>{children}</ThemeProvider>;
}
// 스타일이 적용된 컴포넌트
const StyledApp = styled.div`
background-color: ${({ theme }) => theme.body};
color: ${({ theme }) => theme.text};
min-height: 100vh;
transition: all 0.3s ease;
`;
// 사용 예시
function App() {
return (
<ThemeWrapper>
<StyledApp>
<header>
<ThemeToggle />
</header>
<main>{/* 콘텐츠 */}</main>
</StyledApp>
</ThemeWrapper>
);
}
// 테마 토글 버튼
const ThemeToggle = styled.button`
background: ${({ theme }) => theme.primary};
color: white;
border: none;
border-radius: 4px;
padding: 8px 16px;
cursor: pointer;
&:before {
content: '${({ theme }) => theme.isDark ? '🌞 라이트 모드' : '🌙 다크 모드'}';
}
`;
4. CSS 변수 활용 (CSS 커스텀 프로퍼티)
/* variables.css */
:root {
/* 색상 */
--color-primary: #0070f3;
--color-secondary: #666666;
--color-text: #333333;
--color-background: #ffffff;
/* 타이포그래피 */
--font-family: 'Segoe UI', Roboto, sans-serif;
--font-size-sm: 0.875rem;
--font-size-md: 1rem;
--font-size-lg: 1.25rem;
/* 간격 */
--spacing-xs: 0.25rem;
--spacing-sm: 0.5rem;
--spacing-md: 1rem;
--spacing-lg: 1.5rem;
/* 테두리 */
--border-radius: 4px;
--border-width: 1px;
/* 그림자 */
--shadow-sm: 0 1px 3px rgba(0,0,0,0.12);
--shadow-md: 0 4px 6px rgba(0,0,0,0.1);
}
/* 다크 모드 */
@media (prefers-color-scheme: dark) {
:root {
--color-text: #e0e0e0;
--color-background: #121212;
--color-primary: #90caf9;
--shadow-sm: 0 1px 3px rgba(255,255,255,0.05);
--shadow-md: 0 4px 6px rgba(255,255,255,0.03);
}
}
/* 사용자 지정 테마 클래스 */
.theme-dark {
--color-text: #e0e0e0;
--color-background: #121212;
--color-primary: #90caf9;
}
body {
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-background);
}
// Button.js
import React from 'react';
import './Button.css';
function Button({ primary, size = 'md', children }) {
const className = `button ${primary ? 'button-primary' : 'button-secondary'} button-${size}`;
return (
<button className={className}>
{children}
</button>
);
}
// Button.css
.button {
padding: var(--spacing-sm) var(--spacing-md);
border-radius: var(--border-radius);
border: var(--border-width) solid transparent;
font-family: var(--font-family);
font-size: var(--font-size-md);
cursor: pointer;
transition: all 0.3s ease;
}
.button-primary {
background-color: var(--color-primary);
color: white;
}
.button-secondary {
background-color: var(--color-secondary);
color: white;
}
.button-sm {
padding: var(--spacing-xs) var(--spacing-sm);
font-size: var(--font-size-sm);
}
.button-lg {
padding: var(--spacing-md) var(--spacing-lg);
font-size: var(--font-size-lg);
}
5. CSS Grid와 Flexbox 활용
// Flexbox를 사용한 레이아웃 (styled-components)
import styled from 'styled-components';
const FlexContainer = styled.div`
display: flex;
flex-direction: ${props => props.direction || 'row'};
justify-content: ${props => props.justify || 'flex-start'};
align-items: ${props => props.align || 'stretch'};
flex-wrap: ${props => props.wrap || 'nowrap'};
gap: ${props => props.gap || '0'};
`;
const FlexItem = styled.div`
flex: ${props => props.flex || '0 1 auto'};
align-self: ${props => props.alignSelf || 'auto'};
`;
// CSS Grid를 사용한 레이아웃
const GridContainer = styled.div`
display: grid;
grid-template-columns: ${props => props.columns || 'repeat(12, 1fr)'};
grid-gap: ${props => props.gap || '1rem'};
@media (max-width: 768px) {
grid-template-columns: repeat(6, 1fr);
}
@media (max-width: 576px) {
grid-template-columns: 1fr;
}
`;
const GridItem = styled.div`
grid-column: ${props => props.span || 'span 12'};
@media (max-width: 768px) {
grid-column: ${props => props.tabletSpan || 'span 6'};
}
@media (max-width: 576px) {
grid-column: span 1;
}
`;
// 사용 예시
function Layout() {
return (
<div>
<h2>Flexbox 레이아웃</h2>
<FlexContainer justify="space-between" align="center" gap="1rem">
<FlexItem>항목 1</FlexItem>
<FlexItem flex="1">항목 2 (늘어남)</FlexItem>
<FlexItem>항목 3</FlexItem>
</FlexContainer>
<h2>Grid 레이아웃</h2>
<GridContainer>
<GridItem span="span 8" tabletSpan="span 4">메인 콘텐츠</GridItem>
<GridItem span="span 4" tabletSpan="span 2">사이드바</GridItem>
</GridContainer>
</div>
);
}
결론
React 애플리케이션의 스타일링에는 다양한 방법이 있으며, 각 방법은 고유한 장단점을 가지고 있습니다. 프로젝트 요구사항, 팀 역량, 유지보수 용이성 등을 고려하여 적절한 방식을 선택하는 것이 중요합니다.
현대 React 애플리케이션 개발에서는 다음과 같은 추세가 있습니다:
- 컴포넌트 기반 스타일링: CSS 모듈, CSS-in-JS 등을 사용하여 컴포넌트와 스타일을 함께 관리
- 디자인 시스템 도입: 일관된 디자인 토큰과 컴포넌트 라이브러리 구축
- 유틸리티 기반 접근: Tailwind CSS와 같은 유틸리티 중심 프레임워크의 인기 증가
- 하이브리드 접근 방식: 여러 스타일링 방식을 함께 사용 (예: CSS 모듈 + Sass, Styled Components + 글로벌 스타일)
어떤 방식을 선택하든, 코드 재사용성, 유지보수성, 성능을 균형 있게 고려하는 것이 중요합니다. 또한 팀 내에서 일관된 스타일링 가이드라인을 수립하여 코드 품질을 유지하는 것이 좋습니다.
'Frameworks > React' 카테고리의 다른 글
React 애플리케이션 성능 최적화 (0) | 2025.04.01 |
---|---|
React 폼 관리와 유효성 검사 (0) | 2025.04.01 |
에러 처리와 로딩 상태 관리 (0) | 2025.04.01 |
고급 데이터 가져오기 라이브러리 (0) | 2025.04.01 |
React 컴포넌트에서 API 연동하기 (0) | 2025.04.01 |