mcpField
S
svelte-styling

svelte-styling

github.com/full-stack-skills设计与 UI443 次安装4 周前更新
代码仓库

关于 svelte-styling

svelte-styling 是面向 Svelte 5 组件样式的参考技能,讲解作用域与全局 CSS、自定义属性、class 处理、style: 指令和关键帧,并提供示例与问题排查方法。

主要功能

  1. 01作用域与全局 CSS 模式
  2. 02CSS 自定义属性用法
  3. 03class 属性与指令
  4. 04style: 指令行为
  5. 05作用域与全局关键帧
  6. 06样式问题排查

适用场景

  1. 01排查组件样式未生效的原因
  2. 02在组件间传递 CSS 值
  3. 03为注入的 HTML 应用全局样式
  4. 04解决关键帧或 Tailwind 类问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/full-stack-skills/svelte-skills --skill svelte-styling

安装后在 Claude Code 中输入/svelte-styling确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

agents/
openai.yaml
examples/
global-patterns.md
nested-style.md
README.md
scoped-keyframes.md
scoped-styles.md
style-directive.md
tailwind.md
references/
class-directive.md
css-custom-properties.md
global-reference.md
README.md
scoped-deep.md
scoped-keyframes.md
specificity.md
style-directive.md

详细介绍

Svelte Styling Reference (Svelte 5)

本技能覆盖 Svelte 组件的样式系统,包括作用域样式、全局样式、CSS 自定义属性、class 处理、style: 指令、嵌套 <style> 和 scoped keyframes。

When to use this skill

当用户需要编写 Svelte 组件的样式、处理样式隔离、CSS 变量传递、style: 指令、动画 keyframes、或理解 Svelte 编译器如何处理样式时使用本技能。

Critical: Scoped Styles

<style> 块中的 CSS 默认作用域化——仅影响当前组件内的元素:

<style>
  p { color: burlywood; }
  .container { padding: 1em; }
</style>

编译时 Svelte 为作用域内的选择器自动添加哈希类(如 svelte-123xyz)。

特异性(Specificity)

Scoped 选择器额外增加 +0-1-0 特异性(来自作用域类),可能覆盖全局相同选择器:

/* 全局 */
p { color: blue; }

/* 组件内(scoped,优先级更高) */
p { color: red; }
:where() 包装

当同一作用域类需要出现在选择器中多次时,只有第一次实际贡献特异性;后续出现被包裹在 :where(.svelte-xyz123) 中,贡献零特异性。这避免了深层选择器(如 .a .b .c)的特异性爆炸。

Scoped Keyframes

@keyframes 名称也会自动作用域化,同一组件内 animation: name 引用会被重写以匹配:

<style>
  @keyframes bounce {
    0%, 100% { transform: translateY(0); }
    50% { transform: translateY(-20px); }
  }
  .animated { animation: bounce 1s; }  /* 编译为 bounce-svelte-abc123 */
</style>
何时样式不生效
  • 元素由子组件渲染(scoped 不会穿透组件边界)
  • {@html} 内容(没有作用域类)
  • 类名是动态/程序化添加的,且选择器未使用 :global(...)
  • 选择器不匹配模板中实际存在的元素
  • 在 style="" 属性或 JS 中使用 scoped keyframe 名称(用 -global- 解决)

Critical: Global Styles

:global(...) 单选择器
<style>
  :global(body) { margin: 0; }          /* 全局 body */
  div :global(strong) { color: goldenrod; } /* 嵌套全局 */
  p:global(.big.red) { font-weight: bold; } /* 带条件 */
</style>
  • :global(selector) — 整个选择器退出作用域。
  • parent :global(child) — 父级保留作用域,子级不保留(最常用形式)。
  • tag:global(.class.class) — 元素仍带作用域类,但触发类不需出现在模板中(适用于第三方库运行时添加的类)。
:global { ... } 块(多选择器)
<style>
  :global {
    p { margin: 1em; }
    .theme-dark { --bg: #111; }
  }

  .parent :global {
    .foo .bar { color: red; }  /* .parent 是 scoped,.foo .bar 是全局 */
  }
</style>

:global 块中的选择器按原样发出,不降低特异性——只有 .foo .bar 自身的特异性。

全局 Keyframes

在 keyframe 名称前加 -global-:

<style>
  @keyframes -global-my-animation-name {
    0% { opacity: 0; }
    100% { opacity: 1; }
  }
</style>

编译后 -global- 前缀被移除,成为 my-animation-name,可被其他组件、<style> 属性、JS 引用。

编译器只重写同一 <style> 块内的 animation 引用。style="..." 属性、{@html} 内容、JS、style:color 指令中的 keyframe 名称不会被重写——这些地方需要 -global- 名称。

Critical: CSS Custom Properties

传入自定义属性
<Slider bind:value --track-color="black" --thumb-color="rgb(255 0 0)" />

编译时 Svelte 包裹一层 svelte-css-wrapper(或 SVG 中的 <g>)承载内联 style:

<svelte-css-wrapper style="display: contents; --track-color: black; --thumb-color: rgb(255 0 0)">
  <Slider ... />
</svelte-css-wrapper>

包装元素有 display: contents 但仍会出现在 > 子选择器匹配中——必要时改用后代选择器。

组件内读取
<style>
  .track { background: var(--track-color, #aaa); }
  .thumb { background: var(--thumb-color, blue); }
</style>
CSS 自定义属性可级联

无需直接传值,只要父元素定义了 CSS 变量,子组件即可读取:

/* 全局 */
:root { --primary: #ff3e00; }

Critical: style: Directive

style: 指令是 style="..." 属性的简写,每个属性一个指令。

<div style:color="red">A</div>           
<div style:color={myColor}>B</div>        
<div style:color>C</div>                  
多个样式
<div style:color style:width="12rem" style:--columns={columns}>...</div>
CSS 自定义属性

style:--var 设置 CSS 变量:

<div style:--columns={columns} style:--gap="1rem">...</div>
!important 修饰符

style:color|important="red" → 编译为 style="color: red !important"。

优先级

style: 指令胜出于同元素上的 style="" 属性——即使 style="" 中使用了 !important:

<div style:color="red" style="color: blue !important">This will be red</div>
数值单位

数字不会自动加单位:

<div style:width={10}>...</div>          
<div style:width="{10}px">...</div>      

Critical: class Attribute

Svelte 5.16+ 的 class 属性支持对象和数组(用 clsx 处理)。

对象形式
<div class={{ cool: isCool, large: isLarge }}>...</div>
数组形式
<div class={[faded && 'saturate-0 opacity-50', large && 'scale-200']}>...</div>
混合
<Button class={['btn', props.class]} />
类型安全
<script lang="ts">
  import type { ClassValue } from 'svelte/elements';
  let { class: cls }: { class: ClassValue } = $props();
</script>
<div class={['original', cls]}>...</div>
5.16 之前的 falsy 行为

历史原因:class={false} 会被序列化为 class="false",但 class={undefined} / class={null} 会让属性消失。Svelte 未来版本会让所有 falsy 值省略 class。

Critical: class: Directive(已不推荐)

Svelte 5.16+ 推荐用 class={} 对象/数组形式替代 class: 指令:


<div class={{ cool, lame: !cool }}></div>
<div class:cool class:lame={!cool}></div>

Critical: Nested <style> Elements

一个组件只能有一个顶层 <style> 块,但可以嵌套 <style> 标签(不经过作用域处理,直接插入 DOM):

<div>
  <style>
    /* 原生 style 标签,无作用域,规则全局生效 */
    div { color: red; }
  </style>
</div>

使用场景:

  • 主题 token 的 {#if} 切换(变量随切换增删)
  • 第三方组件自带的 CSS
  • 动态主题变量
  • 邮件 / SVG 模板

注意: 嵌套 <style> 中的 @keyframes 名称是全局的,不会被重写。多个组件中同名 keyframe 会冲突。

Critical: {@html} and Scoped Styles

{@html} 注入的内容没有作用域类,scoped 选择器不会匹配。用 :global(...) 解决:

<style>
  :global(.highlight) { color: red; }
</style>

警告: 永远不要用 :global(...) 来样式化你无法完全控制的 HTML——XSS 风险。

Quick Fixes

问题解决方案
样式不生效检查 scoped 哈希是否覆盖;用 :global
组件样式传不进去用 CSS 自定义属性(--var)而非 scoped 选择器
父组件不能覆盖子组件的样式用 --var 传值,或用 :global(不推荐)
全局样式被组件 scoped 覆盖scoped 提升 +0-1-0 特异性;用 :where() 或增加全局选择器特异性
Tailwind 类不生效JIT 找不到动态拼接的类名;用 class={[...]} 数组映射或 safelist
动态 style="animation: x" 找不到 keyframekeyframe 是 scoped 的;用 @keyframes -global-x
style: 不生效检查表达式语法;数值需要单位
> .child 不匹配父传 --var 时包了 svelte-css-wrapper;改用后代选择器
slot 内容样式不到用 ::slotted(selector) 从父组件样式化

注意事项

  1. Scoped 样式隔离 — 通过哈希类实现,不会真正“隐藏”样式(查看页面源码即可看到)
  2. Scoped 选择器 +0-1-0 特异性 — 总是高于形状相同的全局选择器
  3. @keyframes 名称也会被 scoped — style="animation: name" 找不到 scoped 名称(使用 -global-)
  4. {@html} 内容不受 scoped 影响 — 插入的 HTML 没有作用域类
  5. CSS 变量不需要 scoped — var(--custom) 天然跨越作用域和级联
  6. svelte-css-wrapper 元素 — 父级传入 --var 时会插入,破坏 > 子选择器
  7. :global 不会降低特异性 — 它会退出作用域,但不会退出 specificity
  8. 嵌套 <style> 是全局的 — 不经过 Svelte 编译器处理,而是原样插入 DOM
  9. 编译器只会在同一个 <style> 块内重写 animation — 其他地方需要使用 -global-
  10. <style> 属性和 JS 中的 scoped keyframe 名称 — 不会被重写

常见问题

问:如何让样式影响子组件内部? 答:有两种方式:① 父组件传入 CSS 自定义属性(推荐);② 使用 :global(会影响全局,破坏封装)。

问:Svelte 编译后 class 名称是什么? 答:形如 svelte-123xyz 的哈希,组件级唯一。

问:scoped 样式会优先于全局样式吗? 答:是。scoped 会提升 +0-1-0 特异性。形状相同的全局 p 会输给 scoped p。

问:什么时候该用 :global 而不是 CSS 变量? 答:当你必须控制选择器本身(位置、选择什么),而不是传入值时,使用 :global。大多数“传值”场景使用 CSS 变量更好。

问:为什么 class:[...] 数组中的 falsy 值不会变成字符串? 答:Svelte 会按照 clsx 规则过滤掉 false/null/undefined/""/0。只有 class={false} 才会变成 class="false"(这是历史行为,5.16+ 已更改数组形式)。

问:为什么嵌套 <style> 中的规则是全局的? 答:嵌套 <style> 不会经过 Svelte 编译器的 scoping 处理,而是原样插入 DOM。浏览器会像处理普通 <style> 一样解析它。

问:可以从外部触发 scoped keyframe 吗? 答:不行。scoped keyframe 名称在编译时会被改写,外部无法用裸名称引用。使用 @keyframes -global-name。

问:同时使用 style: 指令和 style="..." 属性会怎样? 答:style: 优先,即使 style="" 使用了 !important 也是如此。这是 Svelte 5 的设计。

问:可以使用 bg-${color}-500 这样的模板字符串创建动态 Tailwind 类吗? 答:无法可靠地工作——JIT 看不到完整类名。请使用查找表({ red: 'bg-red-500', ... })或 safelist。

示例

FileDescription
examples/README.md入口文件,列出所有示例文件及其说明
examples/scoped-styles.mdScoped 样式、特异性、:where() 技巧、样式不生效的情况、编译输出、svelte-css-wrapper
examples/scoped-keyframes.md@keyframes 作用域、-global- 前缀、共享动画、从 JS 触发、prefers-reduced-motion
examples/global-patterns.md:global(...) 单个、复合、嵌套、块级用法,以及何时使用它而不是 CSS 自定义属性
examples/style-directive.mdstyle:property、style:--var、|important、表达式、多个样式、值强制转换
examples/nested-style.md模板中的原始 <style> 标签、{#if}/{#each} 样式片段、生命周期、注意事项
examples/tailwind.mdTailwind CSS、任意值、使用自定义属性动态设置主题、safelist、twMerge

参考

FileDescription
references/README.md入口文件,列出所有参考文件及其说明
references/scoped-deep.md深入介绍作用域机制、哈希生成、:where() 包装、嵌套 <style>、边缘情况
references/scoped-keyframes.mdScoped keyframes、-global- 前缀、跨组件共享、重写规则
references/global-reference.md:global(...) 单个、嵌套、块级、复合用法的完整参考,包含级联和转换示例
references/specificity.md特异性交互、:where() / :is() / :not()、覆盖策略、级联顺序
references/style-directive.md所有 style: 形式、style:--var 序列化、|important、值强制转换、优先级
references/css-custom-properties.mdCSS 自定义属性:传递、读取、级联、动态更新
references/class-directive.mdclass 与 class: 指令、ClassValue 类型、clsx 模式

评论

支持 Markdown