C.W.K.
Stream
Lesson 03 of 07 · published

@layer — specificity 전쟁 없는 CSS 정리

~12 min · css, layer, cascade, tailwind

Level 0React 입문자
0 XP0/54 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
Cascade 는 역사적으로 specificity 의 군비 경쟁이었어. @layer 가 명시적 cascade 순서 줘서 전쟁 끝내는 네이티브 CSS feature. Tailwind v4 가 그 위에 빌드.

@layer 가 뭐

@layer 가 cascade 안 이름 붙은 그룹 만듦. 뒤쪽 이름 레이어의 룰이 specificity 무관하게 앞쪽 이김. @layer reset, base, components, utilities; 가 명시적 순서 선언 — utilities 안의 어떤 것도 components 안의 어떤 것 이김, components selector 가 더 길어도.

Tailwind v4 가 레이어 셋 사용

@import "tailwindcss" 하면 Tailwind 가 내부적으로 레이어 셋 셋업: theme (@theme 의 CSS 변수), base (브라우저 reset, 디폴트), components (본인 컴포넌트 클래스 슬롯), utilities (bg-brand, p-4 클래스). 순서 고정; 슬롯에 추가.

레이어에 추가하는 이유

때때로 Tailwind 유틸리티만으론 부족 — CSS 여러 줄 가진 이름 붙은 컴포넌트 클래스 필요 (예: 애니메이션 keyframe, 복잡한 pseudo-element). @layer components 에 두면 Tailwind 의 예상 cascade 위치에 앉음. 그 후 JSX 에서 여전히 유틸리티로 override 가능 (`

Code

@layer components 안의 커스텀 버튼 클래스·css
@import "tailwindcss";

@theme {
  --color-brand: #FF8FBE;
}

@layer components {
  /* 재사용 가능한 버튼 클래스. Tailwind 유틸리티 여전히 override 가능. */
  .btn-primary {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 1rem;
    border-radius: 0.5rem;
    background: var(--color-brand);
    color: white;
    transition: opacity 0.15s;
  }
  .btn-primary:hover { opacity: 0.9; }

  /* JSX 에서: <button className="btn-primary">…</button>
     padding override: <button className="btn-primary px-6">…</button>
     (Tailwind 의 utilities 레이어의 px-6 가 여기 padding 이김.) */
}
@keyframes 필요한 애니메이션·css
@layer utilities {
  /* @keyframes 와 짝을 이루는 유틸리티 클래스 — 둘 다 같은 레이어. */
  .animate-pulse-brand {
    animation: pulse-brand 2s ease-in-out infinite;
  }
}

/* @keyframes 는 레이어 안에 안 살아 — 글로벌 식별자. */
@keyframes pulse-brand {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.6; }
}

External links

Exercise

@layer components 에 배경, 테두리, 패딩, 그림자 설정하는 커스텀 .card 클래스 추가. JSX 에 사용. 같은 element 에 Tailwind 유틸리티 클래스 추가해서 그 속성 하나 override (예: padding override <div className="card p-8">). 유틸리티 이기는지 확인. 그 후 .card 룰을 @layer components 밖으로 옮기고 유틸리티가 더는 안 이기는지 관찰 — 그게 unlayered 함정.
Hint
테스트 순서: layer-component 가 layer-utility 이김? NO — Tailwind 가 componentsutilities 전에 설정 → utilities 이김. 그게 디자인. Unlayered 룰은 둘 다 이김 — layer 순서 밖 cascade 끝에 앉아서.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.