在前面的章节中,我们花了很多时间学习如何通过 CSSOM 操作样式——无论是操作样式表规则、修改内联样式,还是获取计算样式。但你可能已经注意到一个共同点:所有操作都是基于字符串的。
回想一下你写过的代码:
// 读取样式 —— 得到的是字符串
const width = element.style.width; // "200px"
const color = getComputedStyle(el).color; // "rgb(255, 0, 0)"
// 修改样式 —— 拼接字符串
element.style.width = (parseFloat(width) + 50) + 'px';
element.style.transform = 'translateX(' + x + 'px) rotate(' + deg + 'deg)';字符串本身没有问题——毕竟 CSS 在本质上就是文本。但当我们需要 计算、转换、运算 时,字符串就成了一个麻烦:你需要 parseFloat() 提取数字,需要手动拼接单位,需要小心翼翼地处理格式。
这就是 CSS 类型对象模型(CSS Typed Object Model,简称 CSS Typed OM) 要解决的问题。
CSS Typed OM 是 CSSOM 的一个现代化升级。它将 CSS 值暴露为 类型化的 JavaScript 对象 而不是字符串——数值就是真正的 JavaScript 数字,单位被单独保存,并且定义了单位感知的数学运算。这意味着你可以像操作普通数字一样操作 CSS 值,让代码更清晰、更可靠,也通常更快。
重要提示: CSS Typed OM 目前属于 渐进增强技术,尚未在所有主流浏览器中完全支持。本章的内容旨在让你了解这项前沿技术,并能够在支持的环境中使用它。在实际项目中,请务必做好降级方案。
一、为什么需要 Typed OM?
在深入具体 API 之前,我们先理解一个问题:传统的字符串操作方式到底有什么问题?
1.1 字符串操作 CSS 的痛点
痛点一:解析麻烦
从 CSS 值中提取数字需要手动解析:
// 传统方式:字符串解析
const style = getComputedStyle(element);
const widthStr = style.width; // "200.5px"
const width = parseFloat(widthStr); // 200.5 —— 还要手动提取
const unit = widthStr.replace(/[\d.]/g, ''); // "px" —— 还要手动提取单位
// 做运算后再拼回去
const newWidth = width + 50;
element.style.width = newWidth + 'px'; // 又要手动拼接单位每一步都涉及字符串操作,繁琐且容易出错。
痛点二:类型不安全
你无法在编译时(或运行时早期)发现类型错误。一个本该是数字的地方传入了字符串,可能要到样式不生效时才能发现:
// 没有人能阻止你这样做——直到样式出问题
element.style.width = 'hello'; // 不会报错,但样式无效
element.style.opacity = 'not a number'; // 同样的问题痛点三:单位混乱
不同属性使用不同的单位——width 用 px,font-size 用 em 或 rem,transform 用 deg。手动管理这些单位很容易混淆。
痛点四:复杂属性难以操作
像 transform 这样的属性,值可能包含多个函数(如 translateX(10px) rotate(45deg)),用字符串拼接和解析简直是噩梦。
1.2 Typed OM 的优势
CSS Typed OM 正是为解决这些问题而生的。
优势一:类型安全
数值就是数值,单位就是单位。JavaScript 引擎可以更好地理解和优化这些操作:
// Typed OM 方式:直接操作数值
element.attributeStyleMap.set('width', CSS.px(200));
// 宽度就是 200px,清晰明了优势二:单位感知
单位被保留为对象的一部分,你可以进行单位感知的运算:
const width = CSS.px(200);
const newWidth = width.add(CSS.px(50)); // CSS.px(250)
// 不同单位不能直接相加——类型系统会阻止错误优势三:性能更好
传统的字符串操作需要反复构建和解析 CSS 字符串,而 Typed OM 允许直接操作底层值,然后廉价地转换回去。
优势四:代码更可维护
操作 CSS 值的逻辑变得更清晰、更可读,减少了字符串拼接带来的“魔法代码”。
二、核心接口
CSS Typed OM 提供了一套完整的接口体系。我们来逐一认识它们。
2.1 CSSStyleValue —— 所有 CSS 值的基类
CSSStyleValue 是 CSS Typed OM API 的 基类,所有可通过 Typed OM 访问的 CSS 值都继承自它。
简单理解:CSSStyleValue 就像是所有“类型化 CSS 值”的根。它的子类包括:
CSSNumericValue:带单位的数值(如 200px、50%)。
CSSKeywordValue:关键字值(如 auto、red)。
CSSTransformValue:变换值(如 translateX(10px))。
CSSUnparsedValue:未解析的值(如包含自定义属性的值)。
一个 CSSStyleValue 的实例可以在任何期望字符串的地方使用——这为渐进增强提供了便利。
2.2 CSSStyleValue.parse() 与 parseAll() —— 从字符串到类型化对象
有时候你已经有 CSS 字符串了(比如从 getComputedStyle 读取到的值),想把它转换成类型化的对象。这时候就用到了 parse() 和 parseAll()。
CSSStyleValue.parse(property, cssText) :解析一个 CSS 属性值,返回第一个匹配的 CSSStyleValue 对象。
// 从字符串解析出类型化的 CSS 值
const value = CSSStyleValue.parse('width', '200px');
console.log(value); // CSSNumericValue { value: 200, unit: 'px' }
// 可以直接使用
element.attributeStyleMap.set('width', value);CSSStyleValue.parseAll(property, cssText) :解析一个 CSS 属性值,返回所有匹配的 CSSStyleValue 对象数组。
// 对于可以接受多个值的属性(如 background)
const values = CSSStyleValue.parseAll('background-image', 'url(a.png), url(b.png)');
console.log(values.length); // 2
console.log(values[0]); // CSSImageValue这两个方法是从“字符串世界”通往“类型化世界”的桥梁。
2.3 StylePropertyMap —— CSS 声明块的新表示
StylePropertyMap 是 CSS Typed OM 中 最重要的接口之一。它提供了一种全新的方式来操作元素的样式声明,是传统 CSSStyleDeclaration(也就是 element.style)的替代方案。
要使用 StylePropertyMap,你需要通过元素的 attributeStyleMap 属性来访问它:
// 传统方式:CSSStyleDeclaration
element.style.width = '200px';
element.style.backgroundColor = 'blue';
// Typed OM 方式:StylePropertyMap
element.attributeStyleMap.set('width', CSS.px(200));
element.attributeStyleMap.set('background-color', CSS.color('blue'));StylePropertyMap 提供了以下核心方法:
set(property, value) —— 设置一个 CSS 属性的值,会 覆盖 已有值:
// 设置单个值
element.attributeStyleMap.set('width', CSS.px(200));
// 设置多个值(如 background-image 可以有多层)
element.attributeStyleMap.set('background-image', [
CSS.url('image1.png'),
CSS.url('image2.png')
]);append(property, value) —— 向一个已有属性 追加 值(而不是覆盖):
// 第一次设置
element.attributeStyleMap.set('transform', CSS.translate(10, 10));
// 追加一个旋转 —— 现在 transform 有两个值
element.attributeStyleMap.append('transform', CSS.rotate(45));
// 等价于 CSS: transform: translate(10px, 10px) rotate(45deg);delete(property) —— 删除指定属性的声明:
element.attributeStyleMap.delete('width');
// 相当于 element.style.width = '';clear() —— 删除所有声明:
element.attributeStyleMap.clear();
// 相当于 element.style = '';get(property) 和 getAll(property) —— 读取属性值:
// 获取单个值(如果属性有多个值,返回第一个)
const width = element.attributeStyleMap.get('width');
console.log(width.value); // 200
console.log(width.unit); // 'px'
// 获取所有值(返回数组)
const transforms = element.attributeStyleMap.getAll('transform');
transforms.forEach(t => console.log(t.toString()));2.4 关于 computedStyleMap()
除了 attributeStyleMap (操作内联样式),CSS Typed OM 还提供了 computedStyleMap() 方法,用于获取元素的 计算样式(相当于 getComputedStyle 的类型化版本)。
// 传统方式:getComputedStyle 返回字符串
const styles = getComputedStyle(element);
const width = styles.width; // "200px" —— 字符串
// Typed OM 方式:computedStyleMap 返回类型化对象
const styleMap = element.computedStyleMap();
const width = styleMap.get('width'); // CSSNumericValue { value: 200, unit: 'px' }
console.log(width.value); // 200 —— 真正的数字!computedStyleMap() 返回的是一个 StylePropertyMapReadOnly 对象——顾名思义,它是只读的,只能用来读取计算样式,不能修改。
你还可以遍历 StylePropertyMapReadOnly 来查看元素的所有计算样式:
const styleMap = element.computedStyleMap();
for (const [prop, val] of styleMap) {
console.log(`${prop}: ${val}`);
}2.5 CSSUnparsedValue —— 处理自定义属性
CSS 自定义属性(CSS Variables)的值在 Typed OM 中由 CSSUnparsedValue 表示。
自定义属性的值可能包含变量引用(如 var(--foo)),这些值在解析之前是“未解析的”。CSSUnparsedValue 就是用来表示这种状态的。
// 设置一个包含自定义属性的值
element.attributeStyleMap.set('--theme-color', 'var(--base-color)');
// 读取它
const value = element.attributeStyleMap.get('--theme-color');
console.log(value instanceof CSSUnparsedValue); // true
console.log(value.toString()); // 'var(--base-color)'CSSUnparsedValue 是可变的——你可以在它上面进行操作,修改其中的片段或变量引用。
2.6 CSSTransformValue —— 表示 transform 属性
transform 属性在 CSS 中非常特殊——它可以包含多个变换函数(如 translate、rotate、scale 等),每个函数又有自己的参数。用字符串来操作 transform 一直是个痛点。
CSSTransformValue 就是专门用来表示 transform 属性值的。
// 创建一个 transform 值:translate(10px, 20px) rotate(45deg)
const transform = new CSSTransformValue([
CSS.translate(CSS.px(10), CSS.px(20)),
CSS.rotate(CSS.deg(45))
]);
// 设置到元素上
element.attributeStyleMap.set('transform', transform);
// 读取并操作
const current = element.attributeStyleMap.get('transform');
console.log(current.length); // 2 —— 有两个变换函数
console.log(current.is2D); // true —— 这是 2D 变换
// 添加一个新的变换
current.append(CSS.scale(1.5));
// 现在 transform 有三个函数了CSSTransformValue 的实例属性包括:
length:变换函数的数量(只读)。
is2D:是否是 2D 变换(只读)。
它还有一个实用的方法 toMatrix(),可以将变换转换为 DOMMatrix 对象——这对于需要进行矩阵运算的场景非常有用。
三、浏览器支持与渐进增强策略
正如本章开头提到的,CSS Typed OM 目前尚未在所有主流浏览器中得到完全支持。
当前支持状况
截至 2026 年 6 月:
Chrome / Edge:105+ 版本默认启用。
Safari:需要手动开启(开发 → 实验性功能 → CSS Typed OM)
Firefox:目前仍不支持 attributeStyleMap,仅有部分 computedStyleMap 实验性接口可用。
如何检测 Typed OM 是否可用
在实际项目中使用前,建议先进行特性检测:
function isTypedOMSupported() {
return window.CSS &&
typeof CSS.px === 'function' &&
Element.prototype.attributeStyleMap !== undefined;
}
if (isTypedOMSupported()) {
// 使用 Typed OM
element.attributeStyleMap.set('width', CSS.px(200));
} else {
// 降级到传统方式
element.style.width = '200px';
}渐进增强的实践建议
1. 特性检测是必须的:永远不要假设 Typed OM 可用,先用 if 判断再使用。
2. 封装一个样式操作工具:将 Typed OM 和传统方式封装在一个函数中,业务代码无需关心底层实现:
function setStyle(element, property, value) {
if (isTypedOMSupported()) {
// 假设 value 是 CSS.px(200) 这样的类型化对象
element.attributeStyleMap.set(property, value);
} else {
// 降级:value 应该是字符串如 '200px'
element.style[property] = value;
}
}3. 注意环境要求:Typed OM 需要在 HTTPS 或 localhost 协议下运行。
4. 不要在生产环境中强制依赖:除非你的目标用户群体明确使用支持 Typed OM 的浏览器,否则始终提供降级方案。
四、完整示例
下面是一个综合示例,展示 Typed OM 的完整使用流程:
<style>
.box {
width: 100px;
height: 100px;
background: #007bff;
transition: all 0.3s ease;
}
</style><div class="box" id="box"></div>
<button id="animateBtn">动画</button><script>
const box = document.getElementById('box');
const btn = document.getElementById('animateBtn');
// 1. 检测 Typed OM 是否可用
function isTypedOMSupported() {
return window.CSS &&
typeof CSS.px === 'function' &&
Element.prototype.attributeStyleMap !== undefined;
}
// 2. 封装样式操作
function setTypedStyle(element, property, value) {
if (isTypedOMSupported()) {
element.attributeStyleMap.set(property, value);
} else {
// 降级:需要传入字符串
element.style[property] = value.toString ? value.toString() : value;
}
}
// 3. 读取计算样式(类型化方式)
function getComputedTyped(element, property) {
if (isTypedOMSupported()) {
return element.computedStyleMap().get(property);
} else {
return getComputedStyle(element)[property];
}
}
// 4. 点击按钮执行动画
btn.addEventListener('click', function() {
if (isTypedOMSupported()) {
// Typed OM 方式:类型化操作
const currentWidth = box.computedStyleMap().get('width');
const newWidth = CSS.px(currentWidth.value + 50);
box.attributeStyleMap.set('width', newWidth);
// transform 使用 CSSTransformValue
const rotation = CSS.deg(45);
const transform = new CSSTransformValue([
CSS.rotate(rotation)
]);
box.attributeStyleMap.set('transform', transform);
// 背景色
box.attributeStyleMap.set('background-color', CSS.color('tomato'));
console.log('新宽度:', box.attributeStyleMap.get('width').value + 'px');
} else {
// 降级:传统字符串方式
const currentWidth = parseFloat(getComputedStyle(box).width);
box.style.width = (currentWidth + 50) + 'px';
box.style.transform = 'rotate(45deg)';
box.style.backgroundColor = 'tomato';
}
});
// 5. 控制台测试
console.log('Typed OM 可用:', isTypedOMSupported());
if (isTypedOMSupported()) {
const allStyles = box.computedStyleMap();
console.log('所有计算样式:');
for (const [prop, val] of allStyles) {
console.log(` ${prop}: ${val}`);
}
}
</script>这个示例展示了:
Typed OM 可用性的检测。
带降级的样式操作封装。
attributeStyleMap 设置样式。
computedStyleMap() 读取计算样式。
CSSTransformValue 操作 transform。
与传统方式的对比。
五、小结
本章我们学习了 CSS 类型对象模型(CSS Typed OM)——CSSOM 的现代化升级:
1. 为什么需要 Typed OM
传统字符串操作 CSS 存在诸多痛点:解析麻烦、类型不安全、单位混乱、复杂属性难以操作。
Typed OM 的优势:类型安全、单位感知、性能更好、代码更可维护。
2. 核心接口
CSSStyleValue:所有 Typed OM CSS 值的基类。
CSSStyleValue.parse() / parseAll():从 CSS 字符串解析为类型化对象。
StylePropertyMap:通过 element.attributeStyleMap 访问,提供 set()、append()、delete()、clear() 等方法。
computedStyleMap():获取计算样式的类型化版本,返回 StylePropertyMapReadOnly。
CSSUnparsedValue:表示包含自定义属性的值。
CSSTransformValue:表示 transform 属性值,支持 length、is2D 属性和 toMatrix() 方法
3. 浏览器支持与渐进增强
目前 Chrome/Edge 105+ 默认支持,Safari 需手动开启,Firefox 支持有限。
务必使用特性检测并提供降级方案。
适合作为渐进增强技术使用,不应强制依赖。
CSS Typed OM 代表了 CSS 操作的发展方向。虽然目前还不能在所有项目中全面使用,但了解它、在合适的场景中尝试它,会让你走在技术前沿。随着浏览器支持的不断完善,它终将成为前端开发者的标准工具。
至此,我们完成了 CSSOM 系列的七章内容——从 CSSOM 概览到样式表获取、规则操作、内联样式、计算样式、CSSOM View,再到 CSS Typed OM。你已掌握了从“读取样式”到“修改样式”、从“字符串操作”到“类型化操作”的完整知识体系。