Các phương pháp tốt nhất để thêm các style tùy chỉnh của riêng bạn trong các dự án Tailwind.
Thường thì thách thức lớn nhất khi làm việc với một framework là tìm ra những gì bạn phải làm khi có thứ gì đó bạn cần mà framework không xử lý cho bạn.
Tailwind đã được thiết kế ngay từ đầu để có thể mở rộng và tùy chỉnh, để dù bạn đang xây dựng cái gì, bạn không bao giờ cảm thấy như mình đang chiến đấu với framework.
Hướng dẫn này bao gồm các chủ đề như tùy chỉnh các design token của bạn, cách phá vỡ các ràng buộc đó khi cần thiết, thêm CSS tùy chỉnh của riêng bạn và mở rộng framework bằng các plugin.
Nếu bạn muốn thay đổi những thứ như bảng màu, thang đo khoảng cách, thang đo typography hoặc các breakpoint, hãy thêm các tùy chỉnh của bạn bằng cách sử dụng directive @theme trong CSS của bạn:
@theme { --font-display: "Satoshi", "sans-serif"; --breakpoint-3xl: 120rem; --color-avocado-100: oklch(0.99 0 0); --color-avocado-200: oklch(0.98 0.04 113.22); --color-avocado-300: oklch(0.94 0.11 115.03); --color-avocado-400: oklch(0.92 0.19 114.08); --color-avocado-500: oklch(0.84 0.18 117.33); --color-avocado-600: oklch(0.53 0.12 118.34); --ease-fluid: cubic-bezier(0.3, 0, 0, 1); --ease-snappy: cubic-bezier(0.2, 0, 0, 1); /* ... */}Tìm hiểu thêm về cách tùy chỉnh theme của bạn trong tài liệu về biến theme.
Mặc dù bạn thường có thể xây dựng phần lớn một thiết kế được trau chuốt kỹ lưỡng bằng cách sử dụng một tập hợp các design token bị hạn chế, nhưng đôi khi bạn cần phải phá vỡ các ràng buộc đó để làm cho mọi thứ hoàn hảo đến từng pixel.
Khi bạn thấy mình thực sự cần một cái gì đó như top: 117px để đặt hình nền vào đúng vị trí, hãy sử dụng ký hiệu ngoặc vuông của Tailwind để tạo ra một class ngay lập tức với bất kỳ giá trị tùy ý nào:
<div class="top-[117px]"> <!-- ... --></div>Điều này về cơ bản giống như inline styles, với lợi ích chính là bạn có thể kết hợp nó với các modifier tương tác như hover và các modifier phản hồi như lg:
<div class="top-[117px] lg:top-[344px]"> <!-- ... --></div>Điều này hoạt động cho mọi thứ trong framework, bao gồm những thứ như màu nền, kích thước phông chữ, nội dung pseudo-element, và nhiều hơn nữa:
<div class="bg-[#bada55] text-[22px] before:content-['Festivus']"> <!-- ... --></div>Nếu bạn đang tham chiếu một biến CSS như một giá trị tùy ý, bạn có thể sử dụng cú pháp custom property:
<div class="fill-(--my-brand-color) ..."> <!-- ... --></div>Đây chỉ là cách viết tắt cho fill-[var(--my-brand-color)] giúp thêm hàm var() cho bạn một cách tự động.
Nếu bạn cần sử dụng một thuộc tính CSS mà Tailwind không bao gồm utility sẵn có, bạn cũng có thể sử dụng ký hiệu ngoặc vuông để viết CSS hoàn toàn tùy ý:
<div class="[mask-type:luminance]"> <!-- ... --></div>Điều này thực sự giống như inline styles, nhưng một lần nữa với lợi ích là bạn có thể sử dụng các modifier:
<div class="[mask-type:luminance] hover:[mask-type:alpha]"> <!-- ... --></div>Điều này cũng có thể hữu ích cho những thứ như biến CSS, đặc biệt là khi chúng cần thay đổi trong các điều kiện khác nhau:
<div class="[--scroll-offset:56px] lg:[--scroll-offset:44px]"> <!-- ... --></div>Các variant tùy ý giống như các giá trị tùy ý nhưng để sửa đổi selector ngay lập tức, giống như bạn có thể làm với các variant pseudo-class tích hợp sẵn như hover:{utility} hoặc các variant phản hồi như md:{utility} nhưng sử dụng ký hiệu ngoặc vuông trực tiếp trong HTML của bạn.
<ul role="list"> {#each items as item} <li class="lg:[&:nth-child(-n+3)]:hover:underline">{item}</li> {/each}</ul>Tìm hiểu thêm trong tài liệu về variant tùy ý.
Khi một giá trị tùy ý cần chứa khoảng trắng, hãy sử dụng dấu gạch dưới (_) thay thế và Tailwind sẽ tự động chuyển đổi nó thành khoảng trắng tại thời điểm build:
<div class="grid grid-cols-[1fr_500px_2fr]"> <!-- ... --></div>Trong các tình huống mà dấu gạch dưới là phổ biến nhưng khoảng trắng không hợp lệ, Tailwind sẽ giữ nguyên dấu gạch dưới thay vì chuyển đổi nó thành khoảng trắng, ví dụ như trong các URL:
<div class="bg-[url('/what_a_rush.png')]"> <!-- ... --></div>Trong trường hợp hiếm hoi mà bạn thực sự cần sử dụng dấu gạch dưới nhưng nó gây nhầm lẫn vì khoảng trắng cũng hợp lệ, hãy escape dấu gạch dưới bằng dấu gạch chéo ngược và Tailwind sẽ không chuyển đổi nó thành khoảng trắng:
<div class="before:content-['hello\_world']"> <!-- ... --></div>Nếu bạn đang sử dụng thứ gì đó như JSX nơi dấu gạch chéo ngược bị loại bỏ khỏi HTML được render, hãy sử dụng String.raw() để dấu gạch chéo ngược không bị coi là ký tự escape của JavaScript:
<div className={String.raw`before:content-['hello\_world']`}> <!-- ... --></div>Nhiều utility trong Tailwind chia sẻ một namespace chung nhưng ánh xạ tới các thuộc tính CSS khác nhau. Ví dụ text-lg và text-black đều chia sẻ namespace text-, nhưng một cái dành cho font-size và cái kia dành cho color.
Khi sử dụng các giá trị tùy ý, Tailwind thường có thể tự động xử lý sự mơ hồ này dựa trên giá trị bạn truyền vào:
<!-- Sẽ tạo ra một utility font-size --><div class="text-[22px]">...</div><!-- Sẽ tạo ra một utility color --><div class="text-[#bada55]">...</div>Tuy nhiên, đôi khi nó thực sự mơ hồ, ví dụ như khi sử dụng các biến CSS:
<div class="text-(--my-var)">...</div>Trong những tình huống này, bạn có thể "gợi ý" kiểu cơ bản cho Tailwind bằng cách thêm một kiểu dữ liệu CSS trước giá trị:
<!-- Sẽ tạo ra một utility font-size --><div class="text-(length:--my-var)">...</div><!-- Sẽ tạo ra một utility color --><div class="text-(color:--my-var)">...</div>Mặc dù Tailwind được thiết kế để xử lý phần lớn các nhu cầu styling của bạn, nhưng không có gì ngăn cản bạn viết CSS thuần khi bạn cần:
@import "tailwindcss";.my-custom-style { /* ... */}Nếu bạn chỉ muốn thiết lập một số mặc định cho trang (như màu văn bản, màu nền hoặc phông chữ), tùy chọn dễ nhất là chỉ cần thêm một số class vào các phần tử html hoặc body:
<!doctype html><html lang="en" class="bg-gray-100 font-serif text-gray-900"> <!-- ... --></html>Điều này giữ các quyết định styling cơ bản của bạn trong markup cùng với tất cả các style khác, thay vì ẩn chúng trong một file riêng biệt.
Nếu bạn muốn thêm các style cơ bản mặc định của riêng mình cho các phần tử HTML cụ thể, hãy sử dụng directive @layer để thêm các style đó vào layer base của Tailwind:
@layer base { h1 { font-size: var(--text-2xl); } h2 { font-size: var(--text-xl); }}Sử dụng layer components cho bất kỳ class phức tạp nào bạn muốn thêm vào dự án của mình mà bạn vẫn muốn có thể ghi đè bằng các class utility.
Theo truyền thống, đây sẽ là các class như card, btn, badge — kiểu như vậy.
@layer components { .card { background-color: var(--color-white); border-radius: var(--radius-lg); padding: --spacing(6); box-shadow: var(--shadow-xl); }}Bằng cách định nghĩa các class component trong layer components, bạn vẫn có thể sử dụng các class utility để ghi đè chúng khi cần thiết:
<!-- Sẽ trông giống như một thẻ, nhưng với các góc vuông --><div class="card rounded-none"> <!-- ... --></div>Sử dụng Tailwind, bạn có thể không cần các loại class này thường xuyên như bạn nghĩ. Hãy đọc hướng dẫn của chúng tôi về quản lý sự lặp lại để biết các đề xuất của chúng tôi.
Layer components cũng là một nơi tốt để đặt các style tùy chỉnh cho bất kỳ component bên thứ ba nào bạn đang sử dụng:
@layer components { .select2-dropdown { /* ... */ }}Sử dụng directive @variant để áp dụng một variant Tailwind trong CSS tùy chỉnh:
.my-element { background: white; @variant dark { background: black; }}.my-element { background: white; @media (prefers-color-scheme: dark) { background: black; }}Nếu bạn cần áp dụng nhiều variant cùng một lúc, hãy sử dụng lồng nhau:
.my-element { background: white; @variant dark { @variant hover { background: black; } }}.my-element { background: white; @media (prefers-color-scheme: dark) { &:hover { @media (hover: hover) { background: black; } } }}Ngoài việc sử dụng các utility đi kèm với Tailwind, bạn cũng có thể thêm các utility tùy chỉnh của riêng mình. Điều này có thể hữu ích khi có một tính năng CSS mà bạn muốn sử dụng trong dự án của mình mà Tailwind không bao gồm utility sẵn có.
Sử dụng directive @utility để thêm một utility tùy chỉnh vào dự án của bạn:
@utility content-auto { content-visibility: auto;}Bây giờ bạn có thể sử dụng utility này trong HTML của mình:
<div class="content-auto"> <!-- ... --></div>Nó cũng sẽ hoạt động với các variant như hover, focus và lg:
<div class="hover:content-auto"> <!-- ... --></div>Các utility tùy chỉnh được tự động chèn vào layer utilities cùng với tất cả các utility tích hợp sẵn trong framework.
Nếu utility tùy chỉnh của bạn phức tạp hơn một tên class đơn lẻ, hãy sử dụng lồng nhau để định nghĩa utility:
@utility scrollbar-hidden { &::-webkit-scrollbar { display: none; }}Ngoài việc đăng ký các utility đơn giản với directive @utility, bạn cũng có thể đăng ký các utility chức năng chấp nhận một đối số:
@utility tab-* { tab-size: --value(--tab-size-*);}Hàm đặc biệt --value() được sử dụng để giải quyết giá trị utility.
Sử dụng cú pháp --value(--theme-key-*) để giải quyết giá trị utility dựa trên một tập hợp các key theme:
@theme { --tab-size-2: 2; --tab-size-4: 4; --tab-size-github: 8;}@utility tab-* { tab-size: --value(--tab-size-*);}Điều này sẽ khớp với các utility như tab-2, tab-4, và tab-github.
Để giải quyết giá trị như một giá trị trần, hãy sử dụng cú pháp --value({type}), trong đó {type} là kiểu dữ liệu bạn muốn xác thực giá trị trần:
@utility tab-* { tab-size: --value(integer);}Điều này sẽ khớp với các utility như tab-1 và tab-76.
Các kiểu dữ liệu giá trị trần có sẵn là: number, integer, ratio, và percentage.
Để hỗ trợ các giá trị literal, hãy sử dụng cú pháp --value('literal') (chú ý dấu ngoặc kép):
@utility tab-* { tab-size: --value("inherit", "initial", "unset");}Điều này sẽ khớp với các utility như tab-inherit, tab-initial, và tab-unset.
Để hỗ trợ các giá trị tùy ý, hãy sử dụng cú pháp --value([{type}]) (chú ý dấu ngoặc vuông) để cho Tailwind biết những kiểu nào được hỗ trợ như một giá trị tùy ý:
@utility tab-* { tab-size: --value([integer]);}Điều này sẽ khớp với các utility như tab-[1] và tab-[76].
Các kiểu dữ liệu giá trị tùy ý có sẵn là: absolute-size, angle, bg-size, color, family-name, generic-name, image, integer, length, line-width, number, percentage, position, ratio, relative-size, url, vector, và *.
Cả ba dạng của hàm --value() đều có thể được sử dụng trong một quy tắc dưới dạng nhiều khai báo, và bất kỳ khai báo nào không giải quyết được sẽ bị bỏ qua trong đầu ra:
@theme { --tab-size-github: 8;}@utility tab-* { tab-size: --value([integer]); tab-size: --value(integer); tab-size: --value(--tab-size-*);}Điều này giúp bạn có thể xử lý giá trị khác nhau trong từng trường hợp nếu cần thiết, ví dụ như dịch một số nguyên trần thành phần trăm:
@utility opacity-* { opacity: --value([percentage]); opacity: calc(--value(integer) * 1%); opacity: --value(--opacity-*);}Hàm --value() cũng có thể nhận nhiều đối số và giải quyết chúng từ trái sang phải nếu bạn không cần xử lý giá trị trả về khác nhau trong các trường hợp khác nhau:
@theme { --tab-size-github: 8;}@utility tab-* { tab-size: --value(--tab-size-*, integer, [integer]);}@utility opacity-* { opacity: calc(--value(integer) * 1%); opacity: --value(--opacity-*, [percentage]);}Để hỗ trợ các giá trị âm, hãy đăng ký các utility dương và âm riêng biệt vào các khai báo riêng biệt:
@utility inset-* { inset: --spacing(--value(integer)); inset: --value([percentage], [length]);}@utility -inset-* { inset: --spacing(--value(integer) * -1); inset: calc(--value([percentage], [length]) * -1);}Các modifier được xử lý bằng cách sử dụng hàm --modifier(), hoạt động chính xác giống như hàm --value() nhưng tác động lên một modifier nếu có:
@utility text-* { font-size: --value(--text-*, [length]); line-height: --modifier(--leading-*, [length], [*]);}Nếu một modifier không hiện diện, bất kỳ khai báo nào phụ thuộc vào modifier sẽ không được bao gồm trong đầu ra.
Để xử lý phân số, chúng tôi dựa vào kiểu dữ liệu ratio của CSS. Nếu nó được sử dụng với --value(), đó là tín hiệu để Tailwind xử lý giá trị và modifier như một giá trị duy nhất:
@utility aspect-* { aspect-ratio: --value(--aspect-ratio-*, ratio, [ratio]);}Điều này sẽ khớp với các utility như aspect-square, aspect-3/4, và aspect-[7/9].
Ngoài việc sử dụng các variant đi kèm với Tailwind, bạn cũng có thể thêm các variant tùy chỉnh của riêng mình bằng cách sử dụng directive @custom-variant:
@custom-variant theme-midnight { &:where([data-theme="midnight"] *) { @slot; }}Bây giờ bạn có thể sử dụng variant theme-midnight:<utility> trong HTML của mình:
<html data-theme="midnight"> <button class="theme-midnight:bg-black ..."></button></html>Bạn có thể tạo các variant bằng cách sử dụng cú pháp viết tắt khi không yêu cầu lồng nhau:
@custom-variant theme-midnight (&:where([data-theme="midnight"] *));Khi một variant tùy chỉnh có nhiều quy tắc, chúng có thể được lồng vào nhau:
@custom-variant any-hover { @media (any-hover: hover) { &:hover { @slot; } }}