Skip to content
Published on

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

Authors

소개

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 비교 표

기준FlexboxGrid
차원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: 변형은 CSS prefers-color-scheme 기반으로 변경
  • PostCSS 플러그인 대신 Vite 플러그인 사용 권장

9. CSS-in-JS 비교

9.1 주요 라이브러리 비교

특성styled-componentsEmotionPanda CSSvanilla-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-fillauto-fit의 차이는?

auto-fill은 빈 트랙을 유지하여 가능한 많은 열을 만들고, auto-fit은 빈 트랙을 축소하여 기존 아이템이 남은 공간을 채웁니다. 아이템 수가 적을 때 차이가 드러납니다.

Q7: CSS 애니메이션 성능 최적화 방법은?

transformopacity 속성만 애니메이션하면 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 변수 기반으로 테마를 정의하며, 콘텐츠 경로도 자동 감지됩니다.


참고 자료

  1. MDN - CSS Grid Layout
  2. MDN - Flexbox
  3. MDN - Container Queries
  4. CSS Tricks - A Complete Guide to Grid
  5. CSS Tricks - A Complete Guide to Flexbox
  6. Tailwind CSS v4 Documentation
  7. Chrome - View Transitions API
  8. Chrome - Scroll-Driven Animations
  9. web.dev - CSS :has()
  10. Panda CSS Documentation
  11. vanilla-extract Documentation
  12. web.dev - Learn CSS
  13. State of CSS 2024
  14. CSS Nesting Specification