icon
5장 : 스타일링과 CSS

인라인 스타일링과 CSS 클래스 사용


"스타일링과 CSS"에서는 리액트 애플리케이션의 시각적인 부분을 담당하는 스타일링 기법들을 집중적으로 다룰 차례입니다.

사용자 경험(UX)에 있어 UI의 미적 요소는 매우 중요합니다. 리액트에서 컴포넌트에 스타일을 적용하는 방법은 다양하며, 각각의 장단점이 명확합니다. 이번 장에서는 가장 기본적인 두 가지 방법인 인라인 스타일링(Inline Styling)CSS 클래스(CSS Classes) 사용법에 대해 상세히 알아보겠습니다.


리액트에서의 스타일링 개요

리액트 컴포넌트에 스타일을 적용하는 주요 방법들은 다음과 같습니다.

  1. 인라인 스타일링 (Inline Styling): JSX 요소에 직접 스타일 객체를 전달하는 방식.
  2. CSS 클래스 (CSS Classes): 일반적인 CSS 파일을 작성하고, 컴포넌트에서 className prop을 사용하여 클래스를 적용하는 방식.
  3. CSS 모듈 (CSS Modules): CSS 클래스 이름의 전역 충돌을 방지하는 모듈화된 CSS 방식.
  4. CSS-in-JS 라이브러리: JavaScript 코드 내에서 CSS를 작성하는 방식 (예: Styled Components, Emotion).

이 장에서는 첫 번째와 두 번째 방식에 대해 자세히 다룹니다.


인라인 스타일링 (Inline Styling)

인라인 스타일링은 HTML에서 <div style="color: blue;">와 같이 직접 스타일을 적용하는 것과 유사하지만, 리액트에서는 스타일 속성값을 JavaScript 객체로 전달합니다.

사용 방법

JSX 요소의 style prop에 JavaScript 객체를 할당합니다. 이 객체의 속성 이름은 카멜 케이스(camelCase) 로 작성해야 합니다.

src/components/InlineStylingExample.js
// src/components/InlineStylingExample.js
import React from 'react';

function InlineStylingExample() {
  const containerStyle = {
    backgroundColor: '#f0f0f0', // CSS의 background-color -> backgroundColor
    padding: '20px',
    borderRadius: '8px',
    boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
    textAlign: 'center',
    marginBottom: '20px'
  };

  const titleStyle = {
    color: '#333',
    fontSize: '2em',
    marginBottom: '10px'
  };

  const buttonStyle = {
    backgroundColor: '#007bff',
    color: 'white',
    padding: '10px 20px',
    border: 'none',
    borderRadius: '5px',
    cursor: 'pointer',
    fontSize: '1em'
  };

  return (
    <div style={containerStyle}> {/* 객체 변수를 직접 할당 */}
      <h2 style={titleStyle}>인라인 스타일링 예제</h2>
      <p style={{ color: '#666', fontSize: '1.2em' }}> {/* 객체 리터럴로 직접 할당 */}
        이것은 인라인 스타일이 적용된 단락입니다.
      </p>
      <button style={buttonStyle}>클릭하세요</button>
    </div>
  );
}

export default InlineStylingExample;

특징 및 장단점

장점

  • 동적인 스타일링 용이: JavaScript 변수나 props, state 값에 따라 스타일을 쉽게 변경할 수 있습니다. 조건부 렌더링처럼 조건부 스타일링에 매우 유용합니다.
    // 예시: 조건에 따라 배경색 변경
    const Button = ({ isActive }) => {
      const buttonStyle = {
        backgroundColor: isActive ? 'green' : 'gray',
        color: 'white',
        padding: '10px',
      };
      return <button style={buttonStyle}>버튼</button>;
    };
  • 컴포넌트 단위 캡슐화: 스타일이 컴포넌트 파일 내에 직접 존재하므로, 해당 컴포넌트의 모든 로직과 스타일이 한 곳에 모여 있습니다.
  • CSS 충돌 방지: 각 요소에 직접 적용되므로 클래스 이름 충돌 걱정이 없습니다.

단점

  • CSS 기능 제약
    • 가상 클래스/요소(:hover, ::before, ::after): 직접 적용할 수 없습니다. (JavaScript 이벤트 리스너를 통해 간접적으로 구현해야 함)
    • 미디어 쿼리(@media): 직접 적용할 수 없습니다. (JavaScript를 통해 뷰포트 너비를 감지하여 동적으로 변경해야 함)
    • 키프레임 애니메이션(@keyframes): 직접 적용할 수 없습니다.
  • 재사용성 부족: 동일한 스타일을 여러 요소에 적용하려면 각 요소마다 동일한 스타일 객체를 반복해서 작성하거나, 객체를 변수로 정의하여 사용해야 합니다.
  • 코드 가독성 저해: 스타일 객체가 너무 커지면 JSX 코드의 가독성을 해칠 수 있습니다.
  • 성능: 런타임에 스타일 객체를 생성하고 적용하므로, 대규모 애플리케이션에서 과도하게 사용될 경우 미세한 성능 오버헤드가 발생할 수 있습니다. (대부분의 경우 큰 문제는 아님)

결론: 인라인 스타일링은 간단한 동적 스타일링이나 컴포넌트 내부에서만 사용되는 매우 작은 단위의 스타일에 적합합니다. 하지만 복잡한 스타일이나 재사용이 필요한 경우에는 다른 방법을 고려해야 합니다.


CSS 클래스 (CSS Classes)

CSS 클래스를 사용하는 것은 웹 개발에서 가장 보편적인 스타일링 방법입니다. 리액트에서도 외부 CSS 파일을 import하고, JSX 요소에 className prop을 사용하여 CSS 클래스를 적용합니다.

사용 방법

  1. src 폴더에 .css 파일을 생성합니다. (예: src/App.css, src/styles/Button.css)
  2. CSS 파일에 클래스 선택자를 사용하여 스타일 규칙을 작성합니다.
  3. 스타일을 적용할 컴포넌트 파일에서 CSS 파일을 import 합니다.
  4. JSX 요소에 className prop을 사용하여 CSS 클래스 이름을 할당합니다. (HTML의 class 속성과 동일)
src/components/CssClassesExample.js
// src/components/CssClassesExample.js
import React from 'react';
import './CssClassesExample.css'; // (1) CSS 파일 불러오기

function CssClassesExample() {
  return (
    <div className="container"> {/* (2) className prop 사용 */}
      <h2 className="title">CSS 클래스 예제</h2>
      <p className="description">
        이것은 CSS 클래스가 적용된 단락입니다.
      </p>
      <button className="my-button">클릭하세요</button>
      <button className="my-button primary">기본 버튼</button> {/* 여러 클래스 적용 가능 */}
    </div>
  );
}

export default CssClassesExample;
src/components/CssClassesExample.css
/* src/components/CssClassesExample.css */
.container {
  background-color: #e6f7ff;
  padding: 20px;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
  text-align: center;
  margin-bottom: 20px;
}

.title {
  color: #1890ff;
  font-size: 2.2em;
  margin-bottom: 10px;
}

.description {
  color: #595959;
  font-size: 1.1em;
  line-height: 1.5;
}

.my-button {
  background-color: #f0f2f5;
  color: #333;
  padding: 10px 20px;
  border: 1px solid #d9d9d9;
  border-radius: 5px;
  cursor: pointer;
  font-size: 1em;
  margin: 0 5px;
  transition: background-color 0.2s ease;
}

.my-button:hover {
  background-color: #e6e6e6;
}

.my-button.primary { /* 여러 클래스 적용 예시 */
  background-color: #007bff;
  color: white;
  border-color: #007bff;
}

.my-button.primary:hover {
  background-color: #0056b3;
}

특징 및 장단점

장점

  • 모든 CSS 기능 사용 가능: 가상 클래스, 가상 요소, 미디어 쿼리, 키프레임 애니메이션 등 모든 표준 CSS 기능을 제약 없이 사용할 수 있습니다.
  • 클린 코드: JSX 코드에서 스타일이 분리되어 있어 컴포넌트의 구조를 파악하기 용이합니다.
  • 재사용성: 정의된 CSS 클래스를 여러 컴포넌트나 여러 요소에 쉽게 재사용할 수 있습니다.
  • 성능: 브라우저가 CSS를 효율적으로 파싱하고 적용하므로 성능상 이점이 있습니다.

단점

  • 전역 오염 및 클래스 이름 충돌: 일반 CSS 파일을 사용하면 클래스 이름이 전역적으로 유효하기 때문에, 다른 컴포넌트에서 동일한 클래스 이름을 사용하면 스타일이 덮어씌워지는 충돌(Conflict) 이 발생할 수 있습니다. 대규모 프로젝트에서는 클래스 이름 관리가 복잡해집니다.
    • 이를 해결하기 위해 BEM(Block Element Modifier)과 같은 네이밍 컨벤션을 사용하거나, 다음 장에서 다룰 CSS 모듈을 사용합니다.
  • 동적 스타일링의 복잡성: JavaScript 변수에 따른 동적 스타일링이 인라인 스타일링만큼 직관적이지 않습니다. 조건부로 클래스를 추가/제거하는 로직을 작성해야 합니다.
    // 예시: 조건부 클래스 적용
    const Button = ({ isActive }) => {
      let buttonClasses = "my-button";
      if (isActive) {
        buttonClasses += " active"; // "my-button active"
      }
      return <button className={buttonClasses}>버튼</button>;
    };
    또는 clsxclassnames와 같은 라이브러리를 사용하여 클래스를 조건부로 조합할 수 있습니다.

결론: CSS 클래스는 웹 개발의 표준적인 방식으로, 풍부한 CSS 기능을 활용하고 코드의 구조를 명확히 하는 데 좋습니다. 하지만 전역 스코프로 인한 클래스 이름 충돌 문제가 발생할 수 있어 대규모 프로젝트에서는 이를 해결하기 위한 추가적인 전략이 필요합니다.


App.js에서 예제 컴포넌트 렌더링

이제 위에서 만든 두 가지 예제 컴포넌트를 App.js에 추가하여 실제 동작을 확인해 보세요.

src/App.js
// src/App.js (수정)
import React from 'react';
import './App.css'; // 필요하다면 App.css 유지
import InlineStylingExample from './components/InlineStylingExample';
import CssClassesExample from './components/CssClassesExample';

function App() {
  return (
    <div className="App">
      <h1>리액트 스타일링 기초</h1>
      <InlineStylingExample />
      <hr /> {/* 가로선으로 구분 */}
      <CssClassesExample />
    </div>
  );
}

export default App;

App.css에 기본적인 App 클래스 스타일이 있다면 좋습니다.


"인라인 스타일링, CSS 클래스"는 여기까지입니다. 이 장에서는 리액트에서 가장 기본적으로 사용되는 두 가지 스타일링 방법인 인라인 스타일링과 CSS 클래스 사용법, 그리고 각각의 특징과 장단점을 상세하게 다루었습니다.

인라인 스타일링은 간단한 동적 스타일에, CSS 클래스는 표준적인 CSS 기능과 재사용성에 적합하지만 전역 충돌의 위험이 있다는 것을 이해하셨을 것입니다. 다음 장에서는 이 전역 충돌 문제를 해결하고 CSS를 모듈화하는 강력한 방법인 CSS 모듈에 대해 알아보겠습니다.