你正在查看 Lit 的旧版本文档。点击 这里查看最新版本。

样式

你的组件模板被渲染到其 shadow root 中。你添加到组件的样式会自动_作用域限定_到 shadow root,仅影响组件 shadow root 中的元素。

Shadow DOM 为样式提供了强大的封装。如果 Lit 不使用 Shadow DOM,你必须非常小心,不要意外地设置组件外部元素(组件的祖先或子元素)的样式。这可能需要编写冗长、难以使用的类名。通过使用 Shadow DOM,Lit 确保你编写的任何选择器仅应用于 Lit 组件 shadow root 中的元素。

你可以在静态 styles 类字段中使用标签模板字面量 css 函数定义作用域限定的样式。以这种方式定义样式可获得最佳性能:

你添加到组件的样式使用 Shadow DOM 进行_作用域限定_。快速概览请参阅 Shadow DOM

静态 styles 类字段的值可以是:

  • 单个标签模板字面量。

    static styles = css`...`;
  • 标签模板字面量的数组。

    static styles = [ css`...`, css`...`];

静态 styles 类字段_几乎总是_为组件添加样式的最佳方式,但有些用例你无法通过这种方式处理——例如,按实例自定义样式。有关添加样式的替代方式,请参阅在模板中定义作用域限定的样式

静态样式适用于组件的所有实例。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 来"回传信息"。

使用标签模板字面量的数组,组件可以从超类继承样式,并添加自己的样式:

你也可以在 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 样式。

你添加到组件的样式可以影响:

Lit 模板默认渲染到 shadow 树中。限定在元素 shadow 树中的样式不会影响主文档或其他 shadow 树。同样,除了可继承的 CSS 属性之外,文档级别的样式不会影响 shadow 树的内容。

当你使用标准 CSS 选择器时,它们只匹配你组件 shadow 树中的元素。这意味着你通常可以使用非常简单的选择器,而不必担心它们会意外地设置页面其他部分的样式;例如:input*#my-element

你可以使用特殊的 :host 选择器来设置组件本身的样式。(拥有或"托管"shadow 树的元素称为_宿主元素_。)

要为宿主元素创建默认样式,使用 :host CSS 伪类和 :host() CSS 伪类函数。

  • :host 选择宿主元素。
  • :host(selector) 选择宿主元素,但仅在宿主元素匹配 selector 时。

请注意,宿主元素也可以受到来自 shadow 树外部样式的影响,因此你应将在 :host:host() 规则中设置的样式视为可被用户覆盖的_默认样式_。例如:

my-element {
display: inline-block;
}

你的组件可能接受子元素(就像 <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 模板中定义样式。有两种在模板中添加作用域限定样式的方式:

这些技术各有其优缺点。

通常,样式放在静态 styles 类字段中;然而,元素的静态 styles每个类计算一次的。有时,你可能需要按实例自定义样式。为此,我们建议使用 CSS 属性来创建可主题化元素。或者,你也可以在 Lit 模板中包含 <style> 元素。这些会按实例更新。

render() {
return html`
<style>
/* 按实例更新 */
</style>
<div>模板内容</div>
`;
}

ShadyCSS polyfill 在按实例样式方面的限制。 ShadyCSS polyfill 不支持按实例样式。详见 ShadyCSS 限制

在 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 是已知的,这没有问题,但在构建可复用元素时应避免使用外部样式表。

使样式动态化的一种方式是在模板中的 classstyle 属性中添加表达式。

Lit 提供了两个指令 classMapstyleMap,以方便在 HTML 模板中应用类和样式。

有关这些及其他指令的更多信息,请参阅内置指令文档。

要使用 styleMap 和/或 classMap

  1. 导入 classMap 和/或 styleMap

    import { classMap } from 'lit/directives/class-map.js';
    import { styleMap } from 'lit/directives/style-map.js';
  2. 在你的元素模板中使用 classMap 和/或 styleMap

详见 classMapstyleMap

通过同时使用 CSS 继承CSS 变量及自定义属性,可以轻松创建可主题化的元素。通过应用 CSS 选择器来自定义 CSS 自定义属性,基于树和按实例的主题化可以轻松实现。以下是一个示例:

CSS 继承允许父元素和宿主元素将某些 CSS 属性传播给它们的后代。

并非所有 CSS 属性都会继承。可继承的 CSS 属性包括:

  • color
  • font-family 和其他 font-* 属性
  • 所有 CSS 自定义属性(--*

详见 MDN 上的 CSS 继承

你可以使用 CSS 继承在祖先元素上设置样式,这些样式会被其后代继承:

<style>
html {
color: green;
}
</style>
<my-element>
#shadow-root
将会是绿色
</my-element>

所有 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 自定义属性