龙空技术网

Meta 为啥要卷 CSS-in-JS?StyleX 强在哪里?

高级前端进阶 755

前言:

现时大家对“style在html”大约比较珍视,你们都需要分析一些“style在html”的相关文章。那么小编在网摘上网罗了一些有关“style在html””的相关文章,希望看官们能喜欢,你们快快来学习一下吧!

大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!

2023 年 12 月 5 日 Google 团队推出了最新的 StyleX, StyleX 是一个富有表现力、确定性、可靠且可扩展的样式系统,适用于强大的应用程序。 同时,StyleX 从以前的样式库中汲取了很多好的想法,创造出既熟悉又独特的新东西。

1.StyleX 的起源

Facebook 网站以前也使用了 CSS Module,并且遇到了各种问题,从而激发了 CSS-in-JS 的最初想法。facebook.com 的平均访问者会下载数十兆字节的 CSS, 而且其中大部分未使用。 为了优化初始加载,通常会延迟 CSS,但是这通常会导致更新(Interaction to Next Paint)时间变慢。

同时,使用复杂的选择器会导致冲突或“特异性战争”。 工程师经常会使用 !important 或更复杂的选择器来解决问题,从而使整个系统变得越来越糟糕。几年前,Facebook 工程师开始使用 React 从头开始重构 facebook.com 时创建了 StyleX。

StyleX 专为扩展而设计,该设计已在 Facebook 多年的使用经验中证明了自己。 为 StyleX 添加了诸多新功能,但是并没有降低性能或可扩展性,同时使 StyleX 使用起来更加轻松。

对于 Meta 来说,使用 StyleX 在可扩展性和表现力方面都取得了巨大的进步。 在 facebook.com 上,能够将 CSS Bundle 包从数十兆字节的惰性加载 CSS 缩减为一个几百 KB 的 Bundle 包。

创建 StyleX 不仅是为了满足 Web 上 React 开发人员的样式需求,也是为了统一 Web 和原生 React 的样式。目前,StyleX 也用于对内和对外的诸多产品,包括: Facebook、WhatsApp、Instagram、Workplace 和 Threads

2.到底什么是 StyleX

StyleX 借鉴了诸多 CSS-in-JS 库的开发经验,并使用编译时工具将其与静态 CSS 的性能和可扩展性联系起来。 然而,StyleX 不仅仅是另一个基于编译器的 CSS-in-JS 库, StyleX 经过精心设计,可以满足大型应用程序、可重用组件库和静态类型代码库的要求。主要特性包括:

StyleX 支持 CSS 的富有表现力的子集。避免了复杂的选择器,并保证生成的 CSS 中不会出现特殊性冲突。StyleX 将样式转换、组织和优化为“原子”CSS 类名。 无需学习或管理单独的实用程序类名称库。StyleX 允许跨文件和组件边界合并样式,使其成为允许用户自定义的组件库的理想选择。StyleX 是完全类型化的,并提供类型实用程序,以允许对组件可以接受的属性和值进行细粒度控制。3.StyleX 有什么优势快速

StyleX 的设计目标是在编译时和运行时都快速, Babel 转换不会显著拖慢应用构建速度。

const result = transformSync(sourceCode, {  filename: opts.filename,  parserOpts: { flow: { all: true } },  plugins: [stylexPlugin, opts],});// @stylexjs/babel-plugin 相当轻量,通过将参数 AST 转换为 JS 对象并通过将其传递给 @stylex/shared 中相应名称的函数来转换,从而预先计算 stylex 相关函数,例如 stylex.create 和 stylex.keyframesconst transformedCode = result.code;const injectedStyles = result.metadata.stylex;

在运行时,StyleX 完全避免了与使用 JavaScript 在运行时插入样式的成本,并且仅在必要时有效地组合类名字符串。 生成的 CSS 针对大小进行了优化,确保即使是最大网站的样式也可以被浏览器快速解析。

可扩展

StyleX 旨在扩展到非常大的代码库,就像在 Meta 上拥有的代码库一样。Babel 插件可以利用原子构建和文件级缓存在编译时处理数千个组件中的样式。 由于 StyleX 旨在封装样式,因此允许单独开发新组件,并期望在其他组件中使用后能够以可预测的方式渲染。

import stylex from '@stylexjs/stylex';const styles = stylex.create({  root: {    padding: 10,  },  element: {    backgroundColor: 'red',  },});const styleProps = stylex.apply(styles.root, styles.element);

通过生成原子 CSS 类名,StyleX 有助于最小化 CSS 包的大小。 随着应用程序中组件数量的增加,CSS 包的大小开始趋于稳定。 这使得开发人员不必手动优化或延迟加载 CSS 文件。

可预测

StyleX 自动管理 CSS 选择器的特殊性,以保证生成的规则之间不会发生冲突。 StyleX 为开发人员提供了一个可靠地应用样式的系统,并确保“最后应用的样式总是获胜”

可组合的

StyleX 样式很容易组合。 不仅可以有条件地应用多个本地样式,还可以跨文件和组件传递样式,风格总是与可预测的结果相结合。

import * as stylex from '@stylexjs/stylex';const DARK = '@media (prefers-color-scheme: dark)';// 该函数也在编译时进行处理,并自动生成 CSS 变量// 定义了 HTML 文档的 :root 变量,可以作为常量导入并在 stylex.create 调用export const colors = stylex.defineVars({  primaryText: { default: 'black', [DARK]: 'white' },  secondaryText: { default: '#333', [DARK]: '#ccc' },  accent: { default: 'blue', [DARK]: 'lightblue' },  background: { default: 'white', [DARK]: 'black' },  lineColor: { default: 'gray', [DARK]: 'lightgray' },  borderRadius: '4px',  fontFamily: 'system-ui, sans-serif',  fontSize: '16px',});

下面是使用变量的示例:

import * as stylex from '@stylexjs/stylex';import { colors, spacing } from '../tokens.stylex';// 使用样式const styles = stylex.create({  container: {    color: colors.primaryText,    backgroundColor: colors.background,  },});
类型安全

开发者可以使用 TypeScript 或 Flow 类型来约束组件接受的样式。 每个样式属性和变量都是完全类型化的。

import type { StyleXStyles } from '@stylexjs/stylex';type Props = {  // ...  style?: StyleXStyles<{    color?: string,    backgroundColor?: string,    borderColor?: string,    borderTopColor?: string,    borderEndColor?: string,    borderBottomColor?: string,    borderStartColor?: string,  }>,};
主机托管和可测试

StyleX 允许并鼓励在组件的同一文件中创建样式,从而有助于样式更具可读性和可维护性。 StyleX 能够使用静态分析和构建时工具来消除组件之间的重复样式并删除未使用的样式。

StyleX 可以配置为输出调试类名称而不是功能原子类名称,从而生成不会因较小的设计更改而经常更改的快照。

4.StyleX 如何运作

StyleX 是一组协同工作的工具集合,主要包括:

一个 Babel 插件一个小型运行时库一个 ESlint 插件与打包器和框架的集成不断增多。

StyleX 最重要的部分是 Babel 插件,其查找并提取源代码中定义的所有样式,并在编译时转换为原子类名称(Atomic Class Names)。 辅助函数对收集的样式进行重复数据删除、排序并将其写入 CSS 文件, 这些工具可用于实现打包器插件。

为了让使用 StyleX 尽可能自然,StyleX 支持各种静态模式,通过使用本地常量和表达式来定义样式。 此外,为了给开发者提供尽可能最佳的性能,Babel 插件还会在可能的情况下预先计算最终的类名,以消除给定文件中的任何运行时成本(甚至合并类名)。 如果组件在同一文件中静态定义和使用样式,则运行时成本将为零。

当使用更强大的模式(例如:样式组合)时,微小的运行时会动态合并类名的对象。 该运行时间已被优化为非常快,然后结果会被记忆。

参考资料

标签: #style在html