css-typed-om-polyfill 0.1.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.zh.md CHANGED
@@ -1,240 +1,173 @@
1
- # CSS Typed OM Polyfill
1
+ # Moonlight CSS Typed OM Polyfill
2
2
 
3
- 一个针对 [CSS Typed Object Model (OM) Level 1](https://www.w3.org/TR/css-typed-om/) 规范的 JavaScript polyfill。此 polyfill 旨在为那些本身不支持 CSS Typed OM API 的浏览器提供一个功能子集,使开发者能够以类型化 JavaScript 对象的方式与 CSS 值进行交互。
3
+ **Moonlight** 是一个高性能、高精度的 [CSS Typed Object Model (OM) Level 1](https://www.w3.org/TR/css-typed-om/) 规范 JavaScript polyfill
4
+
5
+ 不同于普通的垫片库,Moonlight 旨在通过 **微架构优化 (Velocity Engine)** 和 **代数逻辑引擎 (Algebraic Soul)**,在不支持原生 API 的环境中提供接近甚至在某些特定场景下超越原生的性能体验。
6
+
7
+ 它不仅是一个工具,更是逻辑与速度的共生体。
4
8
 
5
9
  ## 目录
6
10
 
7
11
  - [简介](#简介)
8
- - [特性](#特性)
9
- - [支持的 CSS Typed OM 接口](#支持的-css-typed-om-接口)
12
+ - [核心进化](#核心进化)
13
+ - [支持的接口](#支持的接口)
10
14
  - [安装](#安装)
11
15
  - [基本用法](#基本用法)
12
- - [高级用法与注意事项](#高级用法与注意事项)
13
- - [解析 CSS 值](#解析-css-值)
14
- - [`calc()` 与数学函数](#calc-与数学函数)
15
- - [算术运算](#算术运算)
16
- - [`var()` (CSS 变量)](#var-css-变量)
17
- - [局限性与待办事项](#局限性与待办事项)
18
- - [开发](#开发)
16
+ - [高级用法](#高级用法)
17
+ - [解析与严格模式](#解析与严格模式)
18
+ - [代数运算与优化](#代数运算与优化)
19
+ - [变换与矩阵 (Transforms)](#变换与矩阵-transforms)
20
+ - [性能哲学](#性能哲学)
21
+ - [局限性](#局限性)
19
22
  - [许可证](#许可证)
20
23
 
21
24
  ## 简介
22
25
 
23
- CSS Typed Object Model 提供了一种在 JavaScript 中以类型感知的方式操作 CSS 值的方法,而不是仅仅处理字符串。这可以带来更健壮和更高性能的代码。此 polyfill 将这种能力的一部分带到了缺乏原生支持的环境中。
24
-
25
- 它专注于将 CSS 字符串解析为类型化对象,对数值执行算术运算,并提供 `element.attributeStyleMap` 接口以便以类型化的方式获取和设置样式。
26
-
27
- ## 特性
28
-
29
- * **`HTMLElement.prototype.attributeStyleMap`**: 使用 `StylePropertyMap` 访问和修改内联样式。
30
- * **CSS 值解析**:
31
- * `CSSStyleValue.parse(property, cssText)`: 解析单个 CSS 值字符串。
32
- * `CSSStyleValue.parseAll(property, cssText)`: 解析逗号分隔的 CSS 值列表。
33
- * **数值**:
34
- * `CSSNumericValue` (数字和单位的基类)
35
- * `CSSUnitValue` (例如, `10px`, `50%`, `3.14rad`)。
36
- * `CSS.*` 工厂函数 (例如, `CSS.px(10)`, `CSS.percent(50)`, `CSS.number(5)`)。
37
- * 算术运算: `.add()`, `.sub()`, `.mul()`, `.div()`, `.negate()`, `.invert()`。
38
- * 单位转换: `.to('targetUnit')` 用于兼容类型 (例如, `s` 转 `ms`)。
39
- * 数学运算的类型检查 (例如, `length + angle` 是无效的)。
40
- * **数学表达式**:
41
- * `CSSMathSum`, `CSSMathProduct`, `CSSMathNegate`, `CSSMathInvert`。
42
- * `CSSMathMin`, `CSSMathMax`。
43
- * 递归解析 `calc()`、`min()`、`max()` 表达式,包括嵌套函数和 `var()`。
44
- * **其他 CSS 值**:
45
- * `CSSKeywordValue` (例如, `auto`, `inherit`, `initial`)
46
- * `CSSVariableReferenceValue` (用于 `var(--custom-property)`)。
47
- * `CSSUnparsedValue` (用于未完全解析或不支持的值)。
48
- * **桩实现/部分实现**:
49
- * `CSSImageValue` (基础桩实现, 将 `url(...)` 作为字符串返回)。
50
- * `CSSPositionValue` (基础桩实现)。
51
- * `CSSTransformValue` 及其组件 (`CSSTranslate`, `CSSRotate`, `CSSScale`) (带有构造函数和 `toString()` 的基础桩实现)。
52
-
53
- ## 支持的 CSS Typed OM 接口
54
-
55
- **核心类:**
56
- * `CSSStyleValue` (抽象基类)
57
- * `CSSNumericValue` (数值类型的抽象基类)
58
- * `CSSUnitValue`
59
- * `CSSKeywordValue`
60
- * `CSSUnparsedValue`
61
- * `CSSVariableReferenceValue`
62
-
63
- **数学类 (继承自 `CSSNumericValue`):**
64
- * `CSSMathValue` (抽象基类)
65
- * `CSSMathSum`
66
- * `CSSMathProduct`
67
- * `CSSMathNegate`
68
- * `CSSMathInvert`
69
- * `CSSMathMin`
70
- * `CSSMathMax`
71
-
72
- **其他 (桩实现/部分实现):**
73
- * `CSSImageValue`
74
- * `CSSPositionValue`
75
- * `CSSTransformValue`
76
- * `CSSTransformComponent` (抽象基类)
77
- * `CSSTranslate`
78
- * `CSSRotate`
79
- * `CSSScale`
80
-
81
- **接口:**
82
- * `StylePropertyMap` (通过 `element.attributeStyleMap` 提供)
26
+ CSS Typed Object Model 允许开发者以对象的形式操作 CSS 值,而不是脆弱的字符串拼接。Moonlight 将这种能力带到了所有现代浏览器中。
27
+
28
+ 它专注于:
29
+ 1. **类型安全**:严格区分 `number`、`length`、`angle` 等类型,拒绝非法计算。
30
+ 2. **数学化简**:自动应用分配律、常量折叠,将复杂的 `calc()` 树化简为最优形式。
31
+ 3. **零分配解析**:使用优化的词法分析器,最小化垃圾回收 (GC) 压力。
32
+
33
+ ## 核心进化
34
+
35
+ * **Velocity Engine (极速引擎)**: 采用类数组结构处理变换列表;针对 2 参数 `calc()` 运算提供极速“热路径 (Hot Path)”。
36
+ * **Algebraic Soul (代数灵魂)**: 实现了数学分配律 (`(A + B) * k = Ak + Bk`) 和智能倒数折叠。
37
+ * **Strict Typing (严苛类型)**: 严格遵循规范,禁止 `number + length` (如 `calc(0 + 10px)`),并提供精准的错误提示。
38
+ * **Full Transforms**: 完整支持 CSS Transform Module Level 2,包括 `skew`, `perspective` `toMatrix()` 计算。
39
+
40
+ ## 支持的接口
41
+
42
+ Moonlight 实现了规范中的核心数学和变换接口:
43
+
44
+ **基础值:**
45
+ * `CSSStyleValue` (解析入口)
46
+ * `CSSNumericValue` (所有数值基类)
47
+ * `CSSUnitValue` (例如: `10px`, `50%`)
48
+ * `CSSKeywordValue` (例如: `auto`)
49
+ * `CSSUnparsedValue` (兜底类型)
50
+
51
+ **数学表达式:**
52
+ * `CSSMathSum`, `CSSMathProduct`
53
+ * `CSSMathNegate`, `CSSMathInvert`
54
+ * `CSSMathMin`, `CSSMathMax`, `CSSMathClamp`
55
+
56
+ **变换与矩阵:**
57
+ * `CSSTransformValue` (类数组对象,支持迭代)
58
+ * `CSSTranslate`, `CSSRotate`, `CSSScale`
59
+ * `CSSSkew`, `CSSSkewX`, `CSSSkewY`
60
+ * `CSSPerspective`
61
+ * 支持 `.toMatrix()` 返回 `DOMMatrix`
62
+
63
+ **DOM 扩展:**
64
+ * `HTMLElement.prototype.attributeStyleMap`
83
65
 
84
66
  ## 安装
85
67
 
86
- 只需在您的 HTML 文件中,在使用 CSS Typed OM API 的任何脚本之前引入 polyfill 脚本即可:
68
+ 直接在项目中引入 polyfill 脚本。它会自动检测原生支持,仅在必要时激活。
87
69
 
88
70
  ```html
89
- <script src="path/to/css-typed-om-polyfill.js"></script>
71
+ <script src="cssom.js"></script>
90
72
  <script>
91
- // 您使用 Typed OM 的代码
92
- const el = document.getElementById('myElement');
93
- if (el && el.attributeStyleMap) {
94
- el.attributeStyleMap.set('width', CSS.px(100));
95
- console.log(el.attributeStyleMap.get('width').toString()); // "100px"
96
- }
73
+ const el = document.querySelector('#box');
74
+ // 如果浏览器不支持原生 Typed OM,Moonlight 将接管 attributeStyleMap
75
+ el.attributeStyleMap.set('opacity', 0.5);
97
76
  </script>
98
77
  ```
99
78
 
100
- polyfill 将自动初始化并将必要的属性附加到全局作用域 (`window`) 和 `HTMLElement.prototype`。
101
-
102
79
  ## 基本用法
103
80
 
104
- ### 访问 `attributeStyleMap`
81
+ ### 操作 `attributeStyleMap`
105
82
 
106
83
  ```javascript
107
- const element = document.createElement('div');
108
- document.body.appendChild(element);
84
+ const el = document.getElementById('hero');
109
85
 
110
- // 设置样式
111
- element.attributeStyleMap.set('width', CSS.px(200));
112
- element.attributeStyleMap.set('opacity', CSS.number(0.5));
113
- element.attributeStyleMap.set('margin-top', CSS.em(1.5));
86
+ // 设置样式 (自动装箱)
87
+ el.attributeStyleMap.set('font-size', CSS.rem(1.5));
88
+ el.attributeStyleMap.set('width', CSS.px(100));
89
+ el.attributeStyleMap.set('opacity', CSS.number(0.8));
114
90
 
115
91
  // 获取样式
116
- const width = element.attributeStyleMap.get('width'); // CSSUnitValue { value: 200, unit: "px" }
117
- console.log(width.value); // 200
92
+ const width = el.attributeStyleMap.get('width');
93
+ console.log(width.value); // 100
118
94
  console.log(width.unit); // "px"
119
- console.log(width.toString()); // "200px"
95
+ console.log(width.toString()); // "100px"
120
96
 
121
- const opacity = element.attributeStyleMap.get('opacity'); // CSSNumericValue { _value: 0.5, _unitType: "number" }
122
- console.log(opacity.toString()); // "0.5"
97
+ // 类型检查
98
+ console.log(width instanceof CSSUnitValue); // true
123
99
  ```
124
100
 
125
- ### 使用 `CSS.*` 工厂函数
101
+ ### 使用工厂函数
126
102
 
127
103
  ```javascript
128
- const length = CSS.px(100);
129
- const percentage = CSS.percent(50);
130
- const duration = CSS.s(2.5);
131
- const angle = CSS.deg(90);
132
- const number = CSS.number(10);
133
-
134
- console.log(length.add(CSS.vw(10)).toString()); // "calc(100px + 10vw)"
104
+ // 创建不同单位的值
105
+ const angle = CSS.deg(45);
106
+ const time = CSS.s(1.5);
107
+ const percent = CSS.percent(100);
108
+
109
+ // 链式计算
110
+ const result = CSS.px(10).add(CSS.px(20)).mul(2);
111
+ console.log(result.toString()); // "60px" (自动化简)
135
112
  ```
136
113
 
137
- ## 高级用法与注意事项
138
-
139
- ### 解析 CSS 值
114
+ ## 高级用法
140
115
 
141
- ```javascript
142
- // 解析单个值
143
- const parsedWidth = CSSStyleValue.parse('width', 'calc(100% - 20px)');
144
- console.log(parsedWidth.toString()); // "calc(100% - 20px)"
145
- if (parsedWidth instanceof CSSMathSum) {
146
- console.log(parsedWidth.operator); // "sum"
147
- console.log(parsedWidth.values[0].toString()); // "100%"
148
- console.log(parsedWidth.values[1].toString()); // "calc(-1 * 20px)" (第二项被取反)
149
- }
116
+ ### 代数运算与优化
150
117
 
151
- const keyword = CSSStyleValue.parse('display', 'block');
152
- console.log(keyword.value); // "block"
153
-
154
- // 解析值列表 (例如, 用于 font-family)
155
- const fontFamilies = CSSStyleValue.parseAll('font-family', '"Arial", sans-serif');
156
- fontFamilies.forEach(font => console.log(font.toString()));
157
- // 输出:
158
- // "Arial" (字符串的 CSSUnparsedValue)
159
- // "sans-serif" (CSSKeywordValue)
160
- ```
161
-
162
- ### `calc()` 与数学函数
163
-
164
- 此 polyfill 包含一个针对 `calc()`、`min()` 和 `max()` 表达式的健壮解析器,它遵循运算符优先级和括号规则。
118
+ Moonlight 不仅仅是存储表达式,它会像编译器一样优化它们。
165
119
 
166
120
  ```javascript
167
- const complexCalc = CSSStyleValue.parse('width', 'calc( (var(--A) + 2 * ( 5vw - var(--B) )) / 3 )');
168
- console.log(complexCalc.toString()); // "calc((var(--A) + 2 * (5vw - var(--B))) / 3)"
169
- // 内部结构将是一个由 CSSMathProduct, CSSMathSum 等组成的树
121
+ // 1. 常量折叠 (Constant Folding)
122
+ const a = CSS.px(10).mul(2);
123
+ console.log(a.toString()); // "20px" (而不是 calc(10px * 2))
124
+
125
+ // 2. 分配律应用 (Distributive Law)
126
+ // (100% - 20px) / 2 => 50% - 10px
127
+ const b = CSS.percent(100).sub(CSS.px(20)).div(2);
128
+ console.log(b.toString()); // "calc(50% + -10px)"
129
+ // 这种优化对于避免深层嵌套的 calc() 树至关重要
170
130
  ```
171
131
 
172
- ### 算术运算
132
+ ### 变换与矩阵 (Transforms)
173
133
 
174
- `CSSNumericValue` 及其子类支持算术运算。涉及不同兼容单位或 `var()` 的运算将产生 `CSSMathSum` 或 `CSSMathProduct` 对象。
134
+ 支持完整的变换对象模型和矩阵计算。
175
135
 
176
136
  ```javascript
177
- const val1 = CSS.px(10);
178
- const val2 = CSS.em(2);
179
- const val3 = CSS.percent(50);
180
- const num = CSS.number(5);
181
-
182
- // 加法
183
- console.log(val1.add(val2).toString()); // "calc(10px + 2em)"
184
- console.log(val1.add(CSS.px(5)).toString()); // "15px" (相同单位)
137
+ // 解析变换字符串
138
+ const transform = CSSStyleValue.parse('transform', 'translate(10px, 50%) rotate(45deg)');
185
139
 
186
- // 减法
187
- console.log(val3.sub(CSS.px(10)).toString()); // "calc(50% - 10px)"
140
+ // 像数组一样访问
141
+ console.log(transform[0] instanceof CSSTranslate); // true
142
+ console.log(transform[1] instanceof CSSRotate); // true
188
143
 
189
- // 乘法
190
- console.log(val1.mul(num).toString()); // "50px" (长度 * 数字 = 长度)
191
- console.log(val1.mul(CSS.percent(200)).toString()); // "calc(10px * 200%)" (长度 * 百分比)
192
-
193
- // 除法
194
- console.log(val1.div(num).toString()); // "2px"
195
- console.log(val1.div(CSS.px(2)).toString()); // "5" (长度 / 长度 = 数字)
196
- ```
197
-
198
- ### `var()` (CSS 变量)
199
-
200
- `var()` 表达式被解析为 `CSSVariableReferenceValue` 对象。它们可以在数学函数和算术运算中使用,并保持未解析状态。
201
-
202
- ```javascript
203
- const myVar = CSSStyleValue.parse('width', 'var(--my-width, 100px)');
204
- console.log(myVar.variable); // "--my-width"
205
- console.log(myVar.fallback.toString()); // "100px"
144
+ // 迭代
145
+ for (const component of transform) {
146
+ console.log(component.toString());
147
+ }
206
148
 
207
- const calcWithVar = CSS.px(10).add(myVar);
208
- console.log(calcWithVar.toString()); // "calc(10px + var(--my-width, 100px))"
149
+ // 计算矩阵 (需要 DOMMatrix 支持)
150
+ const matrix = transform.toMatrix();
151
+ console.log(matrix.m11, matrix.m12, ...);
209
152
  ```
210
153
 
211
- ## 局限性与待办事项
154
+ ## 性能哲学
212
155
 
213
- polyfill 尚在开发中,并未覆盖整个 CSS Typed OM 规范。主要局限性包括:
156
+ Moonlight 的设计遵循 **"Velocity" (极速)** 哲学:
214
157
 
215
- * **`clamp()`**: 目前在数学表达式解析器中不支持(如果位于顶层,将解析为 `CSSUnparsedValue`;如果在 `calc()` 内部,则会抛出错误)。
216
- * **颜色值**: 复杂的颜色函数 (例如, `rgb()`, `hsl()`, `color()`) 通常被解析为 `CSSUnparsedValue`。基本的命名颜色可能解析为 `CSSKeywordValue`。
217
- * **详细的 Transform 解析**: 虽然存在带有构造函数的 `CSSTransformValue` 及其组件类 (`CSSTranslate`, `CSSRotate`, `CSSScale`),但主要的 `CSSStyleValue.parse` 会对 transform 函数字符串返回 `CSSUnparsedValue`。您需要手动构造它们。
218
- * **`CSSNumericValue.equals()`**: 提供简化的结构检查,主要通过 `toString()` 比较,对于所有数学上等价但结构不同的表达式可能不够健壮。
219
- * **类型系统细微之处**: 数学值上的 `type()` 方法尝试确定结果类型 (例如, `length`, `angle`, `percent`),但复杂的交互,特别是与 `var()` 的交互,可能导致类型不确定。
220
- * **无实际值计算**: polyfill 解析并表示 CSS 值和表达式。它**不会**计算表达式的最终使用值 (例如, 它不会将 `calc(10px + 5%)` 解析为单个像素值,因为这需要布局上下文)。
221
- * **简写属性**: 如果浏览器在 `element.style` 中没有将简写属性展开为完整属性,`StylePropertyMap.get()` 可能会对简写属性返回 `null` 或未解析的值。polyfill 依赖于 `element.style.getPropertyValue()` 的返回值。
222
- * **有限的特定属性解析**: `CSSStyleValue.parse(property, cssText)` 目前不使用 `property` 参数来指导特定于该属性语法的解析(超出基本区分)。
158
+ 1. **Hot Path Optimization**: 针对 CSS中最常见的二元运算(如 `width: calc(100% - 20px)`)编写了专门的快速路径,绕过通用的数组分配。
159
+ 2. **Singleton Cache**: 对常用的 `0px`, `1`, `0` 等值使用单例或快速创建模式,减少 GC 压力。
223
160
 
224
- **未来增强 (待办事项):**
225
- * 实现 `clamp()`。
226
- * 改进颜色值的解析。
227
- * 将 transform 函数完整解析为 `CSSTransformValue`。
228
- * 更健壮的 `CSSNumericValue.equals()`。
229
- * 支持更多 `CSSStyleValue` 子类 (例如, `CSSSkew`, `CSSPerspective`, `CSSMatrixComponent`)。
230
- * 考虑 `CSSMathClamp`。
161
+ 在微基准测试中,Moonlight 在纯代数计算场景下性能可与原生实现媲美。
231
162
 
232
- ## 开发
163
+ ## 局限性
233
164
 
234
- 代码包含在一个 IIFE (立即调用函数表达式) 中。数学表达式的核心解析逻辑位于 `parseCssMathExpression` 中。`CSSStyleValue.parse` 是解析 CSS 文本的主要入口点。
165
+ 尽管 Moonlight 非常强大,但由于缺乏浏览器的布局引擎上下文,仍存在物理局限:
235
166
 
236
- 脚本末尾包含一个用 `setTimeout` 包装的示例用法代码,可在浏览器环境中用于测试。
167
+ * **相对单位解析**: 无法将 `em`, `rem`, `vw`, `%` 解析为绝对像素 (`px`),因为这依赖于 DOM 树和布局计算。
168
+ * **上下文无关**: `CSSStyleValue.parse` 不知道它被用于哪个元素,因此无法处理 `inherit` 或基于当前字体的计算。
169
+ * **颜色与图像**: 目前主要关注数值、数学和变换。复杂的 `color()` 或 `image-set()` 可能会回退为 `CSSUnparsedValue`。
237
170
 
238
171
  ## 许可证
239
172
 
240
- [MIT](LICENSE)
173
+ [MIT](LICENSE) - 献给所有追求极致的开发者。