样式
你的组件的模板会被渲染到其 shadow root 中。你添加到组件中的样式会自动被 限定作用域 到 shadow root,并且只影响组件 shadow root 中的元素。
Shadow DOM 为样式提供了强大的封装。如果 Lit 不使用 Shadow DOM,你就必须非常小心,不要意外地为组件外部的元素(无论是组件的祖先还是子元素)添加样式。这可能需要编写冗长、难以使用的类名。通过使用 Shadow DOM,Lit 确保你编写的任何选择器只应用于 Lit 组件的 shadow root 中的元素。
为组件添加样式
Permalink to "为组件添加样式"你可以使用标记模板字面量 css
函数在静态 styles
类字段中定义限定作用域的样式。以这种方式定义样式可以获得最佳性能:
你添加到组件中的样式使用 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 "从超类继承样式"使用标记模板字面量数组,组件可以继承超类的样式,并添加自己的样式:
你也可以使用 super.styles
在 JavaScript 中引用超类的样式属性。如果你使用 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 转义序列(例如,\u2022
)。
static styles = css`
div::before {
content: '\u2022';
}
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 树的元素称为_宿主元素_。)
要为宿主元素创建默认样式,请使用 CSS 伪类 :host
和 CSS 伪类函数 :host()
。
:host
选择宿主元素。:host(selector)
选择宿主元素,但仅当宿主元素匹配_selector_时。
请注意,宿主元素也可能受到 shadow 树外部样式的影响,因此你应该将 :host
和 :host()
规则中设置的样式视为可以被用户覆盖的_默认样式_。例如:
my-element {
display: inline-block;
}
为组件的子元素添加样式
Permalink to "为组件的子元素添加样式"你的组件可能接受子元素(就像 <ul>
元素可以有 <li>
子元素一样)。要渲染子元素,你的模板需要包含一个或多个 <slot>
元素,如使用 slot 元素渲染子元素中所述。
<slot>
元素在 shadow 树中充当占位符,用于显示宿主元素的子元素。
使用 CSS 伪元素 ::slotted()
来选择通过 <slot>
包含在模板中的子元素。
::slotted(*)
匹配所有插槽元素。::slotted(p)
匹配插槽的段落。p ::slotted(*)
匹配<slot>
是段落元素的后代的插槽元素。
请注意,只有直接插槽的子元素可以使用 ::slotted()
添加样式。
<my-element>
<div>可以使用 ::slotted() 添加样式</div>
</my-element>
<my-element>
<div><p>不能使用 ::slotted() 添加样式</p></div>
</my-element>
此外,子元素可以从 shadow 树外部添加样式,因此你应该将 ::slotted()
样式视为可以被覆盖的默认样式。
my-element > div {
/* 针对插槽子元素的外部样式可以覆盖 ::slotted() 样式 */
}
**ShadyCSS polyfill 在插槽内容方面的限制。**有关如何以兼容 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 中不会每个实例更新。此外,使用 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
:
有关更多信息,请参见 classMap 和 styleMap。
通过一起使用 CSS 继承 和 CSS 变量和自定义属性,可以轻松创建可主题化的元素。通过应用 CSS 选择器来自定义 CSS 自定义属性,基于树的和每个实例的主题化都很容易应用。这里有一个例子:
CSS 继承
Permalink to "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 自定义属性
Permalink to "CSS 自定义属性"所有 CSS 自定义属性(--custom-property-name
)都会继承。你可以使用这个特性使你的组件的样式可以从外部配置。
以下组件将其背景色设置为一个 CSS 变量。如果 DOM 树中的祖先选择器设置了 --my-background
的值,CSS 变量就使用该值,否则默认为 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 自定义属性。