Svelte 作用域
將每個 Svelte 組件的實用樣式生成的 CSS 直接放入 Svelte 組件的 <style>
塊,而不是全局 CSS 文件。
這個組件:
<div class="mb-1" />
被轉換為:
<div class="uno-ei382o" />
<style>
:global(.uno-ei382o) {
margin-bottom: 0.25rem;
}
</style>
何時使用
使用場景 | 描述 | 使用的包 | |
---|---|---|---|
小型應用 | ❌ | 使用 1 個全局 CSS 文件更方便。使用 Svelte/SvelteKit 的常規 Vite 插件。 | 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 作用域重寫了你的實用類名,你可以寫類名的位置是有限的:
支持的語法 | 示例 |
---|---|
Class 屬性 | <div class="mb-1" /> |
Class 指令 | <div class:mb-1={condition} /> |
Class 指令簡寫 | <div class:logo /> |
Class 屬性 | <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
添加插件
在 Vite 配置中添加 @unocss/svelte-scoped/vite
:
// vite.config.ts
import { defineConfig } from 'vite'
import { sveltekit } from '@sveltejs/kit/vite'
import UnoCSS from '@unocss/svelte-scoped/vite'
export default defineConfig({
plugins: [
UnoCSS({
// injectReset: '@unocss/reset/normalize.css', // 查看類型定義以瞭解所有包含的重置選項或如何傳入自己的選項
// ...其他 Svelte 作用域選項
}),
sveltekit(),
],
})
添加配置文件
按照下面的描述設置你的 uno.config.ts
文件。
全局樣式
雖然幾乎所有樣式都放置在單個組件中,但仍有一些必須放置在全局樣式表中:預置樣式、安全列表和可選的重置(如果使用 injectReset
選項)。
將 %unocss-svelte-scoped.global%
佔位符添加到你的 <head>
標籤中。在 Svelte 中,這是 index.html
。在 SvelteKit 中,這將在 app.html
的 %sveltekit.head%
之前:
<head>
<!-- ... -->
<title>使用 UnoCSS Svelte 作用域的 SvelteKit</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
替換為你的全局樣式。確保不要從另一個文件導入此轉換,例如在使用 @sveltejs/kit/hooks
中的 sequence 時。
在常規的 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
添加預處理器
在 Svelte 配置中添加 @unocss/svelte-scoped/preprocess
:
// svelte.config.js
import adapter from '@sveltejs/adapter-auto'
import { vitePreprocess } from '@sveltejs/kit/vite'
import UnoCSS from '@unocss/svelte-scoped/preprocess'
const config = {
preprocess: [
vitePreprocess(),
UnoCSS({
// ... 預處理器選項
}),
],
// 其他 Svelte 配置
}
開發環境中不要合併類名
在普通應用中使用 Svelte 作用域時,Vite 插件會自動檢測 dev
和 build
。在開發環境中,類名將保持不同並就地哈希,以便在瀏覽器開發者工具中輕鬆切換開關。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 編譯器自動剝離。
作用域實用類釋放創造力
關於何時使用作用域樣式的一些建議:如果你已經到了項目生命週期中的這樣一個階段,每次使用像 .md:max-w-[50vw]
這樣的類(你知道它只使用一次)時,你就會感到全局樣式表不斷增大而感到不適,那麼就試試這個包吧。對於需要使用的確切類名的猶豫會抑制創造力。當然,你可以在樣式塊中使用 --at-apply: md:max-w-[50vw]
,但這變得乏味,而且上下文中的樣式很有用。此外,如果你想在項目中包含大量圖標,你會開始感受到將它們添加到全局樣式表的負擔。當每個組件承擔自身的樣式和圖標的重量時,你可以繼續擴展項目,而無需分析每個新增內容的成本收益。
配置
將你的 UnoCSS 設置放在 uno.config.ts
文件中:
// uno.config.ts
import { defineConfig } from 'unocss'
export default defineConfig({
// ...UnoCSS 選項
})
由於普通 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 | - | 預設無法工作。相反,請在 Svelte 作用域 Vite 插件之前使用 unplugin-attributify-to-class Vite 插件(attributifyToClass({ include: [/\.svelte$/] }) ) |
@unocss/preset-tagify | - | 添加自定義提取器的預設將無法工作。創建一個預處理器將 <text-red>Hi</text-red> 轉換為 <span class="text-red">Hi</span> ,然後創建一個 PR 在此處添加鏈接。 |
對於其他預設,如果它們不依賴於傳統的 class="..."
使用方式,你需要先將這些類名預處理為 class="..."
屬性。如果它們添加了像排版的 .prose
類這樣的預設,那麼你需要將觸發預設添加的類放入安全列表中。
轉換器支持
轉換器支持你的 CSS 文件(css|postcss|sass|scss|less|stylus|styl)。要使用它們,請在 vite.config.ts
中的 cssFileTransformers
選項中添加轉換器:
// vite.config.ts
import transformerDirectives from '@unocss/transformer-directives'
export default defineConfig({
plugins: [
UnoCSS({
cssFileTransformers: [transformerDirectives()],
}),
sveltekit(),
],
})
INFO
由於 Svelte 作用域的工作方式,轉換器不支持 Svelte 組件。
許可證
- MIT 許可證 © 2022-現在 Jacob Bowdoin