(기본기) CSS
JSP나 타임리프에서 쓰던 CSS 감각을 React와 Tailwind 환경에 연결합니다.
스타일은 잡아보셨을 겁니다
JSP나 타임리프를 써봤다면, CSS 파일을 만들어서 class를 넣어본 경험이 있을 겁니다.
<link rel="stylesheet" href="/style.css" />
<div class="container">
<h1 class="title">안녕하세요</h1>
</div>.container {
max-width: 800px;
margin: 0 auto;
}
.title {
color: #333;
font-size: 24px;
}이 감각은 React에서도 그대로 씁니다.
달라지는 건 CSS를 어디에, 어떻게 붙이느냐입니다.
React에서 CSS를 적용하는 방법
React 컴포넌트는 .tsx 파일 안에 HTML과 로직이 함께 들어갑니다.
스타일을 붙이는 방법은 크게 세 가지입니다.
1. 글로벌 CSS
가장 단순한 방식입니다.
src/index.css 같은 파일을 하나 만들고, main.tsx에서 import합니다.
// main.tsx
import './index.css';파일 안에 쓴 .container, .title 같은 클래스가 프로젝트 전체에 적용됩니다.
타임리프에서 하던 것과 거의 같은 방식입니다.
문제는 프로젝트가 커지면 클래스 이름이 겹치기 시작한다는 점입니다.
Header 컴포넌트의 .title과 Card 컴포넌트의 .title이 서로 간섭합니다.
2. CSS Modules
이 문제를 해결하기 위해 나온 방식이 CSS Modules입니다.
파일 이름을 .module.css로 지으면 클래스가 자동으로 고유한 이름으로 바뀝니다.
/* Card.module.css */
.title {
font-size: 18px;
font-weight: bold;
}import styles from './Card.module.css';
function Card() {
return <h2 className={styles.title}>카드 제목</h2>;
}빌드하면 .title이 Card_title_x7kd2 같은 형태로 변환됩니다.
이름 충돌이 사라지고, 컴포넌트마다 스타일이 격리됩니다.
이 방식이 한동안 React 프로젝트의 표준처럼 쓰였습니다.
잘 동작하지만, 컴포넌트를 만들 때마다 .tsx 파일과 .module.css 파일을 왕복해야 하는 번거로움이 있습니다.
3. Tailwind CSS
그래서 최근에는 Tailwind CSS를 많이 씁니다.
CSS 파일을 따로 만들지 않고, HTML(JSX) 안에서 클래스 이름으로 직접 스타일을 지정합니다.
function Card() {
return (
<div className="max-w-sm rounded-lg shadow-md p-6">
<h2 className="text-lg font-bold text-gray-800">카드 제목</h2>
<p className="mt-2 text-gray-600">카드 내용입니다.</p>
</div>
);
}CSS 파일이 없습니다.
max-w-sm, rounded-lg, text-lg 같은 클래스 이름이 곧 스타일입니다.
Tailwind가 왜 쓸 만할까
처음 보면 클래스 이름이 너무 길어 보입니다.
하지만 실제로 써보면 몇 가지 장점이 바로 느껴집니다.
파일을 왕복하지 않습니다.
컴포넌트 코드 안에서 레이아웃, 색상, 여백을 바로 확인하고 수정합니다.
이름을 고민하지 않습니다.
.card-wrapper, .card-inner-title 같은 클래스명을 지을 필요가 없습니다.
일관된 디자인이 자동으로 잡힙니다.
text-sm, text-lg, p-4, p-6처럼 정해진 스케일을 쓰기 때문에, 팀원마다 14px, 15px, 16px을 제각각 쓰는 일이 줄어듭니다.
Tailwind 맛보기
자주 쓰는 패턴 몇 가지를 보겠습니다.
레이아웃 — Flexbox
가로 배치가 필요하면 flex를 씁니다.
<div className="flex items-center gap-4">
<img className="w-10 h-10 rounded-full" src="/avatar.png" />
<span className="text-sm font-medium">홍길동</span>
</div>| 클래스 | CSS 속성 | 의미 |
|---|---|---|
flex | display: flex | 자식 요소를 가로 배치 |
items-center | align-items: center | 세로 중앙 정렬 |
gap-4 | gap: 1rem | 자식 간 간격 |
레이아웃 — Grid
격자 배치가 필요하면 grid를 씁니다.
<div className="grid grid-cols-3 gap-4">
<div className="bg-gray-100 p-4">1</div>
<div className="bg-gray-100 p-4">2</div>
<div className="bg-gray-100 p-4">3</div>
</div>| 클래스 | CSS 속성 | 의미 |
|---|---|---|
grid | display: grid | 격자 레이아웃 |
grid-cols-3 | grid-template-columns: repeat(3, 1fr) | 3열 |
gap-4 | gap: 1rem | 셀 간 간격 |
반응형
화면 크기에 따라 스타일을 바꿀 때는 접두사를 붙입니다.
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{/* 모바일 1열, 태블릿 2열, 데스크톱 3열 */}
</div>| 접두사 | 조건 | 대략적인 기기 |
|---|---|---|
| (없음) | 기본값 | 모바일 |
md: | 768px 이상 | 태블릿 |
lg: | 1024px 이상 | 데스크톱 |
CSS 미디어 쿼리를 직접 쓰는 대신, 클래스 접두사로 해결합니다.
상태 반응
hover, focus 같은 상태도 접두사로 처리합니다.
<button className="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded">
저장
</button>hover:bg-blue-600은 마우스를 올렸을 때 배경색이 조금 짙어진다는 뜻입니다.
별도의 :hover 선언 블록을 만들지 않아도 됩니다.
CSS를 몰라도 될까?
Tailwind의 기반은 결국 CSS입니다.
flex가 뭔지, padding과 margin이 어떻게 다른지 모르면 Tailwind 클래스를 봐도 의미를 알 수 없습니다.
하지만 너무 깊게 팔 필요는 없습니다.
Tailwind의 선언형 방식 덕분에, AI에게 "이 버튼을 오른쪽 정렬하고 둥글게 만들어줘"라고 말하면 바로 적절한 클래스를 제안받을 수 있습니다.
CSS 속성 이름을 외우는 것보다, 레이아웃이 어떤 원리로 잡히는지 감을 잡는 게 훨씬 중요합니다.
아래 개념 정도만 알고 있으면 대부분의 레이아웃을 이해할 수 있습니다.
- Flexbox: 한 방향(가로 또는 세로)으로 요소를 배치
- Grid: 행과 열로 구성된 격자 배치
- Box Model:
margin(바깥 여백),padding(안쪽 여백),border(테두리) - 반응형: 화면 크기에 따라 레이아웃을 다르게 적용
이 정도 감각이 잡혀 있으면, 나머지는 필요할 때 찾아가며 충분히 해결됩니다.
직접 해보기
- 기존 투두리스트 컴포넌트에 Tailwind 클래스를 적용해보기
flex,grid, 반응형 접두사(md:,lg:)를 한 번씩 써보기