지시문(Directives)

지시문은 Tailwind CSS 프로젝트에서 특별한 기능을 제공하는 커스텀 Tailwind 전용 @규칙(at-rules)입니다.

@tailwind

@tailwind 지시자를 사용하여 Tailwind의 base, components, utilities, 그리고 variants 스타일을 CSS에 삽입할 수 있습니다.

/**
 * 이 부분은 Tailwind의 기본 스타일과 플러그인에 의해 등록된
 * 기본 스타일을 주입합니다.
 */
@tailwind base;

/**
 * 이 부분은 Tailwind의 컴포넌트 클래스와 플러그인에 의해 등록된
 * 컴포넌트 클래스를 주입합니다.
 */
@tailwind components;

/**
 * 이 부분은 Tailwind의 유틸리티 클래스와 플러그인에 의해 등록된
 * 유틸리티 클래스를 주입합니다.
 */
@tailwind utilities;

/**
 * 이 지시자를 사용하여 Tailwind가 호버, 포커스, 반응형, 다크 모드 등
 * 각 클래스의 다양한 변형을 어디에 주입할지 제어할 수 있습니다.
 *
 * 생략하면 Tailwind는 기본적으로 이러한 클래스를 스타일시트의
 * 가장 끝에 추가합니다.
 */
@tailwind variants;

@layer

@layer 지시어를 사용하면 커스텀 스타일 세트가 속한 “버킷”을 Tailwind에 알릴 수 있습니다. 유효한 레이어는 base, components, utilities입니다.

@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
  h1 {
    @apply text-2xl;
  }
  h2 {
    @apply text-xl;
  }
}

@layer components {
  .btn-blue {
    @apply bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded;
  }
}

@layer utilities {
  .filter-none {
    filter: none;
  }
  .filter-grayscale {
    filter: grayscale(100%);
  }
}

Tailwind는 @layer 지시어 내의 CSS를 해당 @tailwind 규칙과 동일한 위치로 자동으로 이동시킵니다. 따라서 우선순위 점수 문제를 피하기 위해 CSS를 특정 순서로 작성할 필요가 없습니다.

레이어에 추가된 커스텀 CSS는 HTML에서 실제로 사용될 때만 최종 빌드에 포함됩니다. 이는 Tailwind에 기본적으로 내장된 모든 클래스와 동일한 방식입니다.

또한 @layer로 커스텀 CSS를 감싸면 hover:focus:와 같은 수정자 또는 md:lg:와 같은 반응형 수정자를 해당 규칙과 함께 사용할 수 있습니다.

@apply

@apply를 사용하면 기존의 유틸리티 클래스를 여러분의 커스텀 CSS에 인라인으로 적용할 수 있습니다.

이 기능은 커스텀 CSS를 작성해야 할 때(예: 서드파티 라이브러리의 스타일을 재정의해야 하는 경우) 유용합니다. 특히, 여러분이 익숙한 문법을 사용하면서도 디자인 토큰을 활용하고 싶을 때 적합합니다.

.select2-dropdown {
  @apply rounded-b-lg shadow-md;
}
.select2-search {
  @apply border border-gray-300 rounded;
}
.select2-results__group {
  @apply text-lg font-bold text-gray-900;
}

@apply로 인라인된 규칙은 기본적으로 !important제거됩니다. 이는 우선순위 점수 문제를 방지하기 위함입니다:

/* 입력 */
.foo {
  color: blue !important;
}

.bar {
  @apply foo;
}

/* 출력 */
.foo {
  color: blue !important;
}

.bar {
  color: blue;
}

만약 기존 클래스를 @apply로 적용하면서 !important를 유지하고 싶다면, 선언 끝에 !important를 추가하면 됩니다:

/* 입력 */
.btn {
  @apply font-bold py-2 px-4 rounded !important;
}

/* 출력 */
.btn {
  font-weight: 700 !important;
  padding-top: .5rem !important;
  padding-bottom: .5rem !important;
  padding-right: 1rem !important;
  padding-left: 1rem !important;
  border-radius: .25rem !important;
}

Sass/SCSS를 사용 중이라면, 이 기능을 사용하기 위해 Sass의 보간 기능을 활용해야 합니다:

.btn {
  @apply font-bold py-2 px-4 rounded #{!important};
}

컴포넌트별 CSS에서 @apply 사용하기

Vue나 Svelte 같은 컴포넌트 프레임워크는 각 컴포넌트 파일 내에 <style> 블록을 추가하여 컴포넌트별 스타일을 정의할 수 있도록 지원합니다.

하지만 전역 CSS에서 정의한 커스텀 클래스를 컴포넌트의 <style> 블록에서 @apply로 사용하려고 하면, 해당 클래스가 존재하지 않는다는 오류가 발생합니다:

main.css
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer components {
  .card {
    background-color: theme(colors.white);
    border-radius: theme(borderRadius.lg);
    padding: theme(spacing.6);
    box-shadow: theme(boxShadow.xl);
  }
}
Card.svelte
<div>
  <slot></slot>
</div>

<style>
  div {
    /* 이 파일과 main.css는 별도로 처리되기 때문에 작동하지 않음 */
    @apply card;
  }
</style>

이 문제는 Vue나 Svelte 같은 프레임워크가 내부적으로 모든 <style> 블록을 독립적으로 처리하고, 각각에 대해 PostCSS 플러그인 체인을 별도로 실행하기 때문입니다.

즉, 10개의 컴포넌트가 각각 <style> 블록을 가지고 있다면, Tailwind는 10번 별도로 실행되며, 각 실행은 다른 실행에 대해 전혀 알지 못합니다. 따라서 Card.svelte에서 @apply card를 시도하면, Svelte가 Card.sveltemain.css를 서로 완전히 독립적으로 처리했기 때문에 Tailwind는 card 클래스가 존재하는지 알 수 없어 실패하게 됩니다.

이 문제를 해결하려면 컴포넌트에서 @apply로 사용할 커스텀 스타일을 플러그인 시스템을 통해 정의해야 합니다:

tailwind.config.js
const plugin = require('tailwindcss/plugin')

module.exports = {
  // ...
  plugins: [
    plugin(function ({ addComponents, theme }) {
      addComponents({
        '.card': {
          backgroundColor: theme('colors.white'),
          borderRadius: theme('borderRadius.lg'),
          padding: theme('spacing.6'),
          boxShadow: theme('boxShadow.xl'),
        }
      })
    })
  ]
}

이렇게 하면 이 설정 파일을 사용하는 모든 파일이 해당 스타일에 접근할 수 있습니다.

하지만 가장 좋은 해결책은 이런 이상한 방법을 사용하지 않는 것입니다. Tailwind의 유틸리티 클래스를 마크업에서 직접 사용하는 것이 의도된 방식이며, @apply 기능을 이런 식으로 남용하지 않으면 더 나은 개발 경험을 얻을 수 있습니다.

@config

@config 지시어를 사용하면 Tailwind가 해당 CSS 파일을 컴파일할 때 사용할 설정 파일을 지정할 수 있습니다. 이는 서로 다른 CSS 진입점에 대해 서로 다른 설정 파일을 사용해야 하는 프로젝트에 유용합니다.

@config "./tailwind.site.config.js";

@tailwind base;
@tailwind components;
@tailwind utilities;

@config 지시어에 제공하는 경로는 해당 CSS 파일을 기준으로 상대적이며, PostCSS 설정이나 Tailwind CLI에 정의된 경로보다 우선 적용됩니다.

postcss-import를 사용하는 경우, @import 문은 @config보다 앞에 와야 합니다. postcss-import는 CSS 사양을 엄격히 따르기 때문에 @import 문이 파일 내 다른 규칙보다 먼저 나와야 합니다.

@import 문 앞에 @config를 두지 마세요

admin.css
@config "./tailwind.admin.config.js";

@import "tailwindcss/base";
@import "./custom-base.css";
@import "tailwindcss/components";
@import "./custom-components.css";
@import "tailwindcss/utilities";

@import 문을 @config 지시어보다 앞에 두세요

admin.css
@import "tailwindcss/base";
@import "./custom-base.css";
@import "tailwindcss/components";
@import "./custom-components.css";
@import "tailwindcss/utilities";

@config "./tailwind.admin.config.js";

함수

Tailwind는 CSS에서 Tailwind 특정 값을 사용할 수 있도록 몇 가지 커스텀 함수를 제공합니다. 이 함수들은 빌드 시점에 평가되며, 최종 CSS에서는 정적 값으로 대체됩니다.

theme()

theme() 함수를 사용하면 점 표기법으로 Tailwind 설정 값을 접근할 수 있습니다.

.content-area {
  height: calc(100vh - theme(spacing.12));
}

점이 포함된 값(예: 간격 스케일의 2.5 값)에 접근해야 한다면, 대괄호 표기법을 사용할 수 있습니다.

.content-area {
  height: calc(100vh - theme(spacing[2.5]));
}

Tailwind는 기본 색상 팔레트를 정의할 때 중첩 객체 구문을 사용하므로, 중첩된 색상에 접근할 때는 점 표기법을 사용해야 합니다.

중첩된 색상 값에 접근할 때 대시 구문을 사용하지 마세요

.btn-blue {
  background-color: theme(colors.blue-500);
}

중첩된 색상 값에 접근할 때 점 표기법을 사용하세요

.btn-blue {
  background-color: theme(colors.blue.500);
}

theme으로 가져온 색상의 투명도를 조정하려면, 슬래시 뒤에 원하는 투명도 값을 추가하면 됩니다.

.btn-blue {
  background-color: theme(colors.blue.500 / 75%);
}

screen()

screen 함수를 사용하면 미디어 쿼리를 생성할 때, 브레이크포인트 값을 직접 복사하지 않고 이름으로 참조할 수 있습니다.

@media screen(sm) {
  /* ... */
}

이 코드는 빌드 시점에 브레이크포인트의 실제 값으로 변환되어, 지정된 브레이크포인트와 일치하는 일반적인 미디어 쿼리를 생성합니다:

@media (min-width: 640px) {
  /* ... */
}