웹사이트를 만들 때, 디자인을 어떻게 입힐지 고민해 본 적 있나요?
HTML에 직접 색상 넣고, 크기 조절하는 건 너무 지저분하고요. 그렇다고 CSS 파일 따로 만들자니 파일도 많아지고 관리가 어렵습니다. "분명 더 좋은 방법이 있을텐데..." 하고 구글링을 시작하면, 온갖 생소한 단어들이 쏟아집니다.
결국 선택지는 크게 두 가지입니다.
하나는 JavaScript 파일 안에서 CSS를 같이 작성하는 방법(ex: styled-components, emotion)이고, 다른 하나는 미리 만들어진 디자인 조각들을 조립하는 방법(ex: Tailwind CSS)입니다.
이 글에서는 각 방법이 어떻게 다른지, 어떤 상황에 어떤 걸 쓰면 좋은지 최대한 쉽게 설명해드리겠습니다.
JavaScript 안에 CSS 쓰기: CSS-in-JS
CSS-in-JS란 무엇인가?
쉽게 말해서, CSS를 JavaScript 파일 안에 같이 쓰는 방법입니다.
보통은 이렇게 따로따로 파일을 만들죠:
- Button.js ← 버튼 기능
- Button.css ← 버튼 디자인
CSS-in-JS는 이걸 하나로 합칩니다:
- Button.js ← 버튼 기능 + 디자인 전부
const Button = styled.button`
background: blue;
color: white;
padding: 10px 20px;
`;
보시다시피 JavaScript 파일 안에 CSS 코드가 들어가 있습니다. 파일을 왔다 갔다 할 필요가 없어지는 거죠.
styled-components
CSS-in-JS 방식 중에서 가장 많이 쓰는 라이브러리입니다. 어떤 점이 좋을까요?
디자인과 기능이 한 곳에 모여있다
Button.js 파일만 열면 "이 버튼이 어떻게 생겼는지, 클릭하면 뭘 하는지" 모든 걸 볼 수 있습니다. CSS 파일과 JavaScript 파일을 왔다갔다 할 필요가 없죠.
클래스 이름 충돌 걱정도 없어진다
일반 CSS에서는 A 페이지에서 .button을 빨간색으로 만들고, B 페이지에서도 .button을 파란색으로 만들면 둘 중 하나가 덮어씌워져서 의도와 다르게 나올 수 있습니다. styled-components는 이런 문제를 아예 차단해 줍니다. 각 컴포넌트마다 .button-abc123, .button-xyz789 같은 고유한 이름을 자동으로 만들어주거든요.
실제 코드 예시:
import styled from 'styled-components';
// 디자인이 적용된 박스를 만듭니다
const Container = styled.div`
max-width: 1200px;
margin: 0 auto;
padding: 20px;
`;
// 제목을 만듭니다. large 속성에 따라 크기가 달라집니다
const Title = styled.h1`
font-size: ${props => props.large ? '48px' : '32px'};
color: #333;
font-weight: bold;
`;
function App() {
return (
<Container>
<Title large>안녕하세요</Title>
</Container>
);
}
emotion
styled-components와 거의 비슷한데, 조금 더 가볍고 빠릅니다.
가장 큰 차이점은 두 가지 방법으로 쓸 수 있다는 점입니다:
- styled-components처럼 쓰는 방법
- 태그에 바로 디자인을 붙이는 방법 (css prop이라고 부름)
코드 예시:
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react';
import styled from '@emotion/styled';
// 방법 1: styled-components처럼 쓰기
const Button = styled.button`
background: blue;
color: white;
padding: 10px 20px;
`;
// 방법 2: 태그에 바로 디자인 붙이기
function Card() {
return (
<div css={css`
background: white;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
`}>
<h2>카드 제목</h2>
</div>
);
}
CSS-in-JS의 단점
렌더링이 느려질 수 있음
브라우저가 웹페이지를 그리는 과정을 생각해 봅시다. 보통은 HTML을 읽고 -> CSS 파일을 가져와서 -> 바로 화면에 그립니다. 하지만 CSS-in-JS는 조금 다른 길을 거칩니다. HTML을 읽고 -> JavaScript를 실행하고 -> 그 안에서 "이 버튼은 파란색, 저 카드는 그림자 효과" 하며 스타일을 만들고 -> 그제서야 화면에 그립니다(렌더링).
한 단계 더 거치다 보니 첫 화면이 나타나기까지 시간이 조금 더 걸릴 수 있습니다. 물론 체감할 정도는 아니지만, 성능에 민감한 서비스라면 고려해 볼 만한 부분이죠.
브라우저 개발자 도구로 보면 클래스 이름이 알아보기 어려움
개발자 도구로 디버깅할 때도 조금 불편합니다. 보통 CSS로 만든 버튼은 F12를 눌러서 Elements 탭을 보면 `<button class="primary-button">` 이런 식으로 의미 있는 이름이 보입니다. 그런데 styled-components로 만든 버튼은 `<button class="sc-bdVaja sc-bwzfXH dQwERt">` 처럼 암호 같은 이름들이 나옵니다.
이 이름들은 styled-components가 클래스 충돌을 막으려고 자동으로 만든 건데, 개발할 때 "어? 이 스타일이 어디서 온 거지?" 하고 찾기가 어려워집니다. 물론 React DevTools 같은 도구를 쓰면 어느 컴포넌트인지 알 수 있지만, CSS에 익숙한 사람들에게는 낯설 수 있습니다.

클래스 이름만 붙이면 끝, Tailwind CSS
유틸리티 클래스란?
레고 블록처럼 작은 디자인 조각들을 조립하는 방식입니다.
기존 방식은 이렇게 했죠:
/* CSS 파일 */
.card {
background-color: white;
border-radius: 8px;
padding: 20px;
box-shadow: 그림자효과;
}
<!-- HTML 파일 -->
<div class="card">카드 내용</div>
유틸리티 클래스 방식은 이렇게 합니다:
<div class="bg-white rounded-lg p-5 shadow-md">카드 내용</div>
bg-white는 "배경은 흰색", rounded-lg는 "둥근 모서리 크게", p-5는 "안쪽 여백 5" 이런 식입니다. 하나하나가 독립적인 레고 블록인 거죠. 이걸 조합해서 원하는 디자인을 만듭니다.
Tailwind CSS
유틸리티 클래스 방식에서 가장 유명한 도구입니다. 이미 수천 개의 디자인 조각이 준비되어 있어서, 그냥 가져다 쓰기만 하면 됩니다. 어떤 점이 좋을까요?
디자인 통일감
개발자마다 제멋대로 색상을 쓰다 보면 파란색만 해도 #3B82F6, #0066CC... 이런 식으로 미묘하게 다른 파란색들이 섞여서 뒤죽박죽이 됩니다. Tailwind는 blue-500, blue-600처럼 정해진 색상만 쓸 수 있어서 자연스럽게 통일감이 생깁니다.
간단한 반응형
예전에는 CSS에서 @media 쿼리 써가면서 "640px 이하일 때는 이렇게, 768px 이상일 때는 저렇게" 복잡하게 했는데, Tailwind에서는 `text-sm md:text-lg lg:text-xl` 이렇게 한 줄이면 끝입니다. 모바일에서는 작은 글씨, 태블릿에서는 중간 글씨, PC에서는 큰 글씨로 알아서 바뀝니다.
작은 번들
번들 크기도 놀라울 정도로 작아집니다. Tailwind가 제공하는 클래스는 수만 개지만, 실제로 `bg-blue-500`이랑 `text-white`만 썼다면 최종 CSS 파일에는 딱 그것만 들어갑니다. 안 쓴 스타일은 자동으로 제거되어서 보통 10KB도 안나옵니다.
하지만 아쉬운 점도 있죠:
- HTML 코드가 길어져서 지저분함
- 클래스 이름을 외워야 함(처음엔 헷갈림)
- 상황에 따라 디자인 바꾸기가 불편함
같은 버튼, 다르게 만들어보기
백문이 불여일견. 두 가지 방식으로 똑같은 버튼을 만들어보겠습니다.
styled-components 버전
import styled from 'styled-components';
// 디자인이 적용된 버튼 컴포넌트 만들기
const StyledButton = styled.button`
padding: 12px 24px;
border-radius: 8px;
font-weight: 600;
border: none;
cursor: pointer;
/* primary가 true면 파란색, 아니면 회색 */
background: ${props => props.primary ? '#3B82F6' : '#E5E7EB'};
color: ${props => props.primary ? 'white' : '#1F2937'};
/* 마우스 올리면 색 변하고 살짝 올라옴 */
&:hover {
background: ${props => props.primary ? '#2563EB' : '#D1D5DB'};
transform: translateY(-2px);
}
/* 비활성화되면 흐려짐 */
&:disabled {
opacity: 0.5;
cursor: not-allowed;
}
`;
function Button({ primary, disabled, children }) {
return (
<StyledButton primary={primary} disabled={disabled}>
{children}
</StyledButton>
);
}
Tailwind CSS 버전
function Button({ primary, disabled, children }) {
return (
<button
disabled={disabled}
className={`
px-6 py-3 rounded-lg font-semibold
${primary
? 'bg-blue-500 text-white hover:bg-blue-600'
: 'bg-gray-200 text-gray-800 hover:bg-gray-300'
}
hover:-translate-y-0.5
disabled:opacity-50 disabled:cursor-not-allowed
`}
>
{children}
</button>
);
}
그래서 뭘 써야 하나요?
사실 정답은 없습니다(제목 어그로 지송ㅋ). 상황에 따라 다르고, 취향에 따라 다릅니다.
CSS-in-JS (styled-components/emotion)가 맞는 경우
만약 서비스에서 사용자 설정에 따라 디자인이 바뀐다면 CSS-in-JS가 적합합니다. 예를 들어, 사용자가 "빨간 테마를 좋아해요" 하면 버튼 색상이 빨강으로 바뀌고, "큰 글씨를 선호해요" 하면 텍스트 크기가 커지는 그런 서비스 말입니다. 이런 동적인 스타일링은 JavaScript 변수와 CSS가 긴밀하게 연결되어야 하기 때문입니다.
컴포넌트 라이브러리를 만드는 경우도 마찬가지입니다. "우리 팀 디자인 시스템을 npm 패키지로 만들어서 다른 팀들이 갖다 쓸 수 있게 하자" 이런 상황이면 CSS-in-JS가 상당히 편할 것입니다. Button 컴포넌트를 설치하면 디자인까지 따라오는 게 훨씬 편하니까요.
그리고 디자이너와 긴밀하게 협업하는 프로젝트라면 CSS-in-JS를 추천합니다. "이 버튼 색상을 조금만 더 진하게 해주세요" 같은 요청이 올 때마다 CSS 파일을 찾아다니는 것보다, 컴포넌트 파일에서 바로 수정하는 게 훨씬 빠릅니다.
선택 팁: 번들 크기가 신경 쓰이면 emotion, 자료와 커뮤니티가 중요하면 styled-components
Tailwind CSS가 맞는 경우
빠르게 만들어야 할 때 Tailwind만 한 게 없습니다. 스타트업이나 개인 프로젝트처럼 "일단 빨리 만들어서 사용자 반응을 보자"는 상황이라면 유틸리티 클래스가 좋을 것입니다. 프로토타입 단계에서는 디자인 완성도보다 속도가 중요한데, HTML만 건드리면서 바로바로 디자인을 바꿀 수 있습니다. "어? 이 버튼 좀 더 크게 해 볼까?" 하면 `p-2`를 `p-4`로 바꾸기만 하면 되니까요.
B2C 서비스나 랜딩 페이지처럼 로딩 속도가 비즈니스에 직접적인 영향을 미치는 경우에도 Tailwind가 좋을 것입니다. 구글에서 "페이지 로딩이 1초 늦어지면 전환율이 7% 떨어진다"라고 했는데, Tailwind 같은 유틸리티 클래스는 런타임에 스타일을 생성하는 과정이 없어서 초기 로딩이 빠릅니다.
그리고 여러 명이 함께 작업하는 프로젝트에서 디자인 일관성을 유지하고 싶다면 Tailwind가 답입니다. CSS는 자유도가 너무 높아서 개발자마다 다른 방식으로 스타일을 짤 수 있는데(디자인 토큰 잘 만들어 놓으면 되긴 합니다), Tailwind는 "우리는 이 색상들, 이 크기들만 써요"라고 선택지를 제한해 주거든요. 마치 정해진 레고 블록으로만 만들 수 있게 하는 것처럼요.
실전 조언
가장 좋은 방법은 직접 체험해 보는 것입니다. 간단한 프로젝트를 하나 정해서(예를 들어 개인 블로그나 포트폴리오 사이트) 먼저 Tailwind로 만들어보고, 그다음에 똑같은 걸 styled-components로 만들어보세요.
Tailwind로 만들 때는 "클래스 이름을 찾는 게 번거로운가? HTML이 너무 지저분해 보이는가?"를 체크해 보시고, styled-components로 만들 때는 "컴포넌트 파일 안에서 디자인까지 관리하는 게 편한가? 조건부 스타일링이 자연스러운가?"를 확인해 보세요.
무엇보다 기억할 점은, 이건 단순한 도구의 차이라는 것입니다. 사용자들은 우리가 어떤 방법으로 만들었는지 전혀 모르고, 알고 싶어 하지도 않습니다. 그저 "이 웹사이트 쓰기 편한가? 예쁜가?"만 신경 쓸 뿐입니다. 너무 완벽한 선택을 하려고 고민만 하지 마시고, 편한 걸로 시작해서 나중에 바꾸면 됩니다.
'개발 > Frontend' 카테고리의 다른 글
| 아이폰에서 크롬은 크로미움이 아니라구요? (0) | 2025.12.19 |
|---|---|
| Next.js 안 써도 괜찮아, React SEO 최적화 총정리 (10) | 2025.12.10 |
| 다크모드 어떻게 하냐구요? 디자인 토큰 쓰세요 (0) | 2025.12.06 |