- Published on
모던 CSS 완전 정복 2025: Flexbox, Grid, Container Queries, Tailwind CSS까지
- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 소개
- 1. 2025년 CSS: 새로운 기능 총정리
- 2. Flexbox 마스터하기
- 3. Grid 마스터하기
- 4. Flexbox vs Grid 결정 가이드
- 5. Container Queries 심화
- 6. 모던 CSS 선택자
- 7. CSS 애니메이션 총정리
- 8. Tailwind CSS v4
- 9. CSS-in-JS 비교
- 10. 반응형 디자인 패턴
- 11. CSS 아키텍처
- 12. 면접 질문 및 퀴즈
- 참고 자료
소개
2025년 CSS는 그 어느 때보다 강력해졌습니다. Container Queries, CSS Nesting, :has() 선택자, View Transitions API, Scroll-Driven Animations 등 수년간 개발자들이 갈망하던 기능들이 모든 주요 브라우저에서 지원되고 있습니다.
JavaScript 없이 순수 CSS만으로 구현 가능한 범위가 폭발적으로 넓어졌고, Tailwind CSS v4는 Oxide 엔진으로 빌드 속도를 10배 개선하며 유틸리티 퍼스트 패러다임을 한 단계 진화시켰습니다.
이 글에서는 Flexbox부터 Grid, Container Queries, 모던 선택자, 애니메이션, Tailwind CSS v4, CSS-in-JS 비교, 반응형 패턴, CSS 아키텍처까지 모던 CSS의 모든 것을 체계적으로 다룹니다.
1. 2025년 CSS: 새로운 기능 총정리
1.1 CSS Nesting (네이티브 중첩)
Sass 없이도 CSS에서 직접 중첩이 가능해졌습니다.
/* 네이티브 CSS Nesting */
.card {
background: white;
border-radius: 8px;
& .title {
font-size: 1.5rem;
font-weight: bold;
}
& .body {
padding: 1rem;
& p {
line-height: 1.6;
}
}
&:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
@media (width >= 768px) {
display: grid;
grid-template-columns: 1fr 2fr;
}
}
1.2 :has() 관계형 선택자
부모를 자식 조건으로 선택할 수 있는 혁명적 선택자입니다.
/* 이미지를 포함한 카드만 스타일 변경 */
.card:has(img) {
grid-template-rows: 200px 1fr;
}
/* 유효하지 않은 입력이 있는 폼 */
form:has(:invalid) .submit-btn {
opacity: 0.5;
pointer-events: none;
}
/* 체크된 체크박스의 형제 요소 스타일 */
input:checked + label {
color: green;
}
1.3 Container Queries 미리보기
미디어 쿼리가 뷰포트 기준이라면, Container Queries는 부모 컨테이너 기준입니다.
.card-container {
container-type: inline-size;
container-name: card;
}
@container card (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 200px 1fr;
}
}
@container card (max-width: 399px) {
.card {
display: flex;
flex-direction: column;
}
}
1.4 CSS Layers (@layer)
캐스케이드 우선순위를 명시적으로 제어합니다.
/* 레이어 순서 선언 (나중이 우선) */
@layer reset, base, components, utilities;
@layer reset {
* { margin: 0; padding: 0; box-sizing: border-box; }
}
@layer base {
body { font-family: system-ui; line-height: 1.6; }
}
@layer components {
.btn { padding: 0.5rem 1rem; border-radius: 4px; }
}
@layer utilities {
.mt-4 { margin-top: 1rem; }
}
2. Flexbox 마스터하기
2.1 Flexbox 핵심 개념
Flexbox는 1차원 레이아웃 시스템으로, 주축(main axis)과 교차축(cross axis)을 기반으로 동작합니다.
.flex-container {
display: flex;
/* 방향 */
flex-direction: row; /* 기본값: 가로 */
flex-direction: column; /* 세로 */
flex-direction: row-reverse; /* 가로 역순 */
/* 줄바꿈 */
flex-wrap: nowrap; /* 기본값: 한 줄 */
flex-wrap: wrap; /* 여러 줄 허용 */
/* 축약형 */
flex-flow: row wrap;
}
2.2 정렬 속성 완벽 정리
.flex-container {
/* 주축 정렬 */
justify-content: flex-start; /* 시작 */
justify-content: center; /* 중앙 */
justify-content: space-between; /* 양끝 배치, 균등 간격 */
justify-content: space-around; /* 균등 간격 (양끝 절반) */
justify-content: space-evenly; /* 완전 균등 간격 */
/* 교차축 정렬 */
align-items: stretch; /* 기본값: 늘리기 */
align-items: center; /* 중앙 */
align-items: flex-start; /* 시작 */
align-items: baseline; /* 텍스트 기준선 */
/* 여러 줄 교차축 정렬 */
align-content: center;
align-content: space-between;
/* 간격 */
gap: 1rem;
row-gap: 1rem;
column-gap: 2rem;
}
2.3 자식 요소 속성
.flex-item {
/* 증가 비율 (남은 공간 분배) */
flex-grow: 1;
/* 축소 비율 */
flex-shrink: 0; /* 축소 방지 */
/* 기본 크기 */
flex-basis: 200px;
/* 축약형: grow shrink basis */
flex: 1 0 200px;
flex: 1; /* = 1 1 0% */
flex: auto; /* = 1 1 auto */
flex: none; /* = 0 0 auto */
/* 개별 정렬 */
align-self: center;
/* 순서 */
order: -1; /* 맨 앞으로 */
}
2.4 Flexbox 실전 패턴
/* 패턴 1: 완벽한 수직/수평 중앙 정렬 */
.center-everything {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
/* 패턴 2: Sticky Footer */
.page-layout {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.page-layout main {
flex: 1;
}
/* 패턴 3: 동일 높이 카드 */
.card-grid {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.card-grid .card {
flex: 1 1 300px;
display: flex;
flex-direction: column;
}
.card-grid .card .content {
flex: 1;
}
/* 패턴 4: 네비게이션 바 */
.navbar {
display: flex;
align-items: center;
gap: 1rem;
}
.navbar .logo { margin-right: auto; }
.navbar .actions { display: flex; gap: 0.5rem; }
3. Grid 마스터하기
3.1 Grid 기본 개념
CSS Grid는 2차원 레이아웃 시스템으로 행과 열을 동시에 제어합니다.
.grid-container {
display: grid;
/* 열 정의 */
grid-template-columns: 200px 1fr 200px; /* 고정-유연-고정 */
grid-template-columns: repeat(3, 1fr); /* 3등분 */
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); /* 반응형 */
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); /* 반응형 + 늘리기 */
/* 행 정의 */
grid-template-rows: auto 1fr auto;
/* 간격 */
gap: 1rem;
row-gap: 1rem;
column-gap: 2rem;
}
3.2 Grid Template Areas
시각적으로 레이아웃을 정의하는 강력한 방법입니다.
.page-layout {
display: grid;
grid-template-areas:
"header header header"
"sidebar content aside"
"footer footer footer";
grid-template-columns: 200px 1fr 200px;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: content; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }
/* 모바일에서는 단일 열 */
@media (max-width: 768px) {
.page-layout {
grid-template-areas:
"header"
"content"
"sidebar"
"aside"
"footer";
grid-template-columns: 1fr;
}
}
3.3 auto-fill vs auto-fit
/* auto-fill: 빈 트랙 유지 (최소 크기로 빈 열 생성) */
.grid-fill {
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}
/* auto-fit: 빈 트랙 축소 (아이템이 남은 공간 채움) */
.grid-fit {
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
아이템이 적을 때 차이가 드러납니다. auto-fill은 빈 열을 남기고, auto-fit은 기존 아이템이 늘어나서 공간을 채웁니다.
3.4 Subgrid
부모 Grid의 트랙을 자식에게 상속하는 기능입니다.
.parent-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
.child-grid {
grid-column: span 3;
display: grid;
grid-template-columns: subgrid; /* 부모의 열 트랙 상속 */
gap: 1rem;
}
3.5 미디어 쿼리 없는 반응형 Grid
/* 완벽한 반응형 카드 그리드 - 미디어 쿼리 없음 */
.responsive-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
gap: 1.5rem;
}
min() 함수를 사용하면 컨테이너가 300px보다 작을 때도 오버플로우 없이 작동합니다.
4. Flexbox vs Grid 결정 가이드
4.1 비교 표
| 기준 | Flexbox | Grid |
|---|---|---|
| 차원 | 1차원 (행 또는 열) | 2차원 (행과 열 동시) |
| 콘텐츠 vs 레이아웃 | 콘텐츠 우선 | 레이아웃 우선 |
| 정렬 방향 | 주축/교차축 | 행/열 독립 제어 |
| 아이템 배치 | 소스 순서 기반 | 자유로운 배치 가능 |
| 적합한 사용 | 네비게이션, 카드 내부 | 페이지 레이아웃, 대시보드 |
| 갭 지원 | gap 지원 | gap 지원 |
| 줄바꿈 제어 | flex-wrap | 자동 트랙 배치 |
4.2 언제 무엇을 사용할까
Flexbox를 선택하세요:
- 한 방향(가로 또는 세로)으로 아이템 배치
- 콘텐츠 크기에 따라 유연한 레이아웃
- 네비게이션 바, 버튼 그룹, 카드 내부 레이아웃
- 아이템 간 간격을 균등하게 배분
Grid를 선택하세요:
- 행과 열을 모두 제어해야 할 때
- 명확한 레이아웃 구조(헤더, 사이드바, 메인)
- 아이템을 겹치거나 자유롭게 배치
- 대시보드, 갤러리, 전체 페이지 레이아웃
함께 사용하세요:
- Grid로 전체 페이지 구조, Flexbox로 컴포넌트 내부 레이아웃
/* Grid + Flexbox 조합 */
.dashboard {
display: grid;
grid-template-columns: 250px 1fr;
grid-template-rows: 60px 1fr;
min-height: 100vh;
}
.dashboard .toolbar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 1rem;
}
.dashboard .sidebar-nav {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
5. Container Queries 심화
5.1 기본 문법
/* 컨테이너 선언 */
.widget-container {
container-type: inline-size; /* 인라인 축(보통 너비) 기준 */
container-name: widget; /* 선택적 이름 지정 */
}
/* 컨테이너 쿼리 */
@container widget (min-width: 500px) {
.widget {
flex-direction: row;
}
}
@container widget (max-width: 499px) {
.widget {
flex-direction: column;
}
}
5.2 container-type 종류
/* inline-size: 인라인 축(보통 너비)만 쿼리 가능 */
.container { container-type: inline-size; }
/* size: 너비와 높이 모두 쿼리 가능 (더 비쌈) */
.container { container-type: size; }
/* normal: 쿼리 불가, 이름만 사용 (스타일 쿼리용) */
.container { container-type: normal; }
5.3 @container vs @media 비교
/* @media: 뷰포트 기준 - 전체 화면 너비 */
@media (min-width: 768px) {
.card { flex-direction: row; }
}
/* @container: 부모 컨테이너 기준 - 재사용 가능 */
@container (min-width: 400px) {
.card { flex-direction: row; }
}
Container Queries의 핵심 장점은 컴포넌트 재사용성입니다. 같은 카드 컴포넌트가 사이드바에서는 세로, 메인 영역에서는 가로로 자동 전환됩니다.
5.4 컨테이너 쿼리 단위
.widget {
/* cqw: 컨테이너 너비의 1% */
font-size: clamp(0.875rem, 3cqw, 1.25rem);
/* cqh: 컨테이너 높이의 1% */
padding: 2cqw;
/* cqi: 컨테이너 인라인 사이즈의 1% */
/* cqb: 컨테이너 블록 사이즈의 1% */
margin-inline: 5cqi;
}
6. 모던 CSS 선택자
6.1 :has() 심화
/* 텍스트 입력에 포커스가 있으면 폼 테두리 변경 */
form:has(input[type="text"]:focus) {
border-color: blue;
}
/* 빈 상태 처리 */
.list:has(> :first-child) {
/* 자식이 있을 때만 적용 */
}
.list:not(:has(> *)) {
/* 자식이 없을 때 */
display: grid;
place-items: center;
}
.list:not(:has(> *))::after {
content: "항목이 없습니다";
}
/* 다크모드 토글 */
html:has(#dark-mode:checked) {
color-scheme: dark;
--bg: #1a1a1a;
--text: #e0e0e0;
}
6.2 :is()와 :where()
/* :is() - 가장 높은 명시도를 상속 */
:is(h1, h2, h3, h4) {
line-height: 1.2;
margin-block: 1em 0.5em;
}
/* :where() - 명시도 0 (쉽게 오버라이드 가능) */
:where(h1, h2, h3, h4) {
line-height: 1.2;
}
/* 실용적 예시: 리셋 스타일에 :where() 사용 */
:where(ul, ol) { list-style: none; padding: 0; }
:where(a) { color: inherit; text-decoration: none; }
/* 깊은 선택자 간소화 */
:is(.article, .blog-post, .docs) :is(h1, h2, h3) {
color: var(--heading-color);
}
6.3 :not() 고급 사용
/* 마지막 항목 제외 테두리 */
.list-item:not(:last-child) {
border-bottom: 1px solid #eee;
}
/* 여러 조건 결합 */
input:not([type="submit"]):not([type="button"]) {
border: 1px solid #ccc;
padding: 0.5rem;
}
/* 비활성 아이템 제외 */
.nav-link:not(.disabled):hover {
background: #f0f0f0;
}
6.4 CSS Nesting 심화
.card {
background: white;
border-radius: 8px;
/* 자식 선택 */
& .title { font-weight: bold; }
/* 수식어 */
&.featured { border: 2px solid gold; }
&:hover { transform: translateY(-2px); }
&::before { content: ""; }
/* 미디어 쿼리 중첩 */
@media (prefers-color-scheme: dark) {
background: #2a2a2a;
color: white;
}
/* 컨테이너 쿼리 중첩 */
@container card (min-width: 400px) {
display: grid;
grid-template-columns: 1fr 1fr;
}
}
7. CSS 애니메이션 총정리
7.1 View Transitions API
페이지 전환이나 DOM 변경 시 부드러운 애니메이션을 제공합니다.
/* 기본 View Transition 스타일 */
::view-transition-old(root) {
animation: fade-out 0.3s ease-out;
}
::view-transition-new(root) {
animation: fade-in 0.3s ease-in;
}
/* 개별 요소에 이름 부여 */
.hero-image {
view-transition-name: hero;
}
/* 해당 요소의 전환 커스터마이즈 */
::view-transition-old(hero) {
animation: scale-down 0.4s ease-out;
}
::view-transition-new(hero) {
animation: scale-up 0.4s ease-in;
}
@keyframes scale-down {
from { transform: scale(1); }
to { transform: scale(0.8); opacity: 0; }
}
@keyframes scale-up {
from { transform: scale(0.8); opacity: 0; }
to { transform: scale(1); }
}
// JavaScript에서 View Transition 트리거
document.startViewTransition(() => {
updateDOM(); // DOM 변경 수행
});
7.2 Scroll-Driven Animations
스크롤 위치에 따라 애니메이션이 진행됩니다.
/* 스크롤 진행률 표시기 */
.scroll-indicator {
position: fixed;
top: 0;
left: 0;
height: 4px;
background: linear-gradient(to right, #3b82f6, #8b5cf6);
transform-origin: left;
animation: grow-width linear;
animation-timeline: scroll();
}
@keyframes grow-width {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
/* 요소가 뷰포트에 들어올 때 페이드 인 */
.fade-in-section {
animation: fade-in linear both;
animation-timeline: view();
animation-range: entry 0% entry 100%;
}
@keyframes fade-in {
from { opacity: 0; transform: translateY(50px); }
to { opacity: 1; transform: translateY(0); }
}
7.3 @keyframes와 transition 비교
/* transition: 상태 변화에 적합 (A에서 B로) */
.button {
background: #3b82f6;
transition: background 0.3s ease, transform 0.2s ease;
}
.button:hover {
background: #2563eb;
transform: scale(1.05);
}
/* @keyframes: 복잡한 다단계 애니메이션 */
@keyframes bounce {
0%, 100% { transform: translateY(0); }
25% { transform: translateY(-20px); }
50% { transform: translateY(0); }
75% { transform: translateY(-10px); }
}
.bounce-element {
animation: bounce 1s ease-in-out infinite;
}
7.4 성능 최적화 팁
/* GPU 가속을 활용하는 속성: transform, opacity */
.good-animation {
/* GPU 합성 레이어 사용 - 빠름 */
transition: transform 0.3s, opacity 0.3s;
}
.bad-animation {
/* 리플로우/리페인트 발생 - 느림 */
transition: width 0.3s, height 0.3s, top 0.3s;
}
/* will-change로 브라우저에 힌트 */
.will-animate {
will-change: transform;
}
/* 주의: 남용하면 메모리 낭비. 실제 애니메이션 직전에만 사용 */
8. Tailwind CSS v4
8.1 Oxide 엔진의 혁신
Tailwind CSS v4는 Rust 기반 Oxide 엔진으로 완전히 재작성되었습니다.
주요 변화:
- 빌드 속도 10배 이상 향상
- CSS-first 설정 (tailwind.config.js 불필요)
- 네이티브 Container Queries 지원
- CSS 변수 기반 테마 시스템
- 자동 콘텐츠 감지 (content 설정 불필요)
8.2 CSS-first 설정
/* app.css - tailwind.config.js 대신 CSS로 설정 */
@import "tailwindcss";
@theme {
--color-primary: #3b82f6;
--color-secondary: #8b5cf6;
--font-family-display: "Inter", sans-serif;
--breakpoint-3xl: 1920px;
}
8.3 Container Queries in Tailwind v4
<!-- 컨테이너 선언 -->
<div class="@container">
<!-- 컨테이너 크기 기반 반응형 -->
<div class="flex flex-col @md:flex-row @lg:grid @lg:grid-cols-3 gap-4">
<div class="p-4">Item 1</div>
<div class="p-4">Item 2</div>
<div class="p-4">Item 3</div>
</div>
</div>
8.4 Tailwind v4 주요 유틸리티
<!-- 새로운 그라디언트 -->
<div class="bg-linear-to-r from-blue-500 to-purple-500">
그라디언트 배경
</div>
<!-- 3D 트랜스폼 -->
<div class="rotate-x-12 rotate-y-6 perspective-800">
3D 효과
</div>
<!-- 새로운 variant 조합 -->
<button class="hover:not-disabled:bg-blue-600 disabled:opacity-50">
스마트 버튼
</button>
<!-- 그룹 변형 개선 -->
<div class="group">
<p class="group-has-[img]:text-sm">
이미지가 있으면 작은 텍스트
</p>
</div>
8.5 마이그레이션 가이드
# v3에서 v4로 자동 마이그레이션
npx @tailwindcss/upgrade
주요 변경 사항:
tailwind.config.js를 CSS@theme블록으로 이전bg-opacity-*대신bg-blue-500/50형태 사용dark:변형은 CSSprefers-color-scheme기반으로 변경- PostCSS 플러그인 대신 Vite 플러그인 사용 권장
9. CSS-in-JS 비교
9.1 주요 라이브러리 비교
| 특성 | styled-components | Emotion | Panda CSS | vanilla-extract |
|---|---|---|---|---|
| 런타임 | 있음 | 있음 | 제로 런타임 | 제로 런타임 |
| 번들 크기 | ~12KB | ~11KB | ~0KB | ~0KB |
| SSR 지원 | 설정 필요 | 설정 필요 | 네이티브 | 네이티브 |
| TypeScript | 지원 | 지원 | 타입 세이프 | 타입 세이프 |
| React 19 | 제한적 | 제한적 | 완벽 | 완벽 |
| 서버 컴포넌트 | 불가 | 불가 | 가능 | 가능 |
9.2 2025년 트렌드: 제로 런타임
React Server Components와 스트리밍 SSR의 등장으로 런타임 CSS-in-JS는 쇠퇴하고 있습니다.
// Panda CSS - 제로 런타임
import { css } from '../styled-system/css'
function Button() {
return (
<button className={css({
bg: 'blue.500',
color: 'white',
padding: '8px 16px',
borderRadius: 'md',
_hover: { bg: 'blue.600' }
})}>
클릭
</button>
)
}
// vanilla-extract - 빌드 타임 CSS
// styles.css.ts
import { style } from '@vanilla-extract/css'
export const button = style({
background: 'blue',
color: 'white',
padding: '8px 16px',
borderRadius: '4px',
':hover': {
background: 'darkblue',
},
})
9.3 선택 가이드
- 신규 프로젝트 + React 19: Panda CSS 또는 vanilla-extract
- 기존 styled-components 프로젝트: 점진적 마이그레이션 고려
- 유틸리티 퍼스트 선호: Tailwind CSS v4
- CSS Modules 선호: vanilla-extract (타입 세이프 CSS Modules)
10. 반응형 디자인 패턴
10.1 Fluid Typography (유동 타이포그래피)
/* clamp()를 사용한 유동 폰트 크기 */
h1 {
/* 최소 2rem, 최대 4rem, 뷰포트에 따라 유동적 */
font-size: clamp(2rem, 5vw + 1rem, 4rem);
}
p {
font-size: clamp(1rem, 0.5vw + 0.875rem, 1.25rem);
line-height: clamp(1.5, 1.2 + 0.5vw, 1.8);
}
/* 유동 간격 */
.section {
padding: clamp(1rem, 3vw, 3rem);
gap: clamp(0.5rem, 2vw, 2rem);
}
10.2 aspect-ratio
/* 비율 유지하는 반응형 이미지/비디오 */
.video-wrapper {
aspect-ratio: 16 / 9;
width: 100%;
}
.square-avatar {
aspect-ratio: 1;
width: 100%;
border-radius: 50%;
object-fit: cover;
}
.card-image {
aspect-ratio: 4 / 3;
object-fit: cover;
}
10.3 논리적 속성 (Logical Properties)
다국어 지원(RTL/LTR)을 위한 논리적 속성입니다.
/* 물리적 속성 (방향 고정) */
.old-way {
margin-left: 1rem;
margin-right: 1rem;
padding-top: 2rem;
padding-bottom: 2rem;
border-left: 3px solid blue;
width: 200px;
height: 100px;
}
/* 논리적 속성 (방향 적응) */
.new-way {
margin-inline: 1rem; /* 좌우 (또는 RTL에서 우좌) */
padding-block: 2rem; /* 상하 */
border-inline-start: 3px solid blue; /* 시작 방향 */
inline-size: 200px; /* 너비 */
block-size: 100px; /* 높이 */
}
10.4 반응형 이미지 전략
<!-- srcset과 sizes로 최적 이미지 제공 -->
<img
srcset="image-400.webp 400w,
image-800.webp 800w,
image-1200.webp 1200w"
sizes="(max-width: 600px) 100vw,
(max-width: 1200px) 50vw,
33vw"
src="image-800.webp"
alt="반응형 이미지"
loading="lazy"
decoding="async"
/>
11. CSS 아키텍처
11.1 BEM (Block Element Modifier)
/* Block */
.card {}
/* Element (블록의 일부) */
.card__title {}
.card__body {}
.card__footer {}
/* Modifier (변형) */
.card--featured {}
.card--compact {}
.card__title--large {}
11.2 유틸리티 퍼스트
<!-- Tailwind 스타일: 유틸리티 클래스 조합 -->
<div class="flex items-center gap-4 p-4 rounded-lg bg-white shadow-md
hover:shadow-lg transition-shadow">
<img class="w-12 h-12 rounded-full object-cover" src="..." alt="..." />
<div>
<h3 class="text-lg font-semibold text-gray-900">사용자 이름</h3>
<p class="text-sm text-gray-500">설명 텍스트</p>
</div>
</div>
11.3 CSS Modules
/* Button.module.css */
.button {
padding: 0.5rem 1rem;
border-radius: 4px;
font-weight: 600;
}
.primary {
background: #3b82f6;
color: white;
}
.secondary {
background: #e5e7eb;
color: #374151;
}
// 자동으로 고유한 클래스명 생성
import styles from './Button.module.css'
function Button({ variant = 'primary', children }) {
return (
<button className={`${styles.button} ${styles[variant]}`}>
{children}
</button>
)
}
11.4 CSS Layers (@layer) 아키텍처
/* 레이어 우선순위: 나중에 선언된 것이 우선 */
@layer reset, base, tokens, components, utilities, overrides;
@layer tokens {
:root {
--color-primary: #3b82f6;
--color-surface: #ffffff;
--space-sm: 0.5rem;
--space-md: 1rem;
--radius-md: 8px;
}
}
@layer components {
.btn {
padding: var(--space-sm) var(--space-md);
border-radius: var(--radius-md);
background: var(--color-primary);
color: white;
}
}
@layer utilities {
.sr-only {
position: absolute;
width: 1px;
height: 1px;
clip: rect(0, 0, 0, 0);
overflow: hidden;
}
}
12. 면접 질문 및 퀴즈
면접 질문 10선
Q1: Flexbox와 Grid의 차이점을 설명하세요.
Flexbox는 1차원 레이아웃(행 또는 열), Grid는 2차원 레이아웃(행과 열 동시) 시스템입니다. Flexbox는 콘텐츠 크기 기반, Grid는 레이아웃 구조 기반입니다. 보통 전체 구조는 Grid, 내부 컴포넌트는 Flexbox를 사용합니다.
Q2: Container Queries가 Media Queries보다 나은 점은?
Media Queries는 뷰포트 크기를 기준으로 하지만, Container Queries는 부모 컨테이너 크기를 기준으로 합니다. 따라서 컴포넌트가 어디에 배치되든 자체적으로 반응형 동작이 가능하여 재사용성이 높아집니다.
Q3: :has() 선택자의 용도를 예시와 함께 설명하세요.
부모 요소를 자식 조건으로 선택할 수 있는 관계형 선택자입니다. 예를 들어 form:has(:invalid)는 유효하지 않은 입력이 있는 폼을 선택하고, .card:has(img)는 이미지를 포함한 카드만 선택합니다.
Q4: CSS Specificity(명시도) 계산 방법을 설명하세요.
인라인 스타일(1000), ID 선택자(100), 클래스/속성/의사클래스(10), 태그/의사요소(1) 순입니다. :is()는 인자 중 가장 높은 명시도를 상속하고, :where()는 항상 0입니다.
Q5: CSS-in-JS에서 제로 런타임이 중요한 이유는?
런타임 CSS-in-JS는 JavaScript 실행 중에 스타일을 생성하여 성능 비용이 발생합니다. React Server Components에서는 동작하지 않으며, SSR 시 하이드레이션 불일치가 발생할 수 있습니다. 제로 런타임은 빌드 시 CSS를 생성하여 이 문제를 해결합니다.
Q6: auto-fill과 auto-fit의 차이는?
auto-fill은 빈 트랙을 유지하여 가능한 많은 열을 만들고, auto-fit은 빈 트랙을 축소하여 기존 아이템이 남은 공간을 채웁니다. 아이템 수가 적을 때 차이가 드러납니다.
Q7: CSS 애니메이션 성능 최적화 방법은?
transform과 opacity 속성만 애니메이션하면 GPU 합성 레이어에서 처리되어 리플로우/리페인트를 피할 수 있습니다. will-change로 브라우저에 힌트를 주되, 남용하면 메모리 낭비입니다. width, height, top 등의 속성 변경은 레이아웃을 재계산하므로 피해야 합니다.
Q8: CSS Layers의 목적은?
@layer를 사용하면 캐스케이드 우선순위를 명시적으로 제어할 수 있습니다. 서드파티 CSS, 리셋, 컴포넌트, 유틸리티의 우선순위를 선택자 명시도와 관계없이 레이어 순서로 관리합니다.
Q9: Tailwind CSS v4의 주요 변화는?
Rust 기반 Oxide 엔진으로 10x 빠른 빌드, CSS-first 설정(tailwind.config.js 불필요), 네이티브 Container Queries 지원, CSS 변수 기반 테마, 자동 콘텐츠 감지 등입니다.
Q10: Subgrid란 무엇이며 언제 사용하나요?
Subgrid는 부모 Grid의 트랙 정의를 자식 Grid가 상속하는 기능입니다. 카드 그리드에서 각 카드의 헤더, 본문, 푸터를 서로 다른 카드와 정렬할 때 유용합니다.
퀴즈 5문제
Q1: 다음 코드에서 .item의 실제 너비는?
.container { display: flex; width: 600px; }
.item { flex: 0 1 200px; }
/* 3개의 .item이 있을 때 */
정답: 각 200px입니다. flex-grow: 0이므로 남은 공간을 분배하지 않고, flex-basis: 200px로 초기 크기를 설정합니다. 총 600px에 3개가 딱 맞습니다.
Q2: :is()와 :where()의 핵심 차이는?
정답: 명시도(Specificity)입니다. :is()는 인자 중 가장 높은 명시도를 상속하고, :where()는 항상 명시도가 0입니다. :where()는 리셋이나 기본 스타일에 적합합니다.
Q3: Container Queries를 사용하려면 부모에 어떤 속성이 필요한가?
정답: container-type: inline-size (또는 size)를 부모 요소에 선언해야 합니다. 선택적으로 container-name으로 이름을 지정할 수 있습니다.
Q4: 다음 중 GPU 가속 애니메이션이 아닌 것은?
a) transform: translateX(100px)
b) opacity: 0.5
c) width: 200px
d) filter: blur(5px)
정답: c) width 변경은 리플로우를 발생시킵니다. transform, opacity, filter는 합성(composite) 단계에서 GPU가 처리합니다.
Q5: Tailwind CSS v4에서 설정 파일은 어떻게 변경되었나?
정답: tailwind.config.js 대신 CSS 파일 내의 @theme 블록에서 설정합니다. CSS 변수 기반으로 테마를 정의하며, 콘텐츠 경로도 자동 감지됩니다.
참고 자료
- MDN - CSS Grid Layout
- MDN - Flexbox
- MDN - Container Queries
- CSS Tricks - A Complete Guide to Grid
- CSS Tricks - A Complete Guide to Flexbox
- Tailwind CSS v4 Documentation
- Chrome - View Transitions API
- Chrome - Scroll-Driven Animations
- web.dev - CSS :has()
- Panda CSS Documentation
- vanilla-extract Documentation
- web.dev - Learn CSS
- State of CSS 2024
- CSS Nesting Specification