为组件添加样式 — Salesforce LWC 样式系统完全指南

全面介绍 Lightning Web Components 的样式系统。涵盖 SLDS 1 vs SLDS 2(Salesforce Cosmos 主题)、SLDS Linter/Validator 工具、Lightning 基础组件样式优先级(变体/工具类/钩子)、组件级样式钩子(--slds-c-*)与全局样式钩子(--slds-g-*)、设计令牌迁移、从 SLDS 蓝图创建组件(5 步完整示例)、Shadow DOM CSS 封装与 :host 选择器、stylesheets 静态属性、自定义样式钩子、五大反模式及共享 CSS(@import)。...

📅 2026/7/19 ✍️ ponybai 🏷️ lwc, salesforce, frontend

为组件添加样式

为组件添加样式

为了让你的组件拥有 Lightning Experience 的外观和体验,请使用 Lightning Design System(SLDS)和 Lightning 基础组件。在 lightning 命名空间中使用基础组件时,你将自动获得 SLDS 样式。本章将全面介绍 LWC 样式系统。

SLDS 1 与 SLDS 2 对比

SLDS 1 与 SLDS 2 对比

SLDS 2 在 Spring '25 引入,默认主题为 Salesforce Cosmos。原始 SLDS 现称为 SLDS 1(默认主题:Lightning Blue)。

关键差异

特性SLDS 1SLDS 2
网站v1.lightningdesignsystem.comlightningdesignsystem.com
默认主题Lightning BlueSalesforce Cosmos
设计令牌支持(--lwc- 前缀)不支持
组件级样式钩子支持(--slds-c-*)暂不支持
全局样式钩子可用(颜色类)主要样式机制 + 语义 UI 颜色
组件蓝图相同(仅在 SLDS 1 站点上)

迁移工具

  • SLDS Linter(新):分析代码是否符合 SLDS 2 规则,支持跨仓库批量自动修复
  • SLDS Validator(VS Code):支持 SLDS 1 + 2,自动安装(Salesforce Extension Pack 的一部分)
重要:如果组件使用 --slds-c-* 组件级钩子 → 暂时留在 SLDS 1。用全局样式钩子替换设计令牌。

Lightning 基础组件 —— 样式优先级

Lightning 基础组件样式优先级

基础组件自动提供 SLDS 样式。按优先级从高到低自定义:

1. 设计变体(variant 属性)

<lightning-button variant="brand" label="Submit"></lightning-button>
<!-- brand, neutral, destructive, success, inverse... -->

2. SLDS 工具类

<lightning-button class="slds-m-left_medium" label="Cancel"></lightning-button>

3. 样式钩子(Styling Hooks)

:host {
  --slds-c-button-brand-color-background: var(--slds-g-orange-70);
}

自定义 CSS 类(正确做法)

/* 错误 —— 覆盖 SLDS 类 */
.slds-button { padding: 16px; }  /* 不要这样做! */

/* 正确 —— 创建自定义类,提供回退值 */
.my-button-padding {
  padding: var(--slds-g-spacing-4, var(--lwc-spacingMedium, 1rem));
}
<button class="slds-button my-button-padding">
关键原则:不要依赖基础组件的内部标记(可能变更);不要覆盖 .slds-* 类;不要使用 !important;不要重载选择器;使用 SLDS 2 全局钩子时始终提供 SLDS 1 回退值。

SLDS 样式钩子 —— 组件级别

SLDS 组件级别样式钩子

组件样式钩子(--slds-c-*)针对特定组件,仅在 SLDS 1 中可用

自定义品牌按钮颜色

<!-- myBaseButton.html -->
<lightning-button variant="brand" label="Submit"></lightning-button>

/* myBaseButton.css */
:host {
  --slds-c-button-brand-color-background: var(--slds-g-purple-30);
  --slds-c-button-brand-color-border: var(--slds-g-purple-30);
}

工作原理

  • 每个基础组件为其元素暴露 CSS 自定义属性
  • :host 上设置属性值来自定义外观
  • 更改仅影响该组件实例
  • 在 SLDS 1 站点每个蓝图上查看可用的样式钩子

支持限制

  • Toast:lightning/platformShowToastEvent 不支持 --slds-c-toast-*(改用 lightning/toast
  • Tooltip:lightning-helptext 不支持 --slds-c-tooltip-*
  • 链接和表单元素:不支持通过自定义属性进行样式设置

SLDS 全局样式钩子与设计令牌

SLDS 全局样式钩子与设计令牌

全局钩子(--slds-g-*)应用于所有组件,在 SLDS 1 和 SLDS 2 中均受支持。

全局间距钩子

/* 替换设计令牌 */
margin-right: var(--slds-g-spacing-2);
/* 以前是:var(--lwc-spacingSmall); */

设计令牌(SLDS 2 中已废弃)

/* 仅 SLDS 1 —— 使用 --lwc- 前缀 */
div { margin-right: var(--lwc-spacingSmall); }

/* 替换为全局钩子: */
div { margin-right: var(--slds-g-spacing-2); }
注意:令牌在编译时替换为实际值 —— 运行时不能使用 getPropertyValue()setPropertyValue()。只有标记为 Global Access 的令牌可用于 LWC。

自定义 Aura 令牌(--c- 前缀)

/* LWC CSS 中使用 --c- 前缀 */
color: var(--c-myBackgroundColor);
建议:优先使用全局样式钩子而非 Aura 令牌,以符合 WCAG 2.1 颜色对比度标准。

从 SLDS 蓝图创建组件

从 SLDS 蓝图创建组件

当没有对应的基础组件时,从最接近的 SLDS 蓝图构建。以 scoped notification 为例:

步骤 1:复制基础变体标记

<div class="slds-scoped-notification slds-media slds-media_center
    slds-scoped-notification_light" role="status">
  <!-- SLDS 标记 -->
</div>

步骤 2:用基础组件替换标准 HTML

<lightning-icon icon-name="utility:info"
    alternative-text="info" size="small"></lightning-icon>

步骤 3:将内容移至 JS,绑定到模板

@api message = "Your message here";
// 模板中:<p>{message}</p>

步骤 4:用 getter 创建主题变体

get scopedNotificationClass() {
  let cls = "slds-scoped-notification slds-media slds-media_center";
  if (this.theme === "light") cls += " slds-scoped-notification_light";
  if (this.theme === "dark") cls += " slds-scoped-notification_dark";
  return cls;
}
// 模板:<div class={scopedNotificationClass}>

步骤 5:绑定动态属性

get iconVariant() {
  return this.theme == 'dark' ? 'inverse' : null;
}
重要:蓝图的标记会成为你的代码 —— SLDS 更新不会自动应用。而基础组件会随 SLDS 更新自动升级。检查蓝图页面上是否有 "Lightning Component" 按钮——如果有,说明基础组件已存在。

CSS 样式表 —— Shadow DOM 封装

CSS 样式表与 Shadow DOM 封装

LWC 使用 Shadow DOM 实现 CSS 封装——组件样式表中的样式仅作用于该组件

Shadow DOM 规则

  • 父组件样式不渗透到子组件内部
  • 父组件可以将子组件作为单个元素设置样式:c-child { border: 2px solid red; }
  • 子组件通过 :host 选择器设置自身样式

:host 选择器

/* child.css */
:host {
  display: block;
  background: yellow;
}
:host(.active) {
  background-color: lightgreen;
}
/* 用法:<c-child class="active"> */

CSS 级联与优先级

  • Shadow DOM 中应用标准级联规则
  • 类选择器 → 更高优先级;相同优先级时后定义的胜出
  • 不支持 ID 选择器(运行时会转换为全局唯一值)

CSS 属性继承

  • 可继承属性(color、font)→ 穿透 Shadow DOM 边界
  • 不可继承属性(border)→ 使用初始值
  • CSS 自定义属性始终穿透 Shadow DOM

CSS 支持限制

  • 不支持 :host-context() 伪类
  • 不支持 ::part 伪元素
  • 不支持 ID 选择器
  • 公共属性不反映到 HTML 属性(使用 class 或 data-* 代替)
性能影响:作用域 CSS 会增加每个元素的作用域属性,每个选择器链都会被作用域化。更多 CSS = 更多带宽、解析和重计算时间。在大型应用中谨慎使用。

Stylesheets 属性与自定义样式钩子

Stylesheets 属性与自定义样式钩子

分配多个样式表 —— static stylesheets

import headerStyles from "./header-styles.css";
import buttonStyles from "./button-styles.css";

export default class Example extends LightningElement {
  static stylesheets = [headerStyles, buttonStyles];
}

加载顺序:myComponent.css(隐式,始终第一)→ header-styles.css → button-styles.css

子类合并

class Subclass extends Superclass {
  static stylesheets = [...super.stylesheets, subclassStylesheet];
}

创建你自己的样式钩子

:host {
  --important-color: red;
}
.important {
  color: var(--important-color);
}

带回调值的主题钩子

.light {
  background-color: var(--light-theme-bg, lightcyan);
  color: var(--light-theme-text, darkblue);
}
.dark {
  background-color: var(--dark-theme-bg, darkslategray);
  color: var(--dark-theme-text, ghostwhite);
}

自定义钩子的优势

  • 消费者在更高 DOM 级别设置值 —— 无需了解实现细节
  • CSS 自定义属性是继承的,自动穿透 Shadow DOM
  • 将钩子作为组件公共 API 的一部分进行文档化
  • 使主题化和品牌重塑变得简单
  • 使用 var() 提供回退值

反模式 —— 不要这样做

反模式 —— 不要这样做

1. 为基础组件的渲染 HTML 设置样式

/* 错误 —— 针对内部标记 */
.acme-box .slds-combobox__input { }
/* 内部类在任何版本中都可能发生变化!*/

2. 直接覆盖 SLDS 类

/* 错误 —— 覆盖 SLDS 选择器 */
.slds-button_brand { background-color: purple; }
.slds-button { padding: 16px; }

3. 使用精确字符串匹配的 querySelector

// 错误 —— 空白被压缩后匹配失败
document.querySelector(".slds-m-around_medium  highlight   yellow");
// 正确 —— 忽略空白的写法
document.querySelector(".slds-m-around_medium.highlight.yellow");
// 注意:空 class="" 和 style="" 在渲染时会被移除

4. 依赖 CSS 作用域令牌

/* 错误 —— 依赖内部属性 */
[c-cmp_cmp-host] { }
/* API 59.0+ 后令牌被混淆为 lwc-2s44vctlls4-host 格式
   使用 lwc:ref 代替 querySelector */

5. 重载选择器

/* 错误 —— 过于具体 / 使用 !important */
body.container > div.sidebar > article.card { }
.button { margin-bottom: 18px !important; }

支持的做法

设计变体(variant)→ SLDS 工具类(class)→ 样式钩子(CSS 自定义属性)→ 自定义 CSS 类配合 SLDS → :host 选择器 → CSS @import 共享样式

共享 CSS 样式规则

共享 CSS 样式规则

1. 创建 CSS 模块(无需 HTML 或 JS)

cssLibrary/
  ├── cssLibrary.css
  └── cssLibrary.js-meta.xml
/* cssLibrary.css */
h1 { font-size: xx-large; }
.warning { color: orange; }

2. 在组件 CSS 中导入

/* myComponent.css */
@import "c/cssLibrary";
/* 其他本地样式 */

关键规则

  • @import 格式:"namespace/moduleName"
  • LWC 不支持 @import 中的媒体查询
  • Lightning Locker:仅 c 和 lightning 命名空间
  • LWS:任何命名空间均可访问
  • 导入的样式与本地样式一样进行级联

优势

  • 所有组件外观一致
  • 共享样式的单一真相源 —— 一次更新,处处应用
  • 与 SLDS 样式钩子配合使用,实现集中式主题化

感谢阅读本指南。如需继续学习,请参阅下一章:组件组合。