css-typed-om-polyfill 0.1.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/LICENSE +21 -0
- package/README.md +240 -0
- package/README.zh.md +240 -0
- package/css-typed-om-polyfill.js +1369 -0
- package/package.json +37 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 oy3o
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# CSS Typed OM Polyfill
|
|
2
|
+
|
|
3
|
+
A JavaScript polyfill for the [CSS Typed Object Model (OM) Level 1](https://www.w3.org/TR/css-typed-om/) specification. This polyfill aims to provide a functional subset of the CSS Typed OM API for browsers that do not natively support it, allowing developers to interact with CSS values as typed JavaScript objects.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Introduction](#introduction)
|
|
8
|
+
- [Features](#features)
|
|
9
|
+
- [Supported CSS Typed OM Interfaces](#supported-css-typed-om-interfaces)
|
|
10
|
+
- [Installation](#installation)
|
|
11
|
+
- [Basic Usage](#basic-usage)
|
|
12
|
+
- [Advanced Usage & Notes](#advanced-usage--notes)
|
|
13
|
+
- [Parsing CSS Values](#parsing-css-values)
|
|
14
|
+
- [`calc()` and Math Functions](#calc-and-math-functions)
|
|
15
|
+
- [Arithmetic Operations](#arithmetic-operations)
|
|
16
|
+
- [`var()` (CSS Variables)](#var-css-variables)
|
|
17
|
+
- [Limitations & To-Do](#limitations--to-do)
|
|
18
|
+
- [Development](#development)
|
|
19
|
+
- [License](#license)
|
|
20
|
+
|
|
21
|
+
## Introduction
|
|
22
|
+
|
|
23
|
+
The CSS Typed Object Model provides a way to manipulate CSS values in JavaScript with type awareness, rather than just dealing with strings. This can lead to more robust and performant code. This polyfill brings some of that power to environments lacking native support.
|
|
24
|
+
|
|
25
|
+
It focuses on parsing CSS strings into typed objects, performing arithmetic on numeric values, and providing the `element.attributeStyleMap` interface for getting and setting styles in a typed manner.
|
|
26
|
+
|
|
27
|
+
## Features
|
|
28
|
+
|
|
29
|
+
* **`HTMLElement.prototype.attributeStyleMap`:** Access and modify inline styles using a `StylePropertyMap`.
|
|
30
|
+
* **CSS Value Parsing:**
|
|
31
|
+
* `CSSStyleValue.parse(property, cssText)`: Parses a single CSS value string.
|
|
32
|
+
* `CSSStyleValue.parseAll(property, cssText)`: Parses a comma-separated list of CSS values.
|
|
33
|
+
* **Numeric Values:**
|
|
34
|
+
* `CSSNumericValue` (base class for numbers and units).
|
|
35
|
+
* `CSSUnitValue` (e.g., `10px`, `50%`, `3.14rad`).
|
|
36
|
+
* `CSS.*` factory functions (e.g., `CSS.px(10)`, `CSS.percent(50)`, `CSS.number(5)`).
|
|
37
|
+
* Arithmetic operations: `.add()`, `.sub()`, `.mul()`, `.div()`, `.negate()`, `.invert()`.
|
|
38
|
+
* Unit conversion: `.to('targetUnit')` for compatible types (e.g., `s` to `ms`).
|
|
39
|
+
* Type checking for math operations (e.g., `length + angle` is invalid).
|
|
40
|
+
* **Mathematical Expressions:**
|
|
41
|
+
* `CSSMathSum`, `CSSMathProduct`, `CSSMathNegate`, `CSSMathInvert`.
|
|
42
|
+
* `CSSMathMin`, `CSSMathMax`.
|
|
43
|
+
* Recursive parsing of `calc()`, `min()`, `max()` expressions, including nested functions and `var()`.
|
|
44
|
+
* **Other CSS Values:**
|
|
45
|
+
* `CSSKeywordValue` (e.g., `auto`, `inherit`, `initial`).
|
|
46
|
+
* `CSSVariableReferenceValue` (for `var(--custom-property)`).
|
|
47
|
+
* `CSSUnparsedValue` (for values not fully parsed or unsupported).
|
|
48
|
+
* **Stubbed/Partial Implementations:**
|
|
49
|
+
* `CSSImageValue` (basic stub, returns `url(...)` as string).
|
|
50
|
+
* `CSSPositionValue` (basic stub).
|
|
51
|
+
* `CSSTransformValue` and its components (`CSSTranslate`, `CSSRotate`, `CSSScale`) (basic stubs with constructors and `toString()`).
|
|
52
|
+
|
|
53
|
+
## Supported CSS Typed OM Interfaces
|
|
54
|
+
|
|
55
|
+
**Core Classes:**
|
|
56
|
+
* `CSSStyleValue` (Abstract Base)
|
|
57
|
+
* `CSSNumericValue` (Abstract Base for numeric types)
|
|
58
|
+
* `CSSUnitValue`
|
|
59
|
+
* `CSSKeywordValue`
|
|
60
|
+
* `CSSUnparsedValue`
|
|
61
|
+
* `CSSVariableReferenceValue`
|
|
62
|
+
|
|
63
|
+
**Math Classes (subclass `CSSNumericValue`):**
|
|
64
|
+
* `CSSMathValue` (Abstract Base)
|
|
65
|
+
* `CSSMathSum`
|
|
66
|
+
* `CSSMathProduct`
|
|
67
|
+
* `CSSMathNegate`
|
|
68
|
+
* `CSSMathInvert`
|
|
69
|
+
* `CSSMathMin`
|
|
70
|
+
* `CSSMathMax`
|
|
71
|
+
|
|
72
|
+
**Other (Stubbed/Partial):**
|
|
73
|
+
* `CSSImageValue`
|
|
74
|
+
* `CSSPositionValue`
|
|
75
|
+
* `CSSTransformValue`
|
|
76
|
+
* `CSSTransformComponent` (Abstract Base)
|
|
77
|
+
* `CSSTranslate`
|
|
78
|
+
* `CSSRotate`
|
|
79
|
+
* `CSSScale`
|
|
80
|
+
|
|
81
|
+
**Interfaces:**
|
|
82
|
+
* `StylePropertyMap` (via `element.attributeStyleMap`)
|
|
83
|
+
|
|
84
|
+
## Installation
|
|
85
|
+
|
|
86
|
+
Simply include the polyfill script in your HTML file before any scripts that use the CSS Typed OM API:
|
|
87
|
+
|
|
88
|
+
```html
|
|
89
|
+
<script src="css-typed-om-polyfill.js"></script>
|
|
90
|
+
<script>
|
|
91
|
+
// Your code using 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
|
+
}
|
|
97
|
+
</script>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The polyfill will automatically initialize and attach necessary properties to the global scope (`window`) and `HTMLElement.prototype`.
|
|
101
|
+
|
|
102
|
+
## Basic Usage
|
|
103
|
+
|
|
104
|
+
### Accessing `attributeStyleMap`
|
|
105
|
+
|
|
106
|
+
```javascript
|
|
107
|
+
const element = document.createElement('div');
|
|
108
|
+
document.body.appendChild(element);
|
|
109
|
+
|
|
110
|
+
// Set a style
|
|
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));
|
|
114
|
+
|
|
115
|
+
// Get a style
|
|
116
|
+
const width = element.attributeStyleMap.get('width'); // CSSUnitValue { value: 200, unit: "px" }
|
|
117
|
+
console.log(width.value); // 200
|
|
118
|
+
console.log(width.unit); // "px"
|
|
119
|
+
console.log(width.toString()); // "200px"
|
|
120
|
+
|
|
121
|
+
const opacity = element.attributeStyleMap.get('opacity'); // CSSNumericValue { _value: 0.5, _unitType: "number" }
|
|
122
|
+
console.log(opacity.toString()); // "0.5"
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Using `CSS.*` Factory Functions
|
|
126
|
+
|
|
127
|
+
```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)"
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Advanced Usage & Notes
|
|
138
|
+
|
|
139
|
+
### Parsing CSS Values
|
|
140
|
+
|
|
141
|
+
```javascript
|
|
142
|
+
// Parse a single value
|
|
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)" (negated second term)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const keyword = CSSStyleValue.parse('display', 'block');
|
|
152
|
+
console.log(keyword.value); // "block"
|
|
153
|
+
|
|
154
|
+
// Parse a list of values (e.g., for font-family)
|
|
155
|
+
const fontFamilies = CSSStyleValue.parseAll('font-family', '"Arial", sans-serif');
|
|
156
|
+
fontFamilies.forEach(font => console.log(font.toString()));
|
|
157
|
+
// Output:
|
|
158
|
+
// "Arial" (CSSUnparsedValue for the string)
|
|
159
|
+
// "sans-serif" (CSSKeywordValue)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### `calc()` and Math Functions
|
|
163
|
+
|
|
164
|
+
The polyfill includes a robust parser for `calc()`, `min()`, and `max()` expressions, respecting operator precedence and parentheses.
|
|
165
|
+
|
|
166
|
+
```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
|
+
// The internal structure will be a tree of CSSMathProduct, CSSMathSum, etc.
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Arithmetic Operations
|
|
173
|
+
|
|
174
|
+
`CSSNumericValue` and its subclasses support arithmetic. Operations involving different compatible units or `var()` will result in `CSSMathSum` or `CSSMathProduct` objects.
|
|
175
|
+
|
|
176
|
+
```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
|
+
// Addition
|
|
183
|
+
console.log(val1.add(val2).toString()); // "calc(10px + 2em)"
|
|
184
|
+
console.log(val1.add(CSS.px(5)).toString()); // "15px" (same unit)
|
|
185
|
+
|
|
186
|
+
// Subtraction
|
|
187
|
+
console.log(val3.sub(CSS.px(10)).toString()); // "calc(50% - 10px)"
|
|
188
|
+
|
|
189
|
+
// Multiplication
|
|
190
|
+
console.log(val1.mul(num).toString()); // "50px" (length * number = length)
|
|
191
|
+
console.log(val1.mul(CSS.percent(200)).toString()); // "calc(10px * 200%)" (length * percent)
|
|
192
|
+
|
|
193
|
+
// Division
|
|
194
|
+
console.log(val1.div(num).toString()); // "2px"
|
|
195
|
+
console.log(val1.div(CSS.px(2)).toString()); // "5" (length / length = number)
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### `var()` (CSS Variables)
|
|
199
|
+
|
|
200
|
+
`var()` expressions are parsed into `CSSVariableReferenceValue` objects. They can be used within math functions and arithmetic operations, remaining unresolved.
|
|
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"
|
|
206
|
+
|
|
207
|
+
const calcWithVar = CSS.px(10).add(myVar);
|
|
208
|
+
console.log(calcWithVar.toString()); // "calc(10px + var(--my-width, 100px))"
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Limitations & To-Do
|
|
212
|
+
|
|
213
|
+
This polyfill is a work in progress and does not cover the entire CSS Typed OM specification. Key limitations include:
|
|
214
|
+
|
|
215
|
+
* **`clamp()`:** Not currently supported in the math expression parser (will parse as `CSSUnparsedValue` if top-level, or throw error if inside `calc`).
|
|
216
|
+
* **Color Values:** Complex color functions (e.g., `rgb()`, `hsl()`, `color()`) are generally parsed as `CSSUnparsedValue`. Basic named colors might parse as `CSSKeywordValue`.
|
|
217
|
+
* **Detailed Transform Parsing:** While `CSSTransformValue` and component classes (`CSSTranslate`, `CSSRotate`, `CSSScale`) exist with constructors, the main `CSSStyleValue.parse` will return `CSSUnparsedValue` for transform function strings. You'd need to construct them manually.
|
|
218
|
+
* **`CSSNumericValue.equals()`:** Provides a simplified structural check, primarily via `toString()` comparison, which may not be robust for all mathematically equivalent but structurally different expressions.
|
|
219
|
+
* **Type System Nuances:** The `type()` method on math values attempts to determine the resulting type (e.g., `length`, `angle`, `percent`), but complex interactions, especially with `var()`, can lead to indeterminate types.
|
|
220
|
+
* **No Actual Value Computation:** The polyfill parses and represents CSS values and expressions. It does **not** compute the final used value of expressions (e.g., it won't resolve `calc(10px + 5%)` to a single pixel value, as that requires layout context).
|
|
221
|
+
* **Shorthand Properties:** `StylePropertyMap.get()` might return `null` or an unparsed value for shorthands if the browser doesn't expand them into longhands in `element.style`. The polyfill relies on what `element.style.getPropertyValue()` returns.
|
|
222
|
+
* **Limited Property-Specific Parsing:** `CSSStyleValue.parse(property, cssText)` does not currently use the `property` argument to guide parsing specific to that property's grammar (beyond basic distinctions).
|
|
223
|
+
|
|
224
|
+
**Future Enhancements (To-Do):**
|
|
225
|
+
* Implement `clamp()`.
|
|
226
|
+
* Improve parsing for color values.
|
|
227
|
+
* Full parsing of transform functions into `CSSTransformValue`.
|
|
228
|
+
* More robust `CSSNumericValue.equals()`.
|
|
229
|
+
* Support for more `CSSStyleValue` subclasses (e.g., `CSSSkew`, `CSSPerspective`, `CSSMatrixComponent`).
|
|
230
|
+
* Consider `CSSMathClamp`.
|
|
231
|
+
|
|
232
|
+
## Development
|
|
233
|
+
|
|
234
|
+
The code is contained within a single IIFE (Immediately Invoked Function Expression). The core parsing logic for math expressions is in `parseCssMathExpression`. `CSSStyleValue.parse` is the main entry point for parsing CSS text.
|
|
235
|
+
|
|
236
|
+
The script includes example usage code wrapped in a `setTimeout` at the end, which can be used for testing in a browser environment.
|
|
237
|
+
|
|
238
|
+
## License
|
|
239
|
+
|
|
240
|
+
[MIT](LICENSE)
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# CSS Typed OM Polyfill
|
|
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 值进行交互。
|
|
4
|
+
|
|
5
|
+
## 目录
|
|
6
|
+
|
|
7
|
+
- [简介](#简介)
|
|
8
|
+
- [特性](#特性)
|
|
9
|
+
- [支持的 CSS Typed OM 接口](#支持的-css-typed-om-接口)
|
|
10
|
+
- [安装](#安装)
|
|
11
|
+
- [基本用法](#基本用法)
|
|
12
|
+
- [高级用法与注意事项](#高级用法与注意事项)
|
|
13
|
+
- [解析 CSS 值](#解析-css-值)
|
|
14
|
+
- [`calc()` 与数学函数](#calc-与数学函数)
|
|
15
|
+
- [算术运算](#算术运算)
|
|
16
|
+
- [`var()` (CSS 变量)](#var-css-变量)
|
|
17
|
+
- [局限性与待办事项](#局限性与待办事项)
|
|
18
|
+
- [开发](#开发)
|
|
19
|
+
- [许可证](#许可证)
|
|
20
|
+
|
|
21
|
+
## 简介
|
|
22
|
+
|
|
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` 提供)
|
|
83
|
+
|
|
84
|
+
## 安装
|
|
85
|
+
|
|
86
|
+
只需在您的 HTML 文件中,在使用 CSS Typed OM API 的任何脚本之前引入 polyfill 脚本即可:
|
|
87
|
+
|
|
88
|
+
```html
|
|
89
|
+
<script src="path/to/css-typed-om-polyfill.js"></script>
|
|
90
|
+
<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
|
+
}
|
|
97
|
+
</script>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
polyfill 将自动初始化并将必要的属性附加到全局作用域 (`window`) 和 `HTMLElement.prototype`。
|
|
101
|
+
|
|
102
|
+
## 基本用法
|
|
103
|
+
|
|
104
|
+
### 访问 `attributeStyleMap`
|
|
105
|
+
|
|
106
|
+
```javascript
|
|
107
|
+
const element = document.createElement('div');
|
|
108
|
+
document.body.appendChild(element);
|
|
109
|
+
|
|
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));
|
|
114
|
+
|
|
115
|
+
// 获取样式
|
|
116
|
+
const width = element.attributeStyleMap.get('width'); // CSSUnitValue { value: 200, unit: "px" }
|
|
117
|
+
console.log(width.value); // 200
|
|
118
|
+
console.log(width.unit); // "px"
|
|
119
|
+
console.log(width.toString()); // "200px"
|
|
120
|
+
|
|
121
|
+
const opacity = element.attributeStyleMap.get('opacity'); // CSSNumericValue { _value: 0.5, _unitType: "number" }
|
|
122
|
+
console.log(opacity.toString()); // "0.5"
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 使用 `CSS.*` 工厂函数
|
|
126
|
+
|
|
127
|
+
```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)"
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## 高级用法与注意事项
|
|
138
|
+
|
|
139
|
+
### 解析 CSS 值
|
|
140
|
+
|
|
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
|
+
}
|
|
150
|
+
|
|
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()` 表达式的健壮解析器,它遵循运算符优先级和括号规则。
|
|
165
|
+
|
|
166
|
+
```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 等组成的树
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### 算术运算
|
|
173
|
+
|
|
174
|
+
`CSSNumericValue` 及其子类支持算术运算。涉及不同兼容单位或 `var()` 的运算将产生 `CSSMathSum` 或 `CSSMathProduct` 对象。
|
|
175
|
+
|
|
176
|
+
```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" (相同单位)
|
|
185
|
+
|
|
186
|
+
// 减法
|
|
187
|
+
console.log(val3.sub(CSS.px(10)).toString()); // "calc(50% - 10px)"
|
|
188
|
+
|
|
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"
|
|
206
|
+
|
|
207
|
+
const calcWithVar = CSS.px(10).add(myVar);
|
|
208
|
+
console.log(calcWithVar.toString()); // "calc(10px + var(--my-width, 100px))"
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## 局限性与待办事项
|
|
212
|
+
|
|
213
|
+
此 polyfill 尚在开发中,并未覆盖整个 CSS Typed OM 规范。主要局限性包括:
|
|
214
|
+
|
|
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` 参数来指导特定于该属性语法的解析(超出基本区分)。
|
|
223
|
+
|
|
224
|
+
**未来增强 (待办事项):**
|
|
225
|
+
* 实现 `clamp()`。
|
|
226
|
+
* 改进颜色值的解析。
|
|
227
|
+
* 将 transform 函数完整解析为 `CSSTransformValue`。
|
|
228
|
+
* 更健壮的 `CSSNumericValue.equals()`。
|
|
229
|
+
* 支持更多 `CSSStyleValue` 子类 (例如, `CSSSkew`, `CSSPerspective`, `CSSMatrixComponent`)。
|
|
230
|
+
* 考虑 `CSSMathClamp`。
|
|
231
|
+
|
|
232
|
+
## 开发
|
|
233
|
+
|
|
234
|
+
代码包含在一个 IIFE (立即调用函数表达式) 中。数学表达式的核心解析逻辑位于 `parseCssMathExpression` 中。`CSSStyleValue.parse` 是解析 CSS 文本的主要入口点。
|
|
235
|
+
|
|
236
|
+
脚本末尾包含一个用 `setTimeout` 包装的示例用法代码,可在浏览器环境中用于测试。
|
|
237
|
+
|
|
238
|
+
## 许可证
|
|
239
|
+
|
|
240
|
+
[MIT](LICENSE)
|