들어가기 전
FOUC현상과 FOUT현상
FOUC(Flash Of Unstyled Content)
브라우저가 HTML 문서를 파싱하고 DOM트리를 구성하는 동안 CSS 파일이 로드되지 않았을 때 발생한다.
외부 CSS 파일이 로드되고 파싱되어 CSSOM 트리가 만들어지면 렌더 트리가 업데이트되고 스타일이 적용된 콘텐츠가 표시되는데 이 과정에서 사용자는 잠시 스타일이 적용되지 않은 콘텐츠를 보게 된다.
FOUT(Flash Of Unstyled Text)
웹 폰트를 사용하는 경우, 브라우저가 웹 폰트 파일을 다운로드하고 파싱하는데 시간이 걸릴 수 있다. 웹 폰트가 아직 로드되지 않았을 때, 브라우저는 시스템 기본 폰트를 사용하여 텍스트를 먼저 렌더링한다. 웹 폰트가 로드되면, 브라우저는 렌더 트리를 업데이트하여 웹 폰트를 적용한 텍스트를 표시하게 된다. 이 과정에서 사용자는 잠시 웹 폰트가 적용되지 않은 텍스트를 볼 수 있게 된다.
styled-component
css-in-js 방식의 스타일 기법이다. CSS-in-JS는 스타일 정의를 css나 scss 파일이 아닌 JavaScript로 작성된 컴포넌트에 바로 삽입한다.
CSS-in-JS의 장점
모듈성
- CSS의 컴포넌트화로 스타일시트의 파일을 유지보수 할 필요가 없다. CSS 모델을 문서 레벨이 아닌 컴포넌트 레벨로 추상화한다. (모듈성)
조건부 스타일링
- JavaScript와 CSS 사이의 상수와 함수를 쉽게 공유 할 수 있다. 예를 들어, React에서는 props를 활용한 조건부 스타일링이 가능하다.
dead css 최소화
- 현재 사용중인 스타일만 DOM에 포함한다. 즉 안쓰는 컴포넌트는 스타일도 번들에 들어가지 않는다.

CSS-in-JS의 단점
css의 중복
- 컴포넌트가 제대로 구조화되지 않으면 css 규칙이 불필요하게 반복될 수 있다. 불필요한 반복으로 인해 css가 평소보다 커진다. 따라서 css 규칙이 커지면 cssom 트리가 커지고 성능에 안좋은 영향을 끼친다.
ex) 특정 컴포넌트 세트에 margin 16px을 적용해야 한다면 각 컴포넌트에 추가해야 한다.
동적 스타일 생성
- prop이 변할 때마다 동적으로 생성하여 JS 코드를 동적인 스타일링이 가능하게 한다. 즉, 빌드 타임에서 모든 스타일을 생성하는 것이 아닌, 런타임을 활용한다. 스타일이 매우 복잡한 컴포넌트에서는 성능 차이가 발생할 수 있다.
emotion
전반적으로 styled component와 차이가 없다.
차이점
css props를 이용해서 복잡한 스타일링을 할 수 있고
태그의 종류를 css를 확인하지 않고 알 수 있다.
<div css={[style, themes[theme], sizes[size]]} />
const themes = {
primary: css`
color: red;
`,
secondary: css`
color: blue;
`
}
const sizes = {
small: css`
fontSize: 0.75rem;
`,
medium: css`
fontSize: 1rem;
`
}
ssr에서는 별도의 설정 없이 동작한다.
반면 styled-components 같은 경우 ServerStyleSheet을 설정 해야 한다.
추가 설정 이유
styled-components는 기본적으로 클라이언트 런타임 시점에 스타일시트를 생성하고 <style> 태그로 DOM에 주입한다.
SSR 환경(예: Next.js)에서는 기본 설정만으로는 서버에서 스타일이 포함되지 않기 때문에,
HTML은 먼저 전송되고 스타일은 클라이언트에서 JS 실행 시점에 주입된다.
따라서 짧은 순간 동안 FOUC(스타일 깜빡임)이 발생할 수 있다.
간단한 코드 비교
styled component
<body>
<button class="sc-hash123">Click me</button>
<!-- styled-components가 런타임에 만든 style 태그 -->
<style data-styled="active" data-styled-version="6.1.0">
.sc-hash123 {
background: tomato;
color: white;
padding: 8px 16px;
border-radius: 6px;
}
</style>
</body>
tailwind css
<head>
<link rel="stylesheet" href="/_next/static/css/app.css">
</head>
<body>
<button class="bg-red-500 text-white px-4 py-2 rounded-md">Click me</button>
</body>
/* app.css (빌드 시점에 이미 완성됨) */
.bg-red-500 { background-color: #ef4444; }
.text-white { color: #fff; }
.px-4 { padding-left: 1rem; padding-right: 1rem; }
.py-2 { padding-top: 0.5rem; padding-bottom: 0.5rem; }
.rounded-md { border-radius: 0.375rem; }
Tailwind css
tailwindcss는 ssr에서 가능한 이유
빌드 환경
1. CSS 소스 (globals.css 등)
2. PostCSS parser → AST 생성
3.Tailwind plugin 실행 (AST 조작)
4. autoprefixer 등 다른 plugin 처리
5. 최종 CSS 출력
개발 환경
1. next dev 실행
2. Tailwind CLI 또는 PostCSS plugin이 감시 시작 (content 배열)
3. *.tsx 등에서 새로운 className 탐지
4. 그 클래스에 해당하는 CSS만 실시간 생성
5. HMR을 통해 스타일 즉시 반영
tailwind css 장점
컨텍스트 스위칭 비용 감소
화면을 분할해서 CSS 파일과 마크업 파일을 동시에 보거나, 파일을 왔다갔다하며 시간을 썼던 경험이 있었을 것이다. Tailwind CSS는 마크업 파일에 스타일을 작성하는 방식이기 때문에, 마크업 파일 하나에만 집중해도 된다.
네이밍 고민 감소
Tailwind CSS를 사용한다면 스타일에 대한 네이밍은 고민하지 않아도 된다.
작은 번들 크기, 좋은 성능
자체적으로 프로젝트 빌드 시 실제로 HTML에 적용되는 유틸리티 클래스만 최종 CSS 파일에 남겨두는 식으로 번들 크기를 줄인다고 한다.
tailwind css 단점
너무 장황해지는 HTML/JSX
공식 문서에서도 Tailwind 방식으로 작성한 코드가 못생겼다는 것을 인정한다. 레이아웃과 스타일 코드의 관심사 분리도 이루어지지 않는다.
특히 동적 스타일링이 필요한 경우, 템플릿 리터럴 코드가 복잡해지면서 이 단점이 더 부각된다. props 형태로 상태값을 받아 간단히 스타일 분기 처리를 할 수 있었던 styled-components 등의 라이브러리와 비교되는 점이다.
고급 CSS 속성 미지원
그리고 간혹 rotateX, translateZ처럼 사용 빈도가 비교적 낮은 속성들이 필요한 경우, 대응되는 유틸리티 클래스가 없기 때문에 직접 CSS 파일을 만들어 기존 스타일링 방식 대로 작성해야 했다.
스타일 코드 중복
또한 동일한 스타일을 여러 요소에 동시에 적용해야 하는 경우(ex. <ul> 하위의 <li>)에도 고민이 됐었는데, 공식 문서에 따르면 IDE의 다중 커서 편집 기능을 이용할 것을 권장하고 있다.
postcss
PostCSS는 CSS 문자열을 Abstract Syntax Tree(AST)로 파싱하고, 이 AST를 플러그인(Tailwind CSS)에 전달하여 AST를 조작한 후, 다시 AST를 Stringifier에 전달하여 CSS 문자열로 변환하는 모듈이다.
여기서 플러그인은 PostCSS가 제공하는 도구들을 기반으로 만들어지는 것이기 때문에 PostCSS의 핵심적인 역할은 CSS를 AST로 파싱하는 Parser 로서의 역할이라고 할 수 있다.
이때 HTML/JSX를 스캔해 실제 사용된 클래스 찾는 일은 Tailwind 내부 JIT 엔진이 수행하게 된다.
참고
https://joonggon.me/posts/tailwindcss-as-plugin-for-postcss
PostCSS의 플러그인으로서 동작하는 Tailwind CSS
Next.js에서 제공하는 CLI 도구인 create-next-app을 사용하면 Next.js 애플리케이션을 개발하는데 필요한 모든 설정을 빠르게 구성할 수 있습니다. npx create-next-app@latest 명령어를 터미널에 입력하면 다음
joonggon.me
'CS' 카테고리의 다른 글
| 웹 폰트 어디까지 알고 있니? (0) | 2025.10.21 |
|---|---|
| 자바스크립트 비동기 (0) | 2025.10.10 |
| [보안] 비밀번호 평문으로 보내는 것은 상관 없을까? (3) | 2025.07.31 |
| [https] 인증서 관련 문제 - ERR_CERT_COMMON_NAME_INVALID (1) | 2025.05.08 |
| [보안] 프론트 단에서 각종 취약점 해결하기 csrf, xss (1) | 2025.04.23 |