css-typed-om-polyfill 0.1.0 → 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.md +119 -185
- package/README.zh.md +115 -182
- package/cssom.js +1732 -0
- package/package.json +3 -3
- package/css-typed-om-polyfill.js +0 -1369
package/README.zh.md
CHANGED
|
@@ -1,240 +1,173 @@
|
|
|
1
|
-
# CSS Typed OM Polyfill
|
|
1
|
+
# Moonlight CSS Typed OM Polyfill
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
- [
|
|
12
|
+
- [核心进化](#核心进化)
|
|
13
|
+
- [支持的接口](#支持的接口)
|
|
10
14
|
- [安装](#安装)
|
|
11
15
|
- [基本用法](#基本用法)
|
|
12
|
-
- [
|
|
13
|
-
- [
|
|
14
|
-
- [
|
|
15
|
-
- [
|
|
16
|
-
|
|
17
|
-
- [
|
|
18
|
-
- [开发](#开发)
|
|
16
|
+
- [高级用法](#高级用法)
|
|
17
|
+
- [解析与严格模式](#解析与严格模式)
|
|
18
|
+
- [代数运算与优化](#代数运算与优化)
|
|
19
|
+
- [变换与矩阵 (Transforms)](#变换与矩阵-transforms)
|
|
20
|
+
- [性能哲学](#性能哲学)
|
|
21
|
+
- [局限性](#局限性)
|
|
19
22
|
- [许可证](#许可证)
|
|
20
23
|
|
|
21
24
|
## 简介
|
|
22
25
|
|
|
23
|
-
CSS Typed Object Model
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
*
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
*
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
* `
|
|
57
|
-
* `
|
|
58
|
-
* `
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
* `
|
|
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
|
-
|
|
68
|
+
直接在项目中引入 polyfill 脚本。它会自动检测原生支持,仅在必要时激活。
|
|
87
69
|
|
|
88
70
|
```html
|
|
89
|
-
<script src="
|
|
71
|
+
<script src="cssom.js"></script>
|
|
90
72
|
<script>
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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
|
-
###
|
|
81
|
+
### 操作 `attributeStyleMap`
|
|
105
82
|
|
|
106
83
|
```javascript
|
|
107
|
-
const
|
|
108
|
-
document.body.appendChild(element);
|
|
84
|
+
const el = document.getElementById('hero');
|
|
109
85
|
|
|
110
|
-
// 设置样式
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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 =
|
|
117
|
-
console.log(width.value); //
|
|
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()); // "
|
|
95
|
+
console.log(width.toString()); // "100px"
|
|
120
96
|
|
|
121
|
-
|
|
122
|
-
console.log(
|
|
97
|
+
// 类型检查
|
|
98
|
+
console.log(width instanceof CSSUnitValue); // true
|
|
123
99
|
```
|
|
124
100
|
|
|
125
|
-
###
|
|
101
|
+
### 使用工厂函数
|
|
126
102
|
|
|
127
103
|
```javascript
|
|
128
|
-
|
|
129
|
-
const
|
|
130
|
-
const
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
168
|
-
|
|
169
|
-
//
|
|
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
|
-
|
|
134
|
+
支持完整的变换对象模型和矩阵计算。
|
|
175
135
|
|
|
176
136
|
```javascript
|
|
177
|
-
|
|
178
|
-
const
|
|
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(
|
|
140
|
+
// 像数组一样访问
|
|
141
|
+
console.log(transform[0] instanceof CSSTranslate); // true
|
|
142
|
+
console.log(transform[1] instanceof CSSRotate); // true
|
|
188
143
|
|
|
189
|
-
//
|
|
190
|
-
|
|
191
|
-
console.log(
|
|
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
|
-
|
|
208
|
-
|
|
149
|
+
// 计算矩阵 (需要 DOMMatrix 支持)
|
|
150
|
+
const matrix = transform.toMatrix();
|
|
151
|
+
console.log(matrix.m11, matrix.m12, ...);
|
|
209
152
|
```
|
|
210
153
|
|
|
211
|
-
##
|
|
154
|
+
## 性能哲学
|
|
212
155
|
|
|
213
|
-
|
|
156
|
+
Moonlight 的设计遵循 **"Velocity" (极速)** 哲学:
|
|
214
157
|
|
|
215
|
-
|
|
216
|
-
|
|
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
|
-
|
|
165
|
+
尽管 Moonlight 非常强大,但由于缺乏浏览器的布局引擎上下文,仍存在物理局限:
|
|
235
166
|
|
|
236
|
-
|
|
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) - 献给所有追求极致的开发者。
|