「及時」模式:全新世代的 Tailwind CSS
Tailwind CSS on GitHub

使用預處理器

Tailwind 搭配 Sass、Less、Stylus 等常見 CSS 預處理器的使用導覽

Tailwind是 PostCSS 插件,因此你可以任意跟其他預處理器像是 Sass、Less、Stylus 搭配使用。就像你可以跟 Autoprefixer的 PostCSS 插件一起使用一樣。

必須值得注意的是使用 Tailwind 不需使用預處理器 - 基本上 Tailwind 專案只會用到非常少量的 CSS,因此預處理器並不會像你在寫一般使用大量 CSS 專案時,那樣有幫助。

此導覽只是給需要或是想要將 Tailwind 跟預處理器整合的人參考用。


將 PostCSS 當成你的預處理器

如果你的新專案正使用 Tailwind,且不需要跟任何既有的 Sass/Less/Stylus stylesheets 整合,你應該要依靠其他 PostCSS 插件來增加你要的預處理器功能,而不是使用另一個預處理器。

這樣有以下幾個好處:

  • 你的建置會更快 因為你的 CSS 不會被解析,也不會被多種工具處理。只使用 PostCSS 可讓你的 CSS 編譯更快速。
  • 沒有奇怪的方式或是變通方式 因為 Tailwind 增加了一些新的、非標準的關鍵字到 CSS (像 @tailwind@applytheme() 等)。你通常必須要用煩人、不直覺的方式來寫 CSS,好讓預處理器產生你要的結果。你可以只用 PostCSS 來避免這個問題。

有關可用的 PostCSS 插件的完整清單,請看 PostCSS GitHub repository。但是底下有些我們在自己專案使用的重要插件,推薦給你們。

建置階段時引用

預處理器最有用的功能之一就是能夠組織你的 CSS 到多個檔案中,並在建置時提前處理 @import 來合併這些檔案,而不是在瀏覽器處理。

用 PostCSS 處理這個的標準插件是 postcss-import

透過 npm 安裝插件

npm install postcss-import

之後將它加到你 PostCSS 設定中最前面第一個插件的位置:

// postcss.config.js
module.exports = {
  plugins: [
    require('postcss-import'),
    require('tailwindcss'),
    require('autoprefixer'),
  ]
}

有關 postcss-import 一個必須注意的重點是它很嚴謹遵守 CSS 規範,以及只允許 @import 出現在檔案最上面。

無作用,`@import` 必須在最上面

/* components.css */

.btn {
  @apply px-4 py-2 rounded font-semibold bg-gray-200 text-black;
}

/* Will not work */
@import "./components/card";

這個問題最簡單的解法就是不要在同一個檔案中,混用一般 CSS 跟 imports。幫你的 imports 建立一個主要入口檔案,將你全部的 CSS 放在別的檔案。

將 imports 跟 CSS 放在不同的檔案

/* components.css */
@import "./components/buttons.css";
@import "./components/card.css";
/* components/buttons.css */
.btn {
  @apply px-4 py-2 rounded font-semibold bg-gray-200 text-black;
}
/* components/card.css */
.card {
  @apply p-4 bg-white shadow rounded;
}

你最可能遇到的情形就是在你的主要 CSS 檔案中,包含了你的 @tailwind 定義。

無作用,`@import` 必須在最上面

@tailwind base;
@import "./custom-base-styles.css";

@tailwind components;
@import "./custom-components.css";

@tailwind utilities;
@import "./custom-utilities.css";

你可以將每個 @tailwind 定義分別建立不同的檔案來解決這問題,然後在你的主要 stylesheet 引用這些檔案。簡單的做法就是,我們為每個 @tailwind 定義提供一份開箱即用的檔案,讓你可直接從 node_modules 引用。

postcss-import 插件聰明到可以自動在 node_modules 中找到檔案,所以你不用提供完整的路徑 - 舉例來說,"tailwindcss/base" 就夠了。

引用我們提供的 CSS 檔案

@import "tailwindcss/base";
@import "./custom-base-styles.css";

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

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

巢狀

為了支援巢狀定義,我們建議使用我們附帶的 tailwindcss/nesting 插件。此插件包了 postcss-nestedpostcss-nesting,且做為相容層以確保你選用的巢狀插件能充分了解 Tailwind 客製的語法,像 @apply and @screen

它被直接包在 tailwindcss 套件中。你需要做的就只是在加到你的 PostCSS 設定時,加在 Tailwind 之前:

// postcss.config.js
module.exports = {
  plugins: [
    require('postcss-import'),
    require('tailwindcss/nesting'),
    require('tailwindcss'),
    require('autoprefixer'),
  ]
}

它使用了類-Sass 語法,事實上就是預設使用 postcss-nested插件,提供了 Tailwind CSS plugin API的巢狀支持。

如你寧可使用 postcss-nesting (以開發中的 CSS Nesting 規範為基礎),首先安裝:

npm install postcss-nesting

然後將插件當作 tailwindcss/nesting 插件的引數加到你的 PostCSS 設定。

// postcss.config.js
module.exports = {
  plugins: [
    require('postcss-import'),
    require('tailwindcss/nesting')(require('postcss-nesting')),
    require('tailwindcss'),
    require('autoprefixer'),
  ]
}

當你有需要使用某個特定版本的 postcss-nested,且想要覆蓋我們綁定的 tailwindcss/nesting 時,這也能夠有幫助。

請注意,如果你的專案使用 postcss-preset-env,你應該確保停用了巢狀,並讓 tailwindcss/nesting 幫你處理。

// postcss.config.js
module.exports = {
  plugins: [
    require('postcss-import'),
    require('tailwindcss/nesting')(require('postcss-nesting')),
    require('tailwindcss'),
    require('postcss-preset-env')({
      features: { 'nesting-rules': false }
    }),
  ]
}

變數

最近 CSS 變數 (官方稱客製化屬性) 擁有很好的瀏覽器支持 browser support,因此你根本就不需預處理器才能使用變數。

:root {
  --theme-color: #52b3d0;
}

/* ... */

.btn {
  background-color: var(--theme-color);
  /* ... */
}

我們在 Tailwind 中廣泛地使用 CSS 變數,所以你可以在 Tailwind 中使用原生 CSS 變數。

你也可能發現你大部份你過去使用過的變數,都能用 Tailwind 的 theme() 函式取代。你能夠從你的 tailwind.config.js 直接存取你全部的設計 tokens:

.btn {
  background-color: theme('colors.blue.500');
  padding: theme('spacing.2') theme('spacing.4');
  /* ... */
}

更多有關 theme() 函式的資訊,可參考 函式跟指令文件

供應商前綴

為了要自動管理 CSS 的供應商前綴,你應使用 Autoprefixer

透過 npm 安裝:

npm install autoprefixer

然後加到你的 PostCSS 設定中,插件清單的最下面:

module.exports = {
  plugins: [
    require('tailwindcss'),
    require('autoprefixer'),
  ]
}

使用 Sass、Less 或 Stylus

要將 Tailwind 跟其他像 Sass、Less 或 Stylus 之類的預處理器搭配使用, 你將需要增加一個建置的步驟,才能透過 PostCSS 執行你預處理的 CSS。

正確的指令會根據你使用的建置工具而有所不同。更多有關整合 Tailwind 到既有的建置流程,請看安裝文件

要了解如何使用 Tailwind 搭配預處理器最重要的就是要知道 Sass、Less 或 Stylus 之類的預處理器是在 Tailwind 執行前分別執行。舉例來說,你不能將 Tailwind 的 theme() 函式結果輸出到 Sass 顏色函式,因為要在 Sass 完成編譯並輸出給 PostCSS 後,theme() 函式才會被執行。

無作用,Sass 先被處理

.alert {
  background-color: darken(theme('colors.red.500'), 10%);
}

為了得到最有系統的開發體驗,推薦你 唯一使用 PostCSS

除此之外,當跟 Tailwind 搭配使用時,每個預處理器都有自己奇特的方式,以下能看到大綱跟變通方式。

Sass

將 Sass 跟 Tailwind 搭配使用時,!important@apply 會要求你使用內插。

無作用,Sass 會報錯 !important

.alert {
  @apply bg-red-500 !important;
}

變通方式就是使用內插

.alert {
  @apply bg-red-500 #{!important};
}

Less

將 Less 跟 Tailwind 搭配使用時,你不能使用 Tailwind 的 @screen 指令。

無作用,Less 不會意識到這是 media query

.card {
  @apply rounded-none;

  @screen sm {
    @apply rounded-lg;
  }
}

反而應該將一般的 media query 跟 theme() 搭配使用來標示螢幕尺寸,或是不要將 @screen 放在巢狀裡。

將一般的 media query 跟 theme() 一起使用

.card {
  @apply rounded-none;

  @media (min-width: theme('screens.sm')) {
    @apply rounded-lg;
  }
}

在最上層使用 @screen

.card {
  @apply rounded-none;
}
@screen sm {
  .card {
    @apply rounded-lg;
  }
}

Stylus

將 Stylus 跟 Tailwind 搭配使用時,要使用 Tailwind的 @apply 功能,必須要將全部的 CSS 規範包在 @css 之內,這樣 Stylus 才會視為 CSS 語法:

無作用,Stylus 會報錯 @apply

.card {
  @apply rounded-lg bg-white p-4
}

使用 @css 避免被當成 Stylus 處理

@css {
  .card {
    @apply rounded-lg bg-white p-4
  }
}

儘管如此,這樣會造成巨大的損失,因為你在 @css 區塊中,無法使用任何 Stylus 功能

另一個方法就是使用 theme() 函式取代 @apply,直接寫 CSS 屬性:

用 theme() 取代 @apply

.card {
  border-radius: theme('borderRadius.lg');
  background-color: theme('colors.white');
  padding: theme('spacing.4');
}

除此之外,Stylus 不支持 @screen 指令 (就像 Less)。

無作用,Stylus 不會意識到這是 media query

.card {
  border-radius: 0;

  @screen sm {
    border-radius: theme('borderRadius.lg');
  }
}

反而應該將一般的 media query 跟 theme() 搭配使用來標示螢幕尺寸,或是不要將 @screen 放在巢狀裡。

將一般的 media query 跟 theme() 一起使用

.card {
  border-radius: 0;

  @media (min-width: theme('screens.sm')) {
    border-radius: theme('borderRadius.lg');
  }
}

在最上層使用 @screen

.card {
  border-radius: 0;
}
@screen sm {
  .card {
    border-radius: theme('borderRadius.lg');
  }
}