样式
你的组件模板被渲染到其 shadow root 中。你添加到组件的样式会自动_作用域限定_到 shadow root,仅影响组件 shadow root 中的元素。
Shadow DOM 为样式提供了强大的封装。如果 Lit 不使用 Shadow DOM,你必须非常小心,不要意外地设置组件外部元素(组件的祖先或子元素)的样式。这可能需要编写冗长、难以使用的类名。通过使用 Shadow DOM,Lit 确保你编写的任何选择器仅应用于 Lit 组件 shadow root 中的元素。
为组件添加样式
Permalink to "为组件添加样式"你可以在静态 styles 类字段中使用标签模板字面量 css 函数定义作用域限定的样式。以这种方式定义样式可获得最佳性能:
你添加到组件的样式使用 Shadow DOM 进行_作用域限定_。快速概览请参阅 Shadow DOM。
静态 styles 类字段的值可以是:
单个标签模板字面量。
static styles = css`...`;标签模板字面量的数组。
static styles = [ css`...`, css`...`];
静态 styles 类字段_几乎总是_为组件添加样式的最佳方式,但有些用例你无法通过这种方式处理——例如,按实例自定义样式。有关添加样式的替代方式,请参阅在模板中定义作用域限定的样式。
在静态样式中使用表达式
Permalink to "在静态样式中使用表达式"静态样式适用于组件的所有实例。CSS 中的任何表达式只计算一次,然后为所有实例重用。
对于基于树或按实例的样式自定义,使用 CSS 自定义属性来允许元素被主题化。
为防止 Lit 组件执行可能的恶意代码,css 标签只允许嵌套的表达式本身是 css 标签字符串或数字。
const mainColor = css`red`;...static styles = css` div { color: ${mainColor} }`; 此限制的存在是为了保护应用程序免受安全漏洞的影响,即恶意样式甚至恶意代码可能从不受信任的来源(如 URL 参数或数据库值)注入。
如果你必须在 css 字面量中使用本身不是 css 字面量的表达式,并且你确信该表达式来自完全受信任的来源(如你自己代码中定义的常量),则可以使用 unsafeCSS 函数包装表达式:
const mainColor = 'red';...static styles = css` div { color: ${unsafeCSS(mainColor)} }`; 仅对受信任的输入使用 unsafeCSS 标签。 注入未清理的 CSS 存在安全风险。例如,恶意 CSS 可以通过添加指向第三方服务器的图片 URL 来"回传信息"。
从超类继承样式
Permalink to "从超类继承样式"使用标签模板字面量的数组,组件可以从超类继承样式,并添加自己的样式:
你也可以在 JavaScript 中使用 super.styles 来引用超类的 styles 属性。如果你使用 TypeScript,我们建议避免使用 super.styles,因为编译器并不总是能正确转换它。如示例所示显式引用超类可以避免此问题。
在编写打算被 TypeScript 子类化的组件时,static styles 字段应显式类型化为 CSSResultGroup,以允许用户使用数组来重写 styles 的灵活性:
// 防止 TypeScript 将 `styles` 的类型收窄为 `CSSResult`// 以便子类可以赋值如 `[SuperElement.styles, css`...`]`static styles: CSSResultGroup = css`...`; 你可以通过创建一个导出标签样式的模块在组件之间共享样式:
export const buttonStyles = css` .blue-button { color: white; background-color: blue; } .blue-button:disabled { background-color: grey; }`; 然后你的元素可以导入这些样式并将它们添加到其静态 styles 类字段中:
import { buttonStyles } from './button-styles.js';
class MyElement extends LitElement { static styles = [ buttonStyles, css` :host { display: block; border: 1px solid black; }` ];} 在样式中使用 Unicode 转义序列
Permalink to "在样式中使用 Unicode 转义序列"CSS 的 Unicode 转义序列是一个反斜杠后跟四位或六位十六进制数:例如,\2022 代表一个项目符号字符。这与 JavaScript 已弃用的_八进制_转义序列格式类似,因此在 css 标签模板字面量中使用这些序列会导致错误。
有两种变通方法可以在样式中添加 Unicode 转义:
- 添加第二个反斜杠(例如,
\\2022)。 - 使用以
\u开头的 JavaScript 转义序列(例如,•)。
static styles = css` div::before { content: '•'; } Shadow DOM 样式概览
Permalink to "Shadow DOM 样式概览"本节简要介绍 Shadow DOM 样式。
你添加到组件的样式可以影响:
设置 Shadow 树的样式
Permalink to "设置 Shadow 树的样式"Lit 模板默认渲染到 shadow 树中。限定在元素 shadow 树中的样式不会影响主文档或其他 shadow 树。同样,除了可继承的 CSS 属性之外,文档级别的样式不会影响 shadow 树的内容。
当你使用标准 CSS 选择器时,它们只匹配你组件 shadow 树中的元素。这意味着你通常可以使用非常简单的选择器,而不必担心它们会意外地设置页面其他部分的样式;例如:input、* 或 #my-element。
设置组件本身的样式
Permalink to "设置组件本身的样式"你可以使用特殊的 :host 选择器来设置组件本身的样式。(拥有或"托管"shadow 树的元素称为_宿主元素_。)
要为宿主元素创建默认样式,使用 :host CSS 伪类和 :host() CSS 伪类函数。
:host选择宿主元素。:host(selector)选择宿主元素,但仅在宿主元素匹配 selector 时。
请注意,宿主元素也可以受到来自 shadow 树外部样式的影响,因此你应将在 :host 和 :host() 规则中设置的样式视为可被用户覆盖的_默认样式_。例如:
my-element { display: inline-block;} 设置组件子元素的样式
Permalink to "设置组件子元素的样式"你的组件可能接受子元素(就像 <ul> 元素可以有 <li> 子元素一样)。要渲染子元素,你的模板需要包含一个或多个 <slot> 元素,如使用 slot 元素渲染子元素中所述。
<slot> 元素作为 shadow 树中的占位符,宿主元素的子元素在此显示。
使用 ::slotted() CSS 伪元素来选择通过 <slot> 包含在模板中的子元素。
::slotted(*)匹配所有 slotted 元素。::slotted(p)匹配 slotted 段落。p ::slotted(*)匹配<slot>是段落元素后代的 slotted 元素。
请注意,只有直接的 slotted 子元素可以通过 ::slotted() 设置样式。
<my-element> <div>可以用 ::slotted() 设置样式</div></my-element>
<my-element> <div><p>不能用 ::slotted() 设置样式</p></div></my-element> 此外,子元素可以从 shadow 树外部设置样式,因此你应该将 ::slotted() 样式视为可被覆盖的默认样式。
my-element > div { /* 外部样式针对 slotted 子元素可以覆盖 ::slotted() 样式 */} ShadyCSS polyfill 在 slotted 内容方面的限制。 有关如何以 polyfill 友好方式使用 ::slotted() 语法的详细信息,请参阅 ShadyCSS 限制。
在模板中定义作用域限定的样式
Permalink to "在模板中定义作用域限定的样式"我们建议使用静态 styles 类字段以获得最佳性能。然而,有时你可能想在 Lit 模板中定义样式。有两种在模板中添加作用域限定样式的方式:
- 使用
<style>元素添加样式。 - 使用外部样式表添加样式(不推荐)。
这些技术各有其优缺点。
在 style 元素中
Permalink to "在 style 元素中"通常,样式放在静态 styles 类字段中;然而,元素的静态 styles 是每个类计算一次的。有时,你可能需要按实例自定义样式。为此,我们建议使用 CSS 属性来创建可主题化元素。或者,你也可以在 Lit 模板中包含 <style> 元素。这些会按实例更新。
render() { return html` <style> /* 按实例更新 */ </style> <div>模板内容</div> `;} ShadyCSS polyfill 在按实例样式方面的限制。 ShadyCSS polyfill 不支持按实例样式。详见 ShadyCSS 限制。
表达式和 style 元素
Permalink to "表达式和 style 元素"在 style 元素内部使用表达式有一些重要的限制和性能问题。
render() { return html` <style> :host { /* 警告:此方法有限制和性能问题! */ color: ${myColor} } </style> <div>模板内容</div> `;} ShadyCSS polyfill 在表达式方面的限制。 由于 ShadyCSS polyfill 的限制,<style> 元素中的表达式不会按实例更新。此外,使用 ShadyCSS polyfill 时,<style> 节点不能作为表达式值传递。详见 ShadyCSS 限制。
在 <style> 元素内部执行表达式效率极低。当 <style> 元素内部的任何文本发生变化时,浏览器必须重新解析整个 <style> 元素,导致不必要的工作。
为了减轻这一开销,将需要按实例评估的样式与不需要的样式分开。
static styles = css`/* ... */`; render() { const redStyle = html`<style> :host { color: red; } </style>`; return html`${this.red ? redStyle : ''}`
导入外部样式表(不推荐)
Permalink to "导入外部样式表(不推荐)"虽然你可以通过 <link> 在模板中包含外部样式表,但我们不推荐这种方式。相反,样式应放在静态 styles 类字段中。
外部样式表注意事项。
- ShadyCSS polyfill 不支持外部样式表。
- 外部样式在加载时可能导致无样式内容闪烁(FOUC)。
href属性中的 URL 是相对于主文档的。如果你在构建一个应用且资源 URL 是已知的,这没有问题,但在构建可复用元素时应避免使用外部样式表。
动态类和样式
Permalink to "动态类和样式"使样式动态化的一种方式是在模板中的 class 或 style 属性中添加表达式。
Lit 提供了两个指令 classMap 和 styleMap,以方便在 HTML 模板中应用类和样式。
有关这些及其他指令的更多信息,请参阅内置指令文档。
要使用 styleMap 和/或 classMap:
导入
classMap和/或styleMap:import { classMap } from 'lit/directives/class-map.js';import { styleMap } from 'lit/directives/style-map.js';在你的元素模板中使用
classMap和/或styleMap:
通过同时使用 CSS 继承和 CSS 变量及自定义属性,可以轻松创建可主题化的元素。通过应用 CSS 选择器来自定义 CSS 自定义属性,基于树和按实例的主题化可以轻松实现。以下是一个示例:
CSS 继承
Permalink to "CSS 继承"CSS 继承允许父元素和宿主元素将某些 CSS 属性传播给它们的后代。
并非所有 CSS 属性都会继承。可继承的 CSS 属性包括:
colorfont-family和其他font-*属性- 所有 CSS 自定义属性(
--*)
详见 MDN 上的 CSS 继承。
你可以使用 CSS 继承在祖先元素上设置样式,这些样式会被其后代继承:
<style>html { color: green;}</style><my-element> #shadow-root 将会是绿色</my-element> CSS 自定义属性
Permalink to "CSS 自定义属性"所有 CSS 自定义属性(--custom-property-name)都会继承。你可以利用这一点使组件的样式可从外部配置。
以下组件将其背景色设置为一个 CSS 变量。该 CSS 变量使用 --my-background 的值(如果它已被匹配 DOM 树中祖先的选择器设置),否则默认为 yellow:
class MyElement extends LitElement { static styles = css` :host { background-color: var(--my-background, yellow); } `; render() { return html`<p>Hello world</p>`; }} 该组件的用户可以使用 my-element 标签作为 CSS 选择器来设置 --my-background 的值:
<style> my-element { --my-background: rgb(67, 156, 144); }</style><my-element></my-element> --my-background 可以按 my-element 的实例进行配置:
<style> my-element { --my-background: rgb(67, 156, 144); } my-element.stuff { --my-background: #111111; }</style><my-element></my-element><my-element class="stuff"></my-element> 详见 MDN 上的 CSS 自定义属性。