Svelte 作用域樣式
將每個 Svelte 組件的工具樣式產生的 CSS 直接放入 Svelte 組件的 <style>
區塊中,而不是放在全域 CSS 檔案中。
此組件
<div class="mb-1" />
將會轉換成
<div class="uno-ei382o" />
<style>
:global(.uno-ei382o) {
margin-bottom: 0.25rem;
}
</style>
何時使用
使用案例 | 說明 | 使用的套件 | |
---|---|---|---|
小型應用程式 | ❌ | 擁有一個全域 CSS 檔案更方便。請使用一般的 Vite 外掛程式來處理 Svelte/SvelteKit。 | unocss/vite |
大型應用程式 | ✅ | Svelte 作用域樣式可以幫助您避免不斷增長的全域 CSS 檔案。 | @unocss/svelte-scoped/vite |
組件庫 | ✅ | 產生的樣式會直接放置在建置的組件中,而無需在使用應用程式的建置流程中使用 UnoCSS。 | @unocss/svelte-scoped/preprocess |
運作方式
一般的 UnoCSS/Tailwind CSS 設定會將工具樣式放置在具有正確順序的全域 CSS 檔案中。相反,Svelte 作用域樣式會將您的樣式分佈到許多任意排序的 Svelte 組件 CSS 檔案中。然而,它必須保持工具樣式的全域性,以便它們可以根據上下文感知的需要,例如從右到左和其他 下方列出的使用案例。這帶來了一個挑戰,解決方法是使用 Svelte 的 :global()
包裝器來選擇退出預設的 Svelte CSS 雜湊方法,而是使用基於檔名 + 類別名稱的雜湊來編譯唯一的類別名稱,這些類別名稱可以在沒有樣式衝突的情況下設為全域。
用法
由於 Svelte 作用域樣式會重寫您的工具類別名稱,因此您可以編寫它們的位置會受到限制
支援的語法 | 範例 |
---|---|
類別屬性 | <div class="mb-1" /> |
類別指令 | <div class:mb-1={condition} /> |
類別指令簡寫 | <div class:logo /> |
類別屬性 | <Button class="mb-1" /> |
Svelte 作用域樣式旨在作為使用工具樣式的專案的直接替代品。因此,也支援在類別屬性中找到的表達式(例如 <div class="mb-1 {foo ? 'mr-1' : 'mr-2'}" />
),但我們建議您今後使用類別指令語法。另請注意,如果您以其他方式使用類別名稱,例如將它們放在 <script>
區塊中或使用屬性化模式,那麼在使用 Svelte 作用域樣式之前,您需要採取額外的步驟。您可以利用 safelist
選項,也可以查看下方的 預設集 部分以獲取更多提示。
上下文感知
即使樣式分佈在應用程式的 Svelte 組件中,它們仍然是全域類別,並且會與特定組件外部的元素相關聯。以下是一些範例
依賴父組件
依賴父組件中屬性的類別
<div class="dark:mb-2 rtl:right-0"></div>
將會轉換成
<div class="uno-3hashz"></div>
<style>
:global(.dark .uno-3hashz) {
margin-bottom: 0.5rem;
}
:global([dir="rtl"] .uno-3hashz) {
right: 0rem;
}
</style>
子組件影響
您可以在 3 個子元素之間添加空格,其中一些子元素位於不同的組件中
<div class="space-x-1">
<div>Status: online</div>
<Button>FAQ</Button>
<Button>Login</Button>
</div>
將會轉換成
<div class="uno-7haszz">
<div>Status: online</div>
<Button>FAQ</Button>
<Button>Login</Button>
</div>
<style>
:global(.uno-7haszz > :not([hidden]) ~ :not([hidden])) {
--un-space-x-reverse: 0;
margin-left: calc(0.25rem * calc(1 - var(--un-space-x-reverse)));
margin-right: calc(0.25rem * var(--un-space-x-reverse));
}
</style>
將類別傳遞給子組件
您可以在組件中添加 class
屬性,以便在使用該組件的任何地方傳遞自定義類別。
<Button class="px-2 py-1">Login</Button>
將會轉換成
<Button class="uno-4hshza">Login</Button>
<style>
:global(.uno-4hshza) {
padding-left:0.5rem;
padding-right:0.5rem;
padding-top:0.25rem;
padding-bottom:0.25rem;
}
</style>
在接收組件中實作類別的一個簡單方法是使用 {$$props.class}
將它們放置在元素上,例如 div class="{$$props.class} foo bar" />
。
套用指令
您可以在 <style>
區塊中使用套用指令,使用 --at-apply
或 @apply
或使用 applyVariables
選項設定的自定義值。
Svelte 作用域樣式甚至可以正確處理上下文相關的類別,例如 dark:text-white
,而一般的 @unocss/transformer-directives
套件無法正確處理,因為它不是專為 Svelte 樣式區塊建置的。例如,使用 Svelte 作用域樣式,此組件
<div />
<style>
div {
--at-apply: rtl:ml-2;
}
</style>
將會轉換成
<div />
<style>
:global([dir=\\"rtl\\"]) div {
margin-right: 0.5rem;
}
</style>
為了使 rtl:ml-2
正常運作,[dir="rtl"]
選擇器會使用 :global()
包裝,以防止 Svelte 編譯器自動將其刪除,因為組件中沒有具有該屬性的元素。然而,div
不能包含在 :global()
包裝器中,因為該樣式會影響應用程式中的每個 div
。
其他樣式區塊指令
Vite 外掛程式
在 Svelte 或 SvelteKit 應用程式中,將產生的樣式直接注入到您的 Svelte 組件中,同時將最必要的樣式放置在全域樣式表中。在 Stackblitz 中查看 SvelteKit 範例
安裝
pnpm add -D unocss @unocss/svelte-scoped
yarn add -D unocss @unocss/svelte-scoped
npm install -D unocss @unocss/svelte-scoped
新增外掛程式
將 @unocss/svelte-scoped/vite
新增到您的 Vite 設定中
import { sveltekit } from '@sveltejs/kit/vite'
import UnoCSS from '@unocss/svelte-scoped/vite'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
UnoCSS({
// injectReset: '@unocss/reset/normalize.css', // see type definition for all included reset options or how to pass in your own
// ...other Svelte Scoped options
}),
sveltekit(),
],
})
新增設定檔
如下 所述 設定您的 uno.config.ts
檔案。
全域樣式
雖然幾乎所有樣式都放置在個別組件中,但仍然有一些樣式必須放置在全域樣式表中:預設樣式、安全列表和可選的重置(如果您使用 injectReset
選項)。
將 %unocss-svelte-scoped.global%
預留位置新增到您的 <head>
標籤中。在 Svelte 中,這是 index.html
。在 SvelteKit 中,這將在 app.html
中的 %sveltekit.head%
之前
<head>
<!-- ... -->
<title>SvelteKit using UnoCSS Svelte Scoped</title>
%unocss-svelte-scoped.global%
%sveltekit.head%
</head>
如果使用 SvelteKit,您還必須將以下內容新增到 src/hooks.server.js
檔案中的 transformPageChunk
鉤子中
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
const response = await resolve(event, {
transformPageChunk: ({ html }) =>
html.replace(
'%unocss-svelte-scoped.global%',
'unocss_svelte_scoped_global_styles'
),
})
return response
}
此轉換必須位於 路徑包含 `hooks` 和 `server` 的檔案中(例如 `src/hooks.server.js`、`src/hooks.server.ts`),因為 `svelte-scoped` 將會在您的伺服器鉤子檔案中尋找,以使用您的全域樣式替換 `unocss_svelte_scoped_global_styles`。請確保不要從其他檔案匯入此轉換,例如當使用 sequence 從 `@sveltejs/kit/hooks` 匯入時。
在一般的 Svelte 專案中,Vite 的 transformIndexHtml
鉤子會自動執行此操作。
Svelte 預處理器
使用工具樣式來建置一個不依賴於包含配套 CSS 檔案的組件庫,方法是使用預處理器將產生的樣式直接放置到建置的組件中。在 Stackblitz 中查看 SvelteKit 程式庫範例
安裝
pnpm add -D unocss @unocss/svelte-scoped
yarn add -D unocss @unocss/svelte-scoped
npm install -D unocss @unocss/svelte-scoped
新增預處理器
將 @unocss/svelte-scoped/preprocess
新增到您的 Svelte 設定中
import adapter from '@sveltejs/adapter-auto'
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
import UnoCSS from '@unocss/svelte-scoped/preprocess'
const config = {
preprocess: [
vitePreprocess(),
UnoCSS({
// ... preprocessor options
}),
],
// other Svelte config
}
不要在開發過程中合併類別名稱
在一般應用程式中使用 Svelte 作用域樣式時,Vite 外掛程式會自動偵測 `dev` 與 `build`。在開發過程中,類別將會保持 distinct 並且就地雜湊,以便在瀏覽器的開發者工具中輕鬆地開啟/關閉。`class="mb-1 mr-1"` 將會變成類似 `class="_mb-1_9hwi32 _mr-1_84jfy4"` 的東西。在生產環境中,這些類別將會使用您想要的前綴(預設為 `uno-`)以及基於檔名 + 類別名稱的雜湊編譯成單個類別名稱,例如 `class="uno-84dke3"`。
如果您希望在使用預處理器時也具有相同的行為,則必須根據環境手動設定 `combine` 選項。一種方法是安裝 cross-env 並將您的開發指令碼更新為
"dev": "cross-env NODE_ENV=development vite dev"
然後調整您的 svelte.config.js
+const prod = process.env.NODE_ENV !== 'development'
const config = {
preprocess: [
vitePreprocess(),
UnoCSS({
+ combine: prod,
}),
],
}
新增設定檔
如下 所述 設定您的 uno.config.ts
檔案。
預設樣式
使用預處理器時,您可以選擇將預設樣式包含在需要的特定組件中,方法是將 `uno-preflights` 作為樣式屬性新增。
<style uno-preflights></style>
任何以句點開頭的特殊預設樣式,例如 ` .prose :where(a):not(:where(.not-prose, .not-prose *))`,都將使用 `:global()` 包裝,以避免被 Svelte 編譯器自動刪除。
如果您的類別不依賴預設樣式,或者您建置的組件僅在已包含預設樣式的應用程式中使用,則無需將預設樣式新增到個別組件中。
安全列表
使用預處理器時,您可以選擇將安全列表類別包含在組件中,方法是將 `uno-safelist` 作為樣式屬性新增。
<style uno-safelist></style>
您的安全名單樣式將會被 :global()
包裹,以避免被 Svelte 編譯器自動移除。
設定
將您的 UnoCSS 設定放置在 uno.config.ts
檔案中
import { defineConfig } from 'unocss'
export default defineConfig({
// ...UnoCSS options
})
由於一般 UnoCSS 全域使用方式和 Svelte 作用域使用方式的差異,因此不支援提取器。預設集和轉換器則如同以下章節所述般受到支援。其他詳細資訊請參閱設定檔和設定參考。
預設集支援
由於需要在全域樣式表中設定一些必要的樣式,而其他所有樣式則依需求包含在每個元件中,因此需要根據具體情況處理預設集。
預設集 | 是否支援 | 備註 |
---|---|---|
@unocss/preset-uno、@unocss/preset-mini、@unocss/preset-wind、@unocss/preset-icons、@unocss/web-fonts | ✅ | 這些以及所有僅依賴規則/變體/預設樣式的社群插件,例如 unocss-preset-forms,皆可正常運作。 |
@unocss/preset-typography | ✅ | 由於此預設集會將規則集新增到您的預設樣式中,因此在使用此預設集時,您必須將 prose 類別新增到您的安全名單中,否則預設樣式將永遠不會被觸發。此預設集中的所有其他類別,例如 prose-pink ,可以設定為元件作用域。 |
@unocss/preset-rem-to-px | ✅ | 此預設集以及所有僅修改樣式輸出的類似預設集皆可正常運作。 |
@unocss/preset-attributify | - | 此預設集無法運作。請改用 unplugin-attributify-to-class Vite 插件 (attributifyToClass({ include: [/\.svelte$/]}) ),並將其放置在 Svelte Scoped Vite 插件之前。 |
@unocss/preset-tagify | - | 新增自定義提取器的預設集將無法運作。請建立一個預處理器,將 <text-red>Hi</text-red> 轉換為 <span class="text-red">Hi</span> ,然後建立一個 PR 將連結新增到這裡。 |
對於其他預設集,如果它們不依賴傳統的 class="..."
用法,您需要先將這些類別名稱預處理成 class="..."
屬性。如果它們新增了類似 typography 的 .prose
類別的預設集,則您需要將觸發預設集新增的類別放置到您的安全名單中。
轉換器支援
您的 CSS 檔案 (css|postcss|sass|scss|less|stylus|styl) 支援轉換器。要使用它們,請將轉換器新增到 vite.config.ts
中的 cssFileTransformers
選項。
import transformerDirectives from '@unocss/transformer-directives'
export default defineConfig({
plugins: [
UnoCSS({
cssFileTransformers: [transformerDirectives()],
}),
sveltekit(),
],
})
資訊
由於 Svelte Scoped 的運作方式,Svelte 元件中不支援轉換器。
作用域的工具類別釋放創造力
關於何時可能想要使用作用域樣式的一些建議:如果您在大型專案的開發過程中,每次使用像 .md:max-w-[50vw]
這樣的類別時,您知道它只會使用一次,但您卻會因為全域樣式表的大小越來越大而感到畏懼,那麼請嘗試使用這個套件。猶豫是否要使用您需要的類別會抑制創造力。當然,您可以在樣式區塊中使用 --at-apply: md:max-w-[50vw]
,但這很繁瑣,而且上下文中的樣式很有用。此外,如果您想在您的專案中包含各種圖示,您將會開始感受到將它們新增到全域樣式表的負擔。當每個元件都承擔自身樣式和圖示的重量時,您可以繼續擴展您的專案,而無需分析每個新增項目的成本效益。
授權條款
- MIT 授權條款 © 2022-PRESENT Jacob Bowdoin