Customization
Tailwind를 재사용 가능한 서드파티 플러그인으로 확장하기.
플러그인을 사용하면 CSS 대신 JavaScript를 통해 Tailwind가 사용자의 스타일시트에 주입할 새로운 스타일을 등록할 수 있습니다.
첫 번째 플러그인을 시작하려면, tailwindcss/plugin
에서 Tailwind의 plugin
함수를 가져옵니다. 그런 다음 plugins
배열 안에서, 가져온 plugin
함수를 첫 번째 인자로 익명 함수와 함께 호출합니다.
const plugin = require('tailwindcss/plugin')
module.exports = {
plugins: [
plugin(function({ addUtilities, addComponents, e, config }) {
// 여기에 커스텀 스타일을 추가하세요
}),
]
}
플러그인 함수는 단일 객체 인자를 받으며, 이 객체는 여러 헬퍼 함수로 구조 분해할 수 있습니다:
addUtilities()
: 새로운 정적 유틸리티 스타일을 등록matchUtilities()
: 새로운 동적 유틸리티 스타일을 등록addComponents()
: 새로운 정적 컴포넌트 스타일을 등록matchComponents()
: 새로운 동적 컴포넌트 스타일을 등록addBase()
: 새로운 기본 스타일을 등록addVariant()
: 커스텀 정적 변형을 등록matchVariant()
: 커스텀 동적 변형을 등록theme()
: 사용자의 테마 설정에서 값을 조회config()
: 사용자의 Tailwind 설정에서 값을 조회corePlugins()
: 코어 플러그인이 활성화되었는지 확인e()
: 클래스 이름으로 사용될 문자열을 수동으로 이스케이프우리는 여러 가지 이유로 코어에 포함되지 않은 인기 있는 기능들을 위한 몇 가지 공식 플러그인을 개발했습니다.
플러그인은 npm을 통해 설치한 후 tailwind.config.js
파일에 추가하여 프로젝트에 적용할 수 있습니다.
/** @type {import('tailwindcss').Config} */
module.exports = {
// ...
plugins: [
require('@tailwindcss/typography'),
require('@tailwindcss/forms'),
require('@tailwindcss/aspect-ratio'),
require('@tailwindcss/container-queries'),
]
}
@tailwindcss/typography
플러그인은 마크다운이나 CMS 데이터베이스와 같은 소스에서 가져온 콘텐츠 블록에 적절한 타이포그래피 스타일을 빠르게 적용할 수 있는 prose
클래스 세트를 제공합니다.
<article class="prose lg:prose-xl">
<h1>치즈가 든 갈릭 브레드: 과학이 말해주는 것</h1>
<p>
수년 동안 부모들은 치즈가 든 갈릭 브레드의 건강상 이점을 아이들에게 강조해 왔으며, 이 음식은 우리 문화에서 아이들이 할로윈에 따뜻하고 치즈가 든 빵으로 분장할 정도로 상징적인 지위를 얻었습니다.
</p>
<p>
하지만 최근 연구에 따르면 이 유명한 전채 요리가 전국적으로 발생하는 광견병 사례와 관련이 있을 수 있다고 합니다.
</p>
<!-- ... -->
</article>
@tailwindcss/forms
플러그인은 폼 엘리먼트를 유틸리티 클래스로 쉽게 스타일링할 수 있도록 도와주는 폼 리셋 레이어를 추가합니다.
<!-- select 엘리먼트의 패딩을 커스터마이징할 수 있습니다: -->
<select class="px-4 py-3 rounded-full">
<!-- ... -->
</select>
<!-- 또는 텍스트 색상 유틸리티를 사용해 체크박스 색상을 변경할 수 있습니다: -->
<input type="checkbox" class="rounded text-pink-500" />
@tailwindcss/aspect-ratio
플러그인은 오래된 브라우저에서도 작동하는 네이티브 aspect-ratio
대안입니다. 이 플러그인은 aspect-w-*
와 aspect-h-*
클래스를 추가하여 엘리먼트에 고정된 가로세로 비율을 지정할 수 있게 해줍니다.
<div class="aspect-w-16 aspect-h-9">
<iframe src="https://www.youtube.com/embed/dQw4w9WgXcQ" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</div>
@tailwindcss/container-queries
플러그인은 뷰포트 대신 @container
로 표시된 부모 요소의 크기에 따라 스타일을 적용할 수 있는 @{size}
변형(예: @sm
, @md
)을 추가합니다.
<div class="@container">
<div class="@lg:text-sky-400">
<!-- ... -->
</div>
</div>
addUtilities
와 matchUtilities
함수를 사용하면 Tailwind의 utilities
레이어에 새로운 스타일을 등록할 수 있습니다.
Tailwind에 기본으로 포함된 유틸리티와 마찬가지로, 플러그인을 통해 추가된 유틸리티도 프로젝트에서 실제로 사용될 때만 생성된 CSS에 포함됩니다.
사용자가 제공한 값을 지원하지 않는 간단한 정적 유틸리티를 등록하려면 addUtilities
함수를 사용하세요:
const plugin = require('tailwindcss/plugin')
module.exports = {
plugins: [
plugin(function({ addUtilities }) {
addUtilities({
'.content-auto': {
'content-visibility': 'auto',
},
'.content-hidden': {
'content-visibility': 'hidden',
},
'.content-visible': {
'content-visibility': 'visible',
},
})
})
]
}
스타일을 자바스크립트로 표현하는 방법에 대해 더 알아보려면 CSS-in-JS 문법 참고 문서를 확인하세요.
matchUtilities
함수를 사용하여 사용자의 theme
설정에 정의된 값에 매핑되는 유틸리티를 등록할 수 있습니다:
const plugin = require('tailwindcss/plugin')
module.exports = {
theme: {
tabSize: {
1: '1',
2: '2',
4: '4',
8: '8',
}
},
plugins: [
plugin(function({ matchUtilities, theme }) {
matchUtilities(
{
tab: (value) => ({
tabSize: value
}),
},
{ values: theme('tabSize') }
)
})
]
}
이렇게 정의된 유틸리티는 임의 값도 지원합니다. 따라서 테마에 없는 값을 대괄호 표기법을 사용하여 적용할 수 있습니다:
<div class="tab-[13]">
<!-- ... -->
</div>
기본적으로 플러그인 유틸리티는 사용자의 prefix
와 important
설정을 자동으로 따릅니다.
예를 들어, 다음과 같은 Tailwind 설정이 있다고 가정해 보겠습니다:
/** @type {import('tailwindcss').Config} */
module.exports = {
prefix: 'tw-',
important: true,
// ...
}
위의 예제 플러그인은 다음과 같은 CSS를 생성합니다:
.tw-content-auto {
content-visibility: auto !important;
}
.tw-content-hidden {
content-visibility: hidden !important;
}
.tw-content-visible {
content-visibility: visible !important;
}
addUtilities
를 사용해 추가한 커스텀 유틸리티는 자동으로 수식어와 함께 사용할 수 있습니다:
<div class="content-auto lg:content-visible">
<!-- ... -->
</div>
더 자세한 내용은 호버, 포커스 및 기타 상태 문서에서 확인할 수 있습니다.
유틸리티 플러그인은 plugin
함수의 두 번째 인자로 설정 객체를 포함하여 기본값을 제공할 수 있습니다:
const plugin = require('tailwindcss/plugin')
module.exports = plugin(function({ matchUtilities, theme }) {
matchUtilities(
{
tab: (value) => ({
tabSize: value
}),
},
{ values: theme('tabSize') }
)
}, {
theme: {
tabSize: {
1: '1',
2: '2',
4: '4',
8: '8',
}
}
})
이 값들은 기본 설정에 있는 값들과 동일하게 동작하며, 최종 사용자가 이를 재정의하거나 확장할 수 있습니다.
addComponents
함수를 사용하면 Tailwind의 components
레이어에 새로운 스타일을 등록할 수 있습니다.
이 기능은 버튼, 폼 컨트롤, 알림 등과 같이 다른 프레임워크에서 자주 볼 수 있는 미리 만들어진 컴포넌트 스타일을 추가할 때 유용합니다. 이러한 스타일은 유틸리티 클래스로 재정의해야 할 수도 있습니다.
플러그인에서 새로운 컴포넌트 스타일을 추가하려면, CSS-in-JS 문법을 사용하여 스타일을 전달하면서 addComponents
를 호출합니다:
const plugin = require('tailwindcss/plugin')
module.exports = {
plugins: [
plugin(function({ addComponents }) {
addComponents({
'.btn': {
padding: '.5rem 1rem',
borderRadius: '.25rem',
fontWeight: '600',
},
'.btn-blue': {
backgroundColor: '#3490dc',
color: '#fff',
'&:hover': {
backgroundColor: '#2779bd'
},
},
'.btn-red': {
backgroundColor: '#e3342f',
color: '#fff',
'&:hover': {
backgroundColor: '#cc1f1a'
},
},
})
})
]
}
Tailwind의 다른 컴포넌트 클래스와 마찬가지로, 플러그인을 통해 추가된 컴포넌트 클래스는 프로젝트에서 실제로 사용될 때만 생성된 CSS에 포함됩니다.
기본적으로 컴포넌트 클래스는 사용자의 prefix
설정을 자동으로 따르지만, 사용자의 important
설정에는 영향을 받지 않습니다.
즉, 다음과 같은 Tailwind 설정이 주어졌을 때:
/** @type {import('tailwindcss').Config} */
module.exports = {
prefix: 'tw-',
important: true,
// ...
}
위의 예제 플러그인은 다음과 같은 CSS를 생성합니다:
.tw-btn {
padding: .5rem 1rem;
border-radius: .25rem;
font-weight: 600;
}
.tw-btn-blue {
background-color: #3490dc;
color: #fff;
}
.tw-btn-blue:hover {
background-color: #2779bd;
}
.tw-btn-red {
background-color: #e3342f;
color: #fff;
}
.tw-btn-red:hover {
background-color: #cc1f1a;
}
컴포넌트 선언을 important
로 만드는 것은 드물지만, 정말로 필요하다면 수동으로 !important
를 추가할 수 있습니다:
const plugin = require('tailwindcss/plugin')
module.exports = {
plugins: [
plugin(function({ addComponents }) {
addComponents({
'.btn': {
padding: '.5rem 1rem !important',
borderRadius: '.25rem !important',
fontWeight: '600 !important',
},
// ...
})
})
]
}
기본적으로 선택자 내의 모든 클래스에는 접두사가 붙습니다. 따라서 다음과 같이 더 복잡한 스타일을 추가하면:
const plugin = require('tailwindcss/plugin')
module.exports = {
prefix: 'tw-',
plugins: [
plugin(function({ addComponents }) {
const components = {
// ...
'.navbar-inverse a.nav-link': {
color: '#fff',
}
}
addComponents(components)
})
]
}
다음과 같은 CSS가 생성됩니다:
.tw-navbar-inverse a.tw-nav-link {
color: #fff;
}
modifiers_ifKPvTE8bYug4bAM67NFC7
와 함께 사용하기addComponents
를 사용해 추가한 모든 컴포넌트 클래스는 자동으로 수정자(modifiers)와 함께 사용할 수 있습니다:
<div class="btn md:btn-lg">
<!-- ... -->
</div>
더 자세한 내용은 Hover, Focus, and Other States 문서에서 확인할 수 있습니다.
addBase
함수를 사용하면 Tailwind의 base
레이어에 새로운 스타일을 등록할 수 있습니다. 이 함수를 사용해 기본 타이포그래피 스타일, 전역 리셋 스타일, 또는 @font-face
규칙 등을 추가할 수 있습니다.
플러그인에서 새로운 기본 스타일을 추가하려면, CSS-in-JS 문법을 사용해 스타일을 전달하면서 addBase
를 호출합니다:
const plugin = require('tailwindcss/plugin')
module.exports = {
plugins: [
plugin(function({ addBase, theme }) {
addBase({
'h1': { fontSize: theme('fontSize.2xl') },
'h2': { fontSize: theme('fontSize.xl') },
'h3': { fontSize: theme('fontSize.lg') },
})
})
]
}
기본 스타일은 div
나 h1
과 같은 순수 선택자를 대상으로 하기 때문에, 사용자가 설정한 prefix
나 important
설정을 따르지 않습니다.
addVariant
와 matchVariant
함수를 사용하면 여러분만의 커스텀 수정자를 등록할 수 있습니다. 이 수정자는 hover
, focus
, supports
와 같은 내장 변형과 동일하게 사용할 수 있습니다.
간단한 커스텀 변형을 만들려면 addVariant
함수를 사용하세요. 이 함수는 커스텀 변형의 이름과 선택자가 어떻게 수정되어야 하는지를 나타내는 형식 문자열을 인자로 받습니다.
const plugin = require('tailwindcss/plugin')
module.exports = {
// ...
plugins: [
plugin(function({ addVariant }) {
addVariant('optional', '&:optional')
addVariant('hocus', ['&:hover', '&:focus'])
addVariant('inverted-colors', '@media (inverted-colors: inverted)')
})
]
}
첫 번째 인자는 사용자가 HTML에서 사용할 수정자 이름입니다. 위 예제를 통해 다음과 같은 클래스를 작성할 수 있습니다.
<form class="flex inverted-colors:outline ...">
<input class="optional:border-gray-300 ..." />
<button class="bg-blue-500 hocus:bg-blue-600">...</button>
</form>
내장된 supports-*
, data-*
, aria-*
변형과 같은 새로운 파라미터화된 변형을 등록하려면 matchVariant
함수를 사용하세요:
const plugin = require('tailwindcss/plugin')
module.exports = {
plugins: [
plugin(function({ matchVariant }) {
matchVariant(
'nth',
(value) => {
return `&:nth-child(${value})`;
},
{
values: {
1: '1',
2: '2',
3: '3',
}
}
);
})
]
}
matchVariant
로 정의된 변형은 대괄호 표기법을 사용해 임의의 값을 지원합니다:
<div class="nth-[3n+1]:bg-blue-500 ...">
<!-- ... -->
</div>
같은 변형에서 나온 다른 값들과의 우선순위 문제를 피하기 위해 생성된 CSS의 소스 순서를 제어하려면 sort
옵션을 사용하세요:
matchVariant("min", (value) => `@media (min-width: ${value})`, {
sort(a, z) {
return parseInt(a.value) - parseInt(z.value);
},
});
여러분이 만든 커스텀 수식어(modifiers)는 Tailwind의 부모 및 형제 상태 수식어와 자동으로 작동하지 않습니다.
group-*
및 peer-*
버전의 커스텀 수식어를 지원하려면, 특수한 :merge
지시어를 사용하여 별도의 변형(variants)으로 등록해야 합니다. 이렇게 하면 최종 선택자에서 .group
및 .peer
클래스가 한 번만 나타나도록 보장할 수 있습니다.
const plugin = require('tailwindcss/plugin')
module.exports = {
// ...
plugins: [
plugin(function({ addVariant }) {
addVariant('optional', '&:optional')
addVariant('group-optional', ':merge(.group):optional &')
addVariant('peer-optional', ':merge(.peer):optional ~ &')
})
]
}
플러그인은 plugin
함수의 두 번째 인자로 객체를 제공하여 사용자의 tailwind.config.js
설정에 자체 설정 값을 병합할 수 있습니다.
const plugin = require('tailwindcss/plugin')
module.exports = plugin(function({ matchUtilities, theme }) {
matchUtilities(
{
tab: (value) => ({
tabSize: value
}),
},
{ values: theme('tabSize') }
)
}, {
theme: {
tabSize: {
1: '1',
2: '2',
4: '4',
8: '8',
}
}
})
이 방법은 플러그인이 생성하는 클래스에 대한 기본 theme
값을 제공하는 데 유용합니다.
때로는 플러그인이 theme
아래에 속하지 않는 방식으로 구성 가능하도록 만드는 것이 합리적일 수 있습니다. 예를 들어, 사용자가 플러그인이 사용하는 클래스 이름을 커스텀할 수 있도록 하고 싶을 수 있습니다.
이런 경우에는 plugin.withOptions
를 사용하여 구성 객체와 함께 호출할 수 있는 플러그인을 정의할 수 있습니다. 이 API는 일반적인 plugin
API와 유사하지만, 각 인수는 사용자의 options
를 받아들이고 일반 API를 사용하여 전달했을 값을 반환하는 함수여야 합니다:
const plugin = require('tailwindcss/plugin')
module.exports = plugin.withOptions(function (options = {}) {
return function({ addComponents }) {
const className = options.className ?? 'markdown'
addComponents({
[`.${className}`]: {
// ...
}
})
}
}, function (options) {
return {
theme: {
markdown: {
// ...
}
},
}
})
사용자는 plugins
설정에서 플러그인을 등록할 때 옵션을 전달하여 플러그인을 호출할 수 있습니다:
/** @type {import('tailwindcss').Config} */
module.exports = {
theme: {
// ...
},
plugins: [
require('./plugins/markdown.js')({
className: 'wysiwyg'
})
],
}
사용자는 커스텀 옵션을 전달할 필요가 없는 경우, 이렇게 생성된 플러그인을 일반적으로 등록할 수도 있습니다:
/** @type {import('tailwindcss').Config} */
module.exports = {
theme: {
// ...
},
plugins: [
require('./plugins/markdown.js')
],
}
Tailwind의 플러그인 시스템은 Emotion과 같은 CSS-in-JS 라이브러리에서 사용하는 것과 유사한 문법으로 작성된 CSS 규칙을 JavaScript 객체로 기대합니다. 이는 내부적으로 postcss-js를 통해 동작합니다.
다음은 간단한 CSS 규칙입니다:
.card {
background-color: #fff;
border-radius: .25rem;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
}
이를 CSS-in-JS 객체로 변환하면 다음과 같습니다:
addComponents({
'.card': {
'background-color': '#fff',
'border-radius': '.25rem',
'box-shadow': '0 2px 4px rgba(0,0,0,0.2)',
}
})
편의를 위해 속성 이름을 camelCase로 작성할 수도 있으며, 이는 자동으로 dash-case로 변환됩니다:
addComponents({
'.card': {
backgroundColor: '#fff',
borderRadius: '.25rem',
boxShadow: '0 2px 4px rgba(0,0,0,0.2)',
}
})
Sass나 Less에서 익숙한 것과 동일한 문법을 사용하여 중첩도 지원됩니다 (postcss-nested를 통해):
addComponents({
'.card': {
backgroundColor: '#fff',
borderRadius: '.25rem',
boxShadow: '0 2px 4px rgba(0,0,0,0.2)',
'&:hover': {
boxShadow: '0 10px 15px rgba(0,0,0,0.2)',
},
'@media (min-width: 500px)': {
borderRadius: '.5rem',
}
}
})
동일한 객체 내에서 여러 규칙을 정의할 수도 있습니다:
addComponents({
'.btn': {
padding: '.5rem 1rem',
borderRadius: '.25rem',
fontWeight: '600',
},
'.btn-blue': {
backgroundColor: '#3490dc',
color: '#fff',
'&:hover': {
backgroundColor: '#2779bd'
},
},
'.btn-red': {
backgroundColor: '#e3342f',
color: '#fff',
'&:hover': {
backgroundColor: '#cc1f1a'
},
},
})
또는 동일한 키를 반복해야 하는 경우 객체 배열로 정의할 수도 있습니다:
addComponents([
{
'@media (min-width: 500px)': {
// ...
}
},
{
'@media (min-width: 500px)': {
// ...
}
},
{
'@media (min-width: 500px)': {
// ...
}
},
])