Split View: 모던 CSS 완전 정복 2025: Flexbox, Grid, Container Queries, Tailwind CSS까지
모던 CSS 완전 정복 2025: Flexbox, Grid, Container Queries, Tailwind CSS까지
- 소개
- 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
Modern CSS Mastery 2025: Flexbox, Grid, Container Queries, and Tailwind CSS
- Introduction
- 1. CSS in 2025: New Features Overview
- 2. Flexbox Mastery
- 3. Grid Mastery
- 4. Flexbox vs Grid Decision Guide
- 5. Container Queries Deep Dive
- 6. Modern CSS Selectors
- 7. CSS Animations Complete Guide
- 8. Tailwind CSS v4
- 9. CSS-in-JS Comparison
- 10. Responsive Design Patterns
- 11. CSS Architecture
- 12. Interview Questions and Quiz
- References
Introduction
CSS in 2025 is more powerful than ever. Container Queries, CSS Nesting, the :has() selector, View Transitions API, Scroll-Driven Animations, and other long-awaited features are now supported across all major browsers.
The scope of what pure CSS can accomplish without JavaScript has exploded, and Tailwind CSS v4, rewritten with its Oxide engine, has improved build speeds by 10x, evolving the utility-first paradigm to its next stage.
This guide covers everything in modern CSS systematically -- from Flexbox and Grid to Container Queries, modern selectors, animations, Tailwind CSS v4, CSS-in-JS comparisons, responsive patterns, and CSS architecture.
1. CSS in 2025: New Features Overview
1.1 CSS Nesting (Native)
You can now nest selectors directly in CSS without Sass.
/* Native 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() Relational Selector
A revolutionary selector that lets you select parents based on their children.
/* Style cards differently when they contain images */
.card:has(img) {
grid-template-rows: 200px 1fr;
}
/* Disable submit when form has invalid inputs */
form:has(:invalid) .submit-btn {
opacity: 0.5;
pointer-events: none;
}
/* Style label when checkbox is checked */
input:checked + label {
color: green;
}
1.3 Container Queries Preview
While media queries are based on viewport size, Container Queries are based on parent container size.
.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)
Explicitly control cascade priority.
/* Declare layer order (later = higher priority) */
@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 Mastery
2.1 Core Concepts
Flexbox is a one-dimensional layout system based on main axis and cross axis.
.flex-container {
display: flex;
/* Direction */
flex-direction: row; /* Default: horizontal */
flex-direction: column; /* Vertical */
flex-direction: row-reverse; /* Reverse horizontal */
/* Wrapping */
flex-wrap: nowrap; /* Default: single line */
flex-wrap: wrap; /* Allow multiple lines */
/* Shorthand */
flex-flow: row wrap;
}
2.2 Complete Alignment Properties
.flex-container {
/* Main axis alignment */
justify-content: flex-start; /* Start */
justify-content: center; /* Center */
justify-content: space-between; /* Ends + equal spacing */
justify-content: space-around; /* Equal spacing (half at edges) */
justify-content: space-evenly; /* Perfectly equal spacing */
/* Cross axis alignment */
align-items: stretch; /* Default: stretch */
align-items: center; /* Center */
align-items: flex-start; /* Start */
align-items: baseline; /* Text baseline */
/* Multi-line cross axis */
align-content: center;
align-content: space-between;
/* Gaps */
gap: 1rem;
row-gap: 1rem;
column-gap: 2rem;
}
2.3 Child Element Properties
.flex-item {
/* Growth ratio (distributes remaining space) */
flex-grow: 1;
/* Shrink ratio */
flex-shrink: 0; /* Prevent shrinking */
/* Base size */
flex-basis: 200px;
/* Shorthand: grow shrink basis */
flex: 1 0 200px;
flex: 1; /* = 1 1 0% */
flex: auto; /* = 1 1 auto */
flex: none; /* = 0 0 auto */
/* Individual alignment */
align-self: center;
/* Order */
order: -1; /* Move to front */
}
2.4 Practical Flexbox Patterns
/* Pattern 1: Perfect centering */
.center-everything {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
/* Pattern 2: Sticky Footer */
.page-layout {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.page-layout main {
flex: 1;
}
/* Pattern 3: Equal-height cards */
.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;
}
/* Pattern 4: Navigation bar */
.navbar {
display: flex;
align-items: center;
gap: 1rem;
}
.navbar .logo { margin-right: auto; }
.navbar .actions { display: flex; gap: 0.5rem; }
3. Grid Mastery
3.1 Grid Fundamentals
CSS Grid is a two-dimensional layout system that controls rows and columns simultaneously.
.grid-container {
display: grid;
/* Column definitions */
grid-template-columns: 200px 1fr 200px; /* Fixed-fluid-fixed */
grid-template-columns: repeat(3, 1fr); /* 3 equal parts */
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); /* Responsive */
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); /* Responsive + stretch */
/* Row definitions */
grid-template-rows: auto 1fr auto;
/* Gaps */
gap: 1rem;
row-gap: 1rem;
column-gap: 2rem;
}
3.2 Grid Template Areas
A visually intuitive way to define layouts.
.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; }
/* Single column on mobile */
@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: Keeps empty tracks (creates empty columns at minimum size) */
.grid-fill {
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}
/* auto-fit: Collapses empty tracks (items stretch to fill space) */
.grid-fit {
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
The difference shows when items are few. auto-fill leaves empty columns, while auto-fit stretches existing items to fill available space.
3.4 Subgrid
Inherit parent Grid tracks in child elements.
.parent-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
.child-grid {
grid-column: span 3;
display: grid;
grid-template-columns: subgrid; /* Inherit parent column tracks */
gap: 1rem;
}
3.5 Responsive Grid Without Media Queries
/* Perfect responsive card grid - no media queries */
.responsive-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
gap: 1.5rem;
}
The min() function ensures no overflow when the container is narrower than 300px.
4. Flexbox vs Grid Decision Guide
4.1 Comparison Table
| Criteria | Flexbox | Grid |
|---|---|---|
| Dimensions | 1D (row or column) | 2D (rows and columns) |
| Content vs Layout | Content-first | Layout-first |
| Alignment | Main/cross axis | Independent row/column control |
| Item placement | Source-order based | Free placement |
| Best for | Navigation, card internals | Page layouts, dashboards |
| Gap support | Yes | Yes |
| Wrapping | flex-wrap | Automatic track placement |
4.2 When to Use Which
Choose Flexbox when:
- Laying out items in one direction (horizontal or vertical)
- Layout should be driven by content size
- Navigation bars, button groups, card internals
- Even spacing between items
Choose Grid when:
- You need to control both rows and columns
- Clear layout structure (header, sidebar, main)
- Overlapping items or free placement
- Dashboards, galleries, full page layouts
Use both together:
- Grid for overall page structure, Flexbox for component internals
/* Grid + Flexbox combination */
.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 Deep Dive
5.1 Basic Syntax
/* Declare container */
.widget-container {
container-type: inline-size; /* Query based on inline axis (usually width) */
container-name: widget; /* Optional name */
}
/* Container query */
@container widget (min-width: 500px) {
.widget {
flex-direction: row;
}
}
@container widget (max-width: 499px) {
.widget {
flex-direction: column;
}
}
5.2 container-type Options
/* inline-size: Query only inline axis (usually width) */
.container { container-type: inline-size; }
/* size: Query both width and height (more expensive) */
.container { container-type: size; }
/* normal: No query capability, name only (for style queries) */
.container { container-type: normal; }
5.3 @container vs @media
/* @media: Viewport-based - entire screen width */
@media (min-width: 768px) {
.card { flex-direction: row; }
}
/* @container: Parent container-based - reusable */
@container (min-width: 400px) {
.card { flex-direction: row; }
}
The key advantage of Container Queries is component reusability. The same card component automatically switches between vertical in a sidebar and horizontal in the main area.
5.4 Container Query Units
.widget {
/* cqw: 1% of container width */
font-size: clamp(0.875rem, 3cqw, 1.25rem);
/* cqh: 1% of container height */
padding: 2cqw;
/* cqi: 1% of container inline size */
/* cqb: 1% of container block size */
margin-inline: 5cqi;
}
6. Modern CSS Selectors
6.1 :has() Deep Dive
/* Change form border when text input is focused */
form:has(input[type="text"]:focus) {
border-color: blue;
}
/* Empty state handling */
.list:has(> :first-child) {
/* Applied only when list has children */
}
.list:not(:has(> *)) {
/* When list is empty */
display: grid;
place-items: center;
}
.list:not(:has(> *))::after {
content: "No items found";
}
/* Dark mode toggle with pure CSS */
html:has(#dark-mode:checked) {
color-scheme: dark;
--bg: #1a1a1a;
--text: #e0e0e0;
}
6.2 :is() and :where()
/* :is() - inherits highest specificity from arguments */
:is(h1, h2, h3, h4) {
line-height: 1.2;
margin-block: 1em 0.5em;
}
/* :where() - specificity always 0 (easily overridden) */
:where(h1, h2, h3, h4) {
line-height: 1.2;
}
/* Practical: use :where() for reset styles */
:where(ul, ol) { list-style: none; padding: 0; }
:where(a) { color: inherit; text-decoration: none; }
/* Simplify deeply nested selectors */
:is(.article, .blog-post, .docs) :is(h1, h2, h3) {
color: var(--heading-color);
}
6.3 Advanced :not()
/* Border on all items except last */
.list-item:not(:last-child) {
border-bottom: 1px solid #eee;
}
/* Combine multiple conditions */
input:not([type="submit"]):not([type="button"]) {
border: 1px solid #ccc;
padding: 0.5rem;
}
/* Exclude disabled items */
.nav-link:not(.disabled):hover {
background: #f0f0f0;
}
6.4 CSS Nesting Deep Dive
.card {
background: white;
border-radius: 8px;
/* Child selection */
& .title { font-weight: bold; }
/* Modifiers */
&.featured { border: 2px solid gold; }
&:hover { transform: translateY(-2px); }
&::before { content: ""; }
/* Nested media queries */
@media (prefers-color-scheme: dark) {
background: #2a2a2a;
color: white;
}
/* Nested container queries */
@container card (min-width: 400px) {
display: grid;
grid-template-columns: 1fr 1fr;
}
}
7. CSS Animations Complete Guide
7.1 View Transitions API
Provides smooth animations during page transitions or DOM changes.
/* Default View Transition styles */
::view-transition-old(root) {
animation: fade-out 0.3s ease-out;
}
::view-transition-new(root) {
animation: fade-in 0.3s ease-in;
}
/* Assign names to individual elements */
.hero-image {
view-transition-name: hero;
}
/* Customize transition for that element */
::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); }
}
// Trigger View Transition from JavaScript
document.startViewTransition(() => {
updateDOM(); // Perform DOM changes
});
7.2 Scroll-Driven Animations
Animations that progress based on scroll position.
/* Scroll progress indicator */
.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 when element enters viewport */
.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 vs transition
/* transition: Best for state changes (A to B) */
.button {
background: #3b82f6;
transition: background 0.3s ease, transform 0.2s ease;
}
.button:hover {
background: #2563eb;
transform: scale(1.05);
}
/* @keyframes: For complex multi-step animations */
@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 Performance Optimization Tips
/* Properties using GPU compositing: transform, opacity */
.good-animation {
/* Uses GPU composite layer - fast */
transition: transform 0.3s, opacity 0.3s;
}
.bad-animation {
/* Triggers reflow/repaint - slow */
transition: width 0.3s, height 0.3s, top 0.3s;
}
/* Hint to browser with will-change */
.will-animate {
will-change: transform;
}
/* Warning: overuse wastes memory. Use only right before animation */
8. Tailwind CSS v4
8.1 The Oxide Engine Revolution
Tailwind CSS v4 was completely rewritten with the Rust-based Oxide engine.
Key changes:
- Build speed improved by 10x or more
- CSS-first configuration (no tailwind.config.js needed)
- Native Container Queries support
- CSS variable-based theming system
- Automatic content detection (no content config needed)
8.2 CSS-first Configuration
/* app.css - Configure with CSS instead of tailwind.config.js */
@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
<!-- Declare container -->
<div class="@container">
<!-- Container size-based responsive -->
<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 Key Tailwind v4 Utilities
<!-- New gradients -->
<div class="bg-linear-to-r from-blue-500 to-purple-500">
Gradient background
</div>
<!-- 3D transforms -->
<div class="rotate-x-12 rotate-y-6 perspective-800">
3D effect
</div>
<!-- New variant combinations -->
<button class="hover:not-disabled:bg-blue-600 disabled:opacity-50">
Smart button
</button>
<!-- Improved group variants -->
<div class="group">
<p class="group-has-[img]:text-sm">
Smaller text when group has image
</p>
</div>
8.5 Migration Guide
# Auto-migrate from v3 to v4
npx @tailwindcss/upgrade
Key changes:
- Move
tailwind.config.jsto CSS@themeblock - Use
bg-blue-500/50instead ofbg-opacity-* dark:variant now uses CSSprefers-color-schemeby default- Vite plugin recommended over PostCSS plugin
9. CSS-in-JS Comparison
9.1 Major Libraries Compared
| Feature | styled-components | Emotion | Panda CSS | vanilla-extract |
|---|---|---|---|---|
| Runtime | Yes | Yes | Zero-runtime | Zero-runtime |
| Bundle size | ~12KB | ~11KB | ~0KB | ~0KB |
| SSR support | Config needed | Config needed | Native | Native |
| TypeScript | Supported | Supported | Type-safe | Type-safe |
| React 19 | Limited | Limited | Full | Full |
| Server Components | No | No | Yes | Yes |
9.2 2025 Trend: Zero-Runtime
With React Server Components and streaming SSR, runtime CSS-in-JS is declining.
// Panda CSS - Zero-runtime
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' }
})}>
Click
</button>
)
}
// vanilla-extract - Build-time 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 Selection Guide
- New project + React 19: Panda CSS or vanilla-extract
- Existing styled-components project: Consider gradual migration
- Utility-first preference: Tailwind CSS v4
- CSS Modules preference: vanilla-extract (type-safe CSS Modules)
10. Responsive Design Patterns
10.1 Fluid Typography
/* Fluid font sizes with clamp() */
h1 {
/* Min 2rem, max 4rem, fluid in between */
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);
}
/* Fluid spacing */
.section {
padding: clamp(1rem, 3vw, 3rem);
gap: clamp(0.5rem, 2vw, 2rem);
}
10.2 aspect-ratio
/* Responsive images/videos that maintain 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
Logical properties for internationalization (RTL/LTR) support.
/* Physical properties (fixed direction) */
.old-way {
margin-left: 1rem;
margin-right: 1rem;
padding-top: 2rem;
padding-bottom: 2rem;
border-left: 3px solid blue;
width: 200px;
height: 100px;
}
/* Logical properties (direction-adaptive) */
.new-way {
margin-inline: 1rem; /* Left+right (or right+left in RTL) */
padding-block: 2rem; /* Top+bottom */
border-inline-start: 3px solid blue; /* Start direction */
inline-size: 200px; /* Width */
block-size: 100px; /* Height */
}
10.4 Responsive Image Strategy
<!-- Serve optimal images with srcset and 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="Responsive image"
loading="lazy"
decoding="async"
/>
11. CSS Architecture
11.1 BEM (Block Element Modifier)
/* Block */
.card {}
/* Element (part of block) */
.card__title {}
.card__body {}
.card__footer {}
/* Modifier (variation) */
.card--featured {}
.card--compact {}
.card__title--large {}
11.2 Utility-First
<!-- Tailwind style: compose utility classes -->
<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">Username</h3>
<p class="text-sm text-gray-500">Description text</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;
}
// Automatically generates unique class names
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) Architecture
/* Layer priority: later declared = higher priority */
@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. Interview Questions and Quiz
Top 10 Interview Questions
Q1: Explain the difference between Flexbox and Grid.
Flexbox is a one-dimensional layout system (row or column), while Grid is a two-dimensional system (rows and columns simultaneously). Flexbox is content-driven, Grid is layout-driven. Typically, Grid handles overall page structure and Flexbox handles component internals.
Q2: Why are Container Queries better than Media Queries?
Media Queries respond to viewport size, while Container Queries respond to parent container size. This means components can be self-responsive regardless of where they are placed, greatly improving reusability.
Q3: Explain the :has() selector with examples.
The :has() relational selector lets you select parents based on child conditions. For example, form:has(:invalid) selects forms with invalid inputs, and .card:has(img) selects cards containing images.
Q4: How is CSS Specificity calculated?
Inline styles (1000), ID selectors (100), classes/attributes/pseudo-classes (10), elements/pseudo-elements (1). :is() inherits the highest specificity from its arguments, while :where() always has 0 specificity.
Q5: Why is zero-runtime important in CSS-in-JS?
Runtime CSS-in-JS generates styles during JavaScript execution, incurring performance costs. It does not work with React Server Components and can cause hydration mismatches during SSR. Zero-runtime generates CSS at build time, solving these issues.
Q6: What is the difference between auto-fill and auto-fit?
auto-fill keeps empty tracks, creating as many columns as possible, while auto-fit collapses empty tracks so existing items stretch to fill remaining space. The difference is visible when there are few items.
Q7: How do you optimize CSS animation performance?
Animate only transform and opacity properties -- these are handled by GPU composite layers, avoiding reflow/repaint. Use will-change to hint the browser, but avoid overuse as it wastes memory. Avoid animating width, height, top as they trigger layout recalculation.
Q8: What is the purpose of CSS Layers?
@layer allows explicit control of cascade priority. You can manage the priority of third-party CSS, resets, components, and utilities by layer order regardless of selector specificity.
Q9: What are the major changes in Tailwind CSS v4?
Rust-based Oxide engine for 10x faster builds, CSS-first configuration (no tailwind.config.js), native Container Queries support, CSS variable-based theming, and automatic content detection.
Q10: What is Subgrid and when should you use it?
Subgrid lets a child Grid inherit its parent Grid's track definitions. It is useful when you need card headers, bodies, and footers to align across different cards in a card grid.
5 Quiz Questions
Q1: What is the actual width of .item in the following code?
.container { display: flex; width: 600px; }
.item { flex: 0 1 200px; }
/* With 3 .item elements */
Answer: 200px each. Since flex-grow: 0, remaining space is not distributed, and flex-basis: 200px sets the initial size. Three items fit exactly in 600px.
Q2: What is the key difference between :is() and :where()?
Answer: Specificity. :is() inherits the highest specificity from its arguments, while :where() always has zero specificity. :where() is ideal for resets and default styles.
Q3: What property must the parent have to use Container Queries?
Answer: The parent element must declare container-type: inline-size (or size). Optionally, you can specify container-name to give it a name.
Q4: Which of the following is NOT a GPU-accelerated animation property?
a) transform: translateX(100px)
b) opacity: 0.5
c) width: 200px
d) filter: blur(5px)
Answer: c) Changing width triggers reflow. transform, opacity, and filter are handled by GPU compositing.
Q5: How has the configuration file changed in Tailwind CSS v4?
Answer: Instead of tailwind.config.js, configuration is done in @theme blocks within CSS files. Themes are defined using CSS variables, and content paths are automatically detected.
References
- 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