CSS를 작성하다 보면 SCSS, PostCSS, Tailwind CSS 같은 용어들을 자주 접하게 된다. 이들이 무엇이고 왜 사용하는지, 그리고 어떤 관계인지 정리해보자.
CSS 전처리기는 브라우저가 이해하지 못하는 확장 문법으로 CSS를 작성하고, 빌드 타임에 순수 CSS로 변환하는 도구다. 대표적으로 SCSS/Sass, Less, Stylus 등이 있다.
"전(Pre) + 처리(Process)"라는 이름처럼, CSS를 생성하기 전에 미리 처리한다는 의미다.
// 작성: SCSS (브라우저가 이해 못함)
$primary-color: #3498db;
$spacing-unit: 8px;
.button {
background: $primary-color;
padding: $spacing-unit * 2;
&:hover {
opacity: 0.8;
}
}
/* 컴파일 후: CSS (브라우저가 이해함) */
.button {
background: #3498db;
padding: 16px;
}
.button:hover {
opacity: 0.8;
}
기본 CSS 문법으로는 불편한 부분들을 더 편하게 표현할 수 있다.
1. 변수 사용
색상, 폰트 크기, 간격 등을 변수로 관리할 수 있다. 일관된 디자인 시스템을 유지하고, 한 곳에서 값을 변경하면 전체에 반영된다.
$primary-color: #3498db;
$spacing-unit: 8px;
.button {
background: $primary-color;
padding: $spacing-unit * 2;
}
.card {
border-color: $primary-color;
margin: $spacing-unit;
}
2. 중첩 (Nesting)
HTML 구조를 반영하여 스타일을 중첩해서 작성할 수 있다. 가독성이 높아지고 선택자 반복을 줄일 수 있다.
.navigation {
background: #333;
ul {
list-style: none;
li {
display: inline-block;
a {
color: white;
text-decoration: none;
&:hover {
color: #3498db;
}
}
}
}
}
3. Mixins
재사용 가능한 스타일 블록을 만들 수 있다. 함수처럼 매개변수도 받을 수 있다.
@mixin flex-center {
display: flex;
justify-content: center;
align-items: center;
}
@mixin box-shadow($color) {
box-shadow: 0 2px 4px $color;
}
.container {
@include flex-center;
@include box-shadow(rgba(0, 0, 0, 0.1));
}
4. 파일 분할과 Import
스타일을 여러 파일로 나누고 조합할 수 있다. 컴포넌트별, 기능별로 관리하기 좋다.
@import 'variables';
@import 'mixins';
@import 'components/button';
@import 'components/card';
@import 'layout/header';
5. 연산
계산식을 사용하여 동적으로 값을 생성할 수 있다.
$base-spacing: 8px;
.sidebar {
width: 100% / 3;
padding: $base-spacing * 1.5;
margin-top: $base-spacing / 2;
}
6. 함수와 제어문
조건문, 반복문 등을 사용하여 복잡한 스타일 로직을 구현할 수 있다.
@for $i from 1 through 5 {
.margin-#{$i} {
margin: #{$i}rem;
}
}
// 생성 결과
// .margin-1 { margin: 1rem; }
// .margin-2 { margin: 2rem; }
// ...
Tailwind CSS나 CSS-in-JS를 사용한다면 전처리기는 굳이 필요 없다. 전처리기의 장점(변수, 재사용, 중첩 등)을 이미 다른 방식으로 제공하기 때문이다.
Tailwind CSS 예시
// SCSS 없이 Tailwind만 사용
<button className="bg-primary px-4 py-2 hover:bg-primary-dark transition-opacity">
버튼
</button>
CSS-in-JS 예시 (styled-components)
// SCSS 없이 styled-components 사용
const Button = styled.button`
background: ${props => props.theme.colors.primary};
padding: ${props => props.theme.spacing[2]};
&:hover {
opacity: 0.8;
}
`;
PostCSS는 이미 작성된 CSS를 JavaScript 플러그인으로 변환/처리하는 도구다.
전처리기: SCSS → CSS
PostCSS: CSS → 처리된 CSS
CSS가 작성된 후(Post)에 추가 처리를 하기 때문에 "후처리기"라고 부른다.
1. Autoprefixer
브라우저 호환성을 위한 벤더 프리픽스를 자동으로 추가한다.
/* 작성 */
.box {
display: flex;
transform: scale(1.5);
user-select: none;
}
/* 처리 후 */
.box {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-transform: scale(1.5);
-ms-transform: scale(1.5);
transform: scale(1.5);
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
2. cssnano
CSS를 압축하고 최적화한다.
/* 작성 */
.box {
color: #ffffff;
margin: 10px 10px 10px 10px;
}
/* 처리 후 */
.box{color:#fff;margin:10px}
3. postcss-preset-env
미래의 CSS 문법을 현재 브라우저에서 사용 가능하게 변환한다.
/* 작성 (CSS Nesting - 미래 문법) */
.box {
& .inner {
color: red;
}
}
/* 처리 후 (현재 브라우저 지원) */
.box .inner {
color: red;
}
// postcss.config.js
module.exports = {
plugins: {
'postcss-import': {}, // CSS 파일 import 처리
'postcss-nesting': {}, // CSS 중첩 문법 지원
'tailwindcss': {}, // 유틸리티 클래스 생성
'autoprefixer': {}, // 벤더 프리픽스 추가
'cssnano': {}, // CSS 압축
}
}
Tailwind CSS는 PostCSS 플러그인으로 구현된 유틸리티 CSS 프레임워크다.
PostCSS = 플랫폼/엔진
Tailwind CSS = PostCSS 플러그인 중 하나
즉, Tailwind는 PostCSS라는 플랫폼을 이용해서 자신들의 목적에 맞는 도구를 만든 것이다.
<!-- 작성: HTML 클래스 -->
<div class="bg-blue-500 p-4 hover:bg-blue-600"></div>
/* PostCSS 입력 */
@import "tailwindcss";
/* PostCSS (Tailwind 플러그인) 처리 후 */
.bg-blue-500 {
background-color: #3b82f6;
}
.p-4 {
padding: 1rem;
}
.hover\:bg-blue-600:hover {
background-color: #2563eb;
}
Tailwind를 사용해도 복잡한 스타일이 필요할 때가 있다. 이때 SCSS 없이도 @layer 디렉티브로 해결할 수 있다.
/* global.css */
@import "tailwindcss";
@layer components {
.custom-animation {
animation: slide-in 0.3s ease-out;
}
.btn-primary {
@apply bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600;
}
}
@layer utilities {
@keyframes slide-in {
from { transform: translateX(-100%); }
to { transform: translateX(0); }
}
}
Tailwind 4에서는 테마 변수도 간편하게 정의할 수 있다:
@theme {
--color-primary: #3498db;
--color-secondary: #2ecc71;
--spacing-unit: 8px;
}
CSS가 개발 환경에서 프로덕션까지 가는 전체 과정을 단계별로 살펴보자.
작성 → 전처리기 → CSS → 후처리기 → 최종 CSS → 브라우저
1단계: 개발자가 작성
개발자는 편의를 위해 SCSS 같은 전처리기 문법으로 스타일을 작성한다.
// src/styles/main.scss
$primary: #3498db;
$spacing: 8px;
.card {
background: $primary;
padding: $spacing * 2;
.title {
font-size: 1.5rem;
&:hover {
opacity: 0.8;
}
}
}
2단계: 전처리기 컴파일
빌드 도구(Webpack, Vite 등)가 SCSS를 순수 CSS로 변환한다.
/* 중간 결과: 컴파일된 CSS */
.card {
background: #3498db;
padding: 16px;
}
.card .title {
font-size: 1.5rem;
}
.card .title:hover {
opacity: 0.8;
}
3단계: PostCSS 처리
컴파일된 CSS를 PostCSS 플러그인들이 순차적으로 처리한다.
3-1. Autoprefixer (벤더 프리픽스 추가)
.card {
background: #3498db;
padding: 16px;
}
.card .title {
font-size: 1.5rem;
}
.card .title:hover {
opacity: 0.8;
}
3-2. cssnano (압축 및 최적화)
/* 최종 결과: 압축된 CSS */
.card{background:#3498db;padding:16px}.card .title{font-size:1.5rem}.card .title:hover{opacity:.8}
4단계: 브라우저 전달
최종 생성된 CSS 파일이 HTML에 연결되어 브라우저로 전달된다.
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="/dist/main.min.css">
</head>
<body>
<div class="card">
<h2 class="title">제목</h2>
</div>
</body>
</html>
실제 프로젝트에서는 빌드 도구가 이 과정을 자동화한다.
Webpack 설정
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.scss$/,
use: [
'style-loader', // 3. CSS를 DOM에 주입
'css-loader', // 2. CSS를 JS로 변환
'postcss-loader', // 1-2. PostCSS 처리
'sass-loader', // 1-1. SCSS → CSS 컴파일
]
}
]
}
};
PostCSS 설정
// postcss.config.js
module.exports = {
plugins: [
require('autoprefixer'), // 벤더 프리픽스 추가
require('cssnano')({ // CSS 압축
preset: 'default',
}),
]
};
Vite 설정
// vite.config.js
import { defineConfig } from 'vite';
export default defineConfig({
css: {
preprocessorOptions: {
scss: {
// SCSS 옵션
}
},
postcss: {
plugins: [
require('autoprefixer'),
require('cssnano'),
]
}
}
});
# npm run build 실행 시
✓ Building CSS...
- Compiling SCSS files... (전처리기)
- Processing with PostCSS... (후처리기)
├─ autoprefixer (브라우저 호환성)
├─ cssnano (압축)
└─ purgecss (미사용 CSS 제거)
✓ Build complete!
- main.css: 245 KB → 28 KB (88% 감소)
이렇게 여러 단계를 거쳐 개발자가 작성한 스타일이 최적화되어 브라우저로 전달된다.
현대 웹 개발에서는 Tailwind나 CSS-in-JS를 사용하면 전처리기가 필요 없고, PostCSS는 대부분의 프로젝트에서 자동으로 설정되어 백그라운드에서 동작한다.