可构建的 CSS 样式表

一直以来,我们都可以使用 JavaScript 创建样式表。 不过,以往的做法是使用 document.createElement('style') 创建一个 <style> 元素,然后访问其 sheet 属性以获取对底层 CSSStyleSheet 实例的引用。 这种方法会产生重复的 CSS 代码和随之而来的臃肿,而且无论是否存在臃肿,附加行为都会导致未经样式化的内容一闪而过。 CSSStyleSheet 接口是 CSS 表示接口集合(称为 CSSOM)的基础,它提供了一种编程方式来处理样式表,并消除了与旧方法相关的问题。

通过可构造样式表,我们可以定义和准备共享的 CSS 样式,然后将这些样式轻松地应用到多个 Shadow Root 或 Documents中,而不会出现重复。共享 CSSStyleSheet 的更新会应用到所有采用了该 CSSStyleSheet 的根中,而且一旦加载了样式表,采用该样式表的过程就会变得快速而同步。

可构建样式表所建立的关联适用于多种不同的应用。它可以为许多组件提供一个集中式主题:主题可以是一个传递给组件的 CSSStyleSheet 实例,主题的更新会自动传播给组件。它可用于将 CSS 自定义属性值分发到特定的 DOM 子树,而无需依赖级联。它甚至可用作浏览器 CSS 解析器的直接接口,从而轻松预载样式表,而无需将其注入 DOM。

构建样式表

可构造样式表规范并没有引入一个新的应用程序接口来实现这一目标,而是通过调用 CSSStyleSheet() 构造函数来强制创建样式表。生成的 CSSStyleSheet 对象有两个新方法,可以更安全地添加和更新样式表规则,而不会触发 Flash of Unstyled Content (FOUC)replace()replaceSync() 方法都是用 CSS 字符串替换样式表,而 replace() 返回一个 Promise。 在这两种情况下,都不支持外部样式表引用–任何 @import 规则都会被忽略并产生警告。

const sheet = new CSSStyleSheet();

// replace all styles synchronously:
sheet.replaceSync('a { color: red; }');

// replace all styles:
sheet.replace('a { color: blue; }')
  .then(() => {
    console.log('Styles replaced');
  })
  .catch(err => {
    console.error('Failed to replace styles:', err);
  });

// Any @import rules are ignored.
// Both of these still apply the a{} style:
sheet.replaceSync('@import url("styles.css"); a { color: red; }');
sheet.replace('@import url("styles.css"); a { color: red; }');
// Console warning: "@import rules are not allowed here..."

x

在规范的早期版本中,replace() 允许使用 @import 规则,并在这些规则加载完成后返回一个解析的 Promise。 从 Chrome 浏览器 84 开始,该功能已从规范中删除,@import 规则会被忽略并发出警告。

使用构建的样式表

可构造样式表引入的第二个新功能是 Shadow Roots 和 Documents 上的 adoptedStyleSheets 属性。 通过该属性,我们可以明确地将 CSSStyleSheet 定义的样式应用到指定的 DOM 子树。 为此,我们要将该属性设置为一个数组,其中包含一个或多个要应用于该元素的样式表。

// Create our shared stylesheet:
const sheet = new CSSStyleSheet();
sheet.replaceSync('a { color: red; }');

// Apply the stylesheet to a document:
document.adoptedStyleSheets.push(sheet);

// Apply the stylesheet to a Shadow Root:
const node = document.createElement('div');
const shadow = node.attachShadow({ mode: 'open' });
shadow.adoptedStyleSheets.push(sheet);

在规范的早期版本中,adcitedStyleSheets 是作为一个冻结数组实现的,这意味着像 push() 这样的就地突变会产生异常。 添加新的样式表需要重新定义数组: document.adoptedStyleSheets = […document.adoptedStyleSheets, newSheet] 由于规范已更新为允许数组突变,这种情况已不复存在。

将所有内容整合在一起

有了可构造样式表(Constructable StyleSheets),网络开发人员现在有了创建 CSS 样式表并将其应用到 DOM 树的明确解决方案。 我们有一个新的基于 Promise 的 API,用于从 CSS 源字符串加载样式表,该 API 使用浏览器的内置解析器和加载语义。 最后,我们还提供了一种机制,用于将样式表更新应用到样式表的所有使用中,从而简化了主题更改和颜色偏好等工作。

View Demo

展望未来

Constructable Stylesheets(可构造样式表)的初始版本包含此处描述的 API,但目前正在努力使其更易于使用。 有人建议用插入和移除样式表的专用方法来扩展 adoptedStyleSheets FrozenArray,这样就不需要克隆数组,也能避免潜在的重复样式表引用。

阅读余下内容
 

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注


京ICP备12002735号