- 前端
- UI组件
【免费下载链接】fast
The adaptive interface system for modern web experiences.
ElementStyles是 @microsoft/fast-element 中用于表示"可应用到自定义元素上的一组样式"的核心抽象类。它统一了字符串 CSS、CSSStyleSheet构造式样式表与其他ElementStyles实例的组合方式,并通过可插拔的StyleStrategy负责把样式真正挂载到 Shadow DOM 或document上。本文以官方 API 文档 fast-element.elementstyles.md 为主线,结合 element-styles.ts、element-controller.ts 等源码,讲解该类的全部公开成员、底层实现与实战用法。
ElementStyles:可应用于自定义元素的样式抽象
在 fast-element 的样式体系中,ElementStyles是连接"样式声明"与"样式注入"两个环节的中间层。其类定义(fast-element.elementstyles.md)如下:
export declare abstract class ElementStyles在 API 文档中它被声明为抽象类,而当前仓库的实际实现(element-styles.ts)是一个具体类,拥有公开构造函数:
export class ElementStyles { public constructor(public readonly styles: ReadonlyArray<ComposableStyles>) {} }也就是说,ElementStyles本质是一个静态的样式容器:构造时接收一组ComposableStyles(可组合样式),对外暴露只读的styles数组,自身不直接操作 DOM,而是把"如何注入"委托给内部的StyleStrategy。这种"数据与行为分离"的设计,让同一组样式可以针对不同运行时环境(支持构造式样式表的现代浏览器、仅支持<style>标签的旧环境)选择不同的注入策略。
ComposableStyles 与 ElementStyleFactory:两个关键类型
围绕ElementStyles的两个类型定义同样来自官方 API 文档:
- ComposableStyles:
string | ElementStyles | CSSStyleSheet,表示"可以被组合进自定义元素 Shadow DOM 的样式",可以是普通 CSS 字符串、另一个ElementStyles实例或浏览器的构造式样式表; - ElementStyleFactory:
(styles: ReadonlyArray<ComposableStyles>) => ElementStyles,负责"为一个ComposableStyles数组创建ElementStyles实例"。
两者的源码定义集中在 element-styles.ts。其中ComposableStyles的三元结构是理解ElementStyles的关键:嵌套的ElementStyles会被递归展开(reduceStyles函数),最终扁平化为string | CSSStyleSheet的数组后交给策略处理:
function reduceStyles( styles: ReadonlyArray<ComposableStyles>, ): (string | CSSStyleSheet)[] { return styles.reduce<(string | CSSStyleSheet)[]>((reduced, current) => { if (current instanceof ElementStyles) { reduced.push(...reduceStyles(current.styles)); } else { reduced.push(current); } return reduced; }, []); }这意味着你可以在一个ElementStyles中直接组合另一个ElementStyles,而不必预先手动展开,例如把"基础样式 + 主题样式"两个独立模块拼成一个整体注入。
静态属性 create:统一的样式工厂
ElementStyles公开的唯一静态属性是create(fast-element.elementstyles.create.md):
static readonly create: ElementStyleFactory;其职责用官方文档原文说是"从ComposableStyles创建ElementStyles",也就是ElementStyleFactory类型的实例。它等价于在运行时执行new ElementStyles(styles)。在 1.x 时代的 API 设计中,它是创建样式容器的统一入口;到了当前 3.x 源码,日常开发更多直接使用css模板标签(见下文),create语义仍可通过构造函数体现。
方法 withBehaviors:关联行为与 v3 的迁移
1.x 文档中ElementStyles只有一个公开方法withBehaviors(fast-element.elementstyles.withbehaviors.md):
withBehaviors(...behaviors: Behavior[]): this;参数behaviors的类型为 Behavior 数组——一个拥有bind(source, context)/unbind(source)两个方法的接口,表示"能向视图或元素的 bind/unbind 过程贡献行为"的对象。该方法的作用是"将行为与这一组样式关联",并返回this以支持链式调用。
需要特别说明的是:该 API 属于 fast-element 1.x 时代的产物。根据仓库内的迁移文档 fast-element-3.md,v3 已经移除了ElementStyles.withBehaviors()、ElementStyles.behaviors以及css中的 CSS bindings,ElementStyles变为"完全静态的样式容器"。官方的迁移建议是:
把运行时条件移入元素内部,直接调用
this.$fastController.addStyles()/this.$fastController.removeStyles()。
具体迁移步骤(fast-element-3.md):
- 将条件性的
ElementStyles保留为独立的css值; - 把外部监听或条件(例如
matchMedia()或应用事件订阅)移入元素生命周期; - 条件生效时调用
this.$fastController.addStyles(styles),失效或清理时调用this.$fastController.removeStyles(styles); - 原先插入到
css中的函数式/绑定式插值,改为使用元素状态配合标准 DOM 或控制器更新。
这一变化体现了 fast-element 把"样式"与"行为"彻底解耦的设计取向:样式只承载静态 CSS,动态逻辑全部交给元素控制器生命周期管理。
实践入口:css 模板标签如何产出 ElementStyles
尽管ElementStyles可以手动new,日常开发中最常见的入口是css模板标签。在 css.ts 中:
export const css: CSSTemplateTag = (( strings: TemplateStringsArray, ...values: CSSValue[] ): ElementStyles => { return new ElementStyles(collectStyles(strings, values)); }) as any;collectStyles(css.ts)负责把模板字符串与插值(CSSValue = ComposableStyles | CSSDirective)拆解为ComposableStyles[]:普通字符串拼接进cssString,遇到ElementStyles/CSSStyleSheet实例则作为一个独立片段压入数组,最终交给new ElementStyles(...)。
典型用法:
import { css } from "@microsoft/fast-element"; const baseStyles = css`:host { display: block; }`; // 组合:字符串 + ElementStyles 实例 const themeStyles = css` ${baseStyles} :host { color: var(--accent-color); } `;此外,css.partial()(css.ts)返回的是CSSDirective,可在样式声明处实现"局部 CSS 片段"的懒计算与复用。
底层原理:StyleStrategy 与 StyleTarget 双策略机制
ElementStyles自身不负责挂载样式,而是把该职责交给StyleStrategy。相关接口定义在 style-strategy.ts:
StyleTarget:可被样式注入的目标节点,需要支持adoptedStyleSheets、append、removeChild、querySelectorAll(style-strategy.ts);StyleStrategy:实现addStylesTo(target)与removeStylesFrom(target)两个方法(style-strategy.ts)。
ElementStyles的strategygetter(element-styles.ts)会在首次访问时根据环境自动选择默认策略,也可通过setDefaultStrategy()(element-styles.ts)显式指定。当前仓库中 element-controller 模块会在加载时完成注册(element-controller.ts):
AdoptedStyleSheetsStrategy:当ElementStyles.supportsAdoptedStyleSheets(同时满足document.adoptedStyleSheets为数组且CSSStyleSheet.prototype.replace存在)为真时启用。它利用构造式样式表,将字符串通过replaceSync转为CSSStyleSheet并做缓存,再写入目标节点的adoptedStyleSheets(element-controller.ts)。源码中还针对 Safari 16.4 的 FrozenArray 兼容问题做了特判(element-controller.ts);StyleElementStrategy:回退方案,为每段样式创建一个带唯一fast-N类名的<style>元素,插入目标(ShadowRoot 或document.body),移除时按类名批量查询删除(element-controller.ts)。
ElementStyles通过addStylesTo/removeStylesFrom/isAttachedTo(element-styles.ts)把策略能力包装成面向控制器的简洁接口,并用WeakSet记录已注入的目标,避免重复注入。
与元素生命周期的协作:Controller 如何消费 ElementStyles
样式最终由 ElementController 消费,其关键成员包括:
mainStyles:组件主样式。解析优先级为"实例级resolveStyles()覆盖 > 定义级definition.styles"(element-controller.ts);addStyles(styles)/removeStyles(styles):向元素注入/移除样式。ElementStyles实例走策略通道(仅在isAttachedTo(source)为 false 时才注入),HTMLStyleElement则直接挂到 ShadowRoot 上(element-controller.ts);- 生命周期集成:在
connect()首次初始化时调用renderTemplate与addStyles(this.mainStyles)(element-controller.ts)。
结合迁移文档的建议,动态换肤的推荐写法是:
class MyElement extends FASTElement { #lightTheme = css`:host { color: #111; }`; #darkTheme = css`:host { color: #eee; }`; connectedCallback() { super.connectedCallback(); const mql = matchMedia("(prefers-color-scheme: dark)"); this.$fastController.addStyles(mql.matches ? this.#darkTheme : this.#lightTheme); } disconnectedCallback() { super.disconnectedCallback(); this.$fastController.removeStyles(this.#darkTheme); this.$fastController.removeStyles(this.#lightTheme); } }小结
ElementStyles是 fast-element 样式系统中最底层的容器抽象:它以ComposableStyles统一了字符串、CSSStyleSheet与嵌套样式实例,用ElementStyleFactory(create静态属性)统一了创建入口,并通过StyleStrategy把注入逻辑与业务代码解耦。虽然 1.x 时代的withBehaviors在 v3 中已被移除,但其背后的"样式与行为分离"思想被$fastController.addStyles()/removeStyles()所继承和强化。理解 element-styles.ts 与 element-controller.ts 中该类的实现细节,有助于你写出更贴合运行时特性的组件样式代码。
- 前端
- UI组件
【免费下载链接】fast
The adaptive interface system for modern web experiences.
相关推荐
Carnac系统托盘集成:Windows桌面应用的最佳实践
Carnac系统托盘集成:Windows桌面应用的最佳实践 在Windows桌面应用开发中,系统托盘集成是提升用户体验的关键功能。Carnac作为一款专业的键盘
前端UI组件深入解析 fast-element 的 ComposableStyles:自定义元素 Shadow DOM 的可组合样式类型
深入解析 fast element 的 ComposableStyles:自定义元素 Shadow DOM 的可组合样式类型 导读 ComposableStyl
前端UI组件@microsoft/fast-element 样式系统 API 全解:从 ComposableStyles 到 StyleStrategy 的架构与实践
@microsoft/fast element 样式系统 API 全解:从 ComposableStyles 到 StyleStrategy 的架构与实践 本文
前端UI组件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考