全局样式应统一放入 src/app.css,并在布局文件中用 <style global> 导入;:global() 仅穿透选择器部分,不可嵌套;富文本和 slot 样式需配合 wrapper 或显式穿透;重复使用的全局规则应抽离为外部 CSS 文件。

全局样式该放哪,而不是怎么放
别在某个组件的 <style> 里塞 :global(body) 或重置规则——它会生效,但热更新时可能丢样式、多处定义时覆盖不可控、复用时得复制粘贴。真正该全局的样式(字体、间距、主题变量、CSS Reset),统一放进 src/app.css,然后在 src/routes/__layout.svelte(SvelteKit v1)或 src/routes/+layout.svelte(v2)顶部加:
<style global><br> @import url('/app.css');<br></style>这样既受 Svelte 生命周期管理,又支持 PostCSS、HMR 正常、构建时可提取。
:global() 不是“全局开关”,而是“选择器穿透器”
:global() 只放行括号内的选择器部分,且不能嵌套。写错就白写:
- •
:global(.a .b) → 整个选择器被放行,浏览器原生解析,有效- •
:global(.a) .b → .a 全局匹配,.b 仍被局部化,大概率不生效- •
div :global(strong) → 只影响本组件内 <div> 下的 <strong>,安全可控- •
:global(.third-party) button → 想改第三方组件按钮?确保该第三方组件真渲染了带 .third-party 的容器,且没用 $$props.class 却没绑定到根节点富文本、{@html} 和 slot 里的样式怎么管
{@html} 插入的内容不会被加作用域属性,所以 .content h1 这种写法无效。可靠做法是:
- • 用 wrapper 包一层:
<div class="rich-content">{@html unsafeHtml}</div>
- • 在组件
<style> 中写:.rich-content :global(h1) { font-size: 2.4rem; }
- • 别写
:global(.rich-content h1) —— .rich-content 是局部类,会被哈希化,:global() 不处理它- •
<slot> 内容默认属于父组件作用域,子组件无法用普通选择器控制;要么父组件透传 class,要么用 :global() 显式穿透,但后者要小心异步渲染时机什么时候该放弃 :global(),直接上外部 CSS 文件
如果发现你在三个以上组件里重复写 :global(.btn)、:global(.card),说明这些规则本就不该分散在组件中。直接抽成 src/lib/styles/components.css,再通过 <style global> 引入布局文件,或者干脆在 main.js 里 import '$lib/styles/components.css'(仅限极简项目,且确认你接受 HMR 失效风险)。真正难的不是让样式“生效”,而是让变更、复用、调试都可预期——:global() 是手术刀,不是胶水。


















