我帮助编写技术文档,今年我一直在撰写的一项非常突出的功能是类型化对象模型 (或类型化 OM)。如果您还没有遇到它,那也情有可原,因为它相当新。它属于CSS Houdini API 套件,表面上看起来并不那么令人兴奋。但是,它支撑着所有这些 API,并最终将改变我们对 CSS 作为一种语言的看法。
它允许在 CSS 中对值进行类型化。请记住 CSS 的基本语法
selector {
property: value;
}
该值可以是很多东西,颜色、单位、图像、文字。这对 CSS 来说是有意义的,但对我们来说,当我们访问它并尝试通过任何方式更改它时,它会以字符串的形式出现。
类型化 OM 允许将其作为类型返回。因此,如果我们要在 JavaScript 中访问例如10px
,则不会返回'10px'
,而是获得数字10
和单位'px'
。这更容易处理。
您可能已经看到了一些 Ana Tudor 令人惊叹的演示。在她的“Hollow”示例中,她在 JavaScript 中注册自定义属性以在她的 CSS 中使用。她正在使用属性和值 API,因此可以确定这些属性的类型。如果没有类型化 OM,这是不可能的。
举个例子
从表面上看,这似乎比我们目前习惯的访问和设置样式的方式要多做一些工作,但它有很多好处。如果我们想要获取元素的宽度,我们会执行以下操作
const elementWidth = getComputedStyle(myElement).width;
// returns '300px'
我们不仅在这里访问字符串,而且getComputedStyle
会强制重新布局。我们可能不知道使用了哪些单位,因此访问字符串的数字部分变得很棘手,如果我们在代码中多次运行此操作,可能会损害性能。
如果我们想使用类型化 OM 并返回类型化值,则必须通过computedStyleMap()
及其get()
方法访问属性和值
const elementWidth = myElement.computedStyleMap().get('width');
// returns CSSUnitValue {value: 300, type: 'px'}
现在我们可以分别访问值和单位,并且此处的返回值为整数。
elementWidth.value // 300
elementWidth.unit // 'px'
我们也没有强制重新布局,这绝对是一件好事。你可能现在在想,是的,我们不仅可以将 CSS 值作为类型访问,还可以通过全局CSS
对象非常轻松地创建单位值
let newWidth = CSS.px(320);
// returns CSSUnitValue {value: 320, type: 'px'}
这是一个简单的示例,并且易于展示,因为规范的单位部分已针对其他一些值类型进行了相当大的完善。但无论如何,它减少了许多字符串匹配和灵活性。
另一组规范良好的值是转换值:translate
、rotate
、scale
等。这很棒,因为如果我们想在没有类型化 OM 的情况下更改元素上的其中一个值,这可能很棘手,尤其是在我们设置了多个值时。
.myElement {
transform: rotate(10deg) scale(1.2);
}
假设我们想增加旋转。如果我们使用getComputedStyle()
访问此属性,则会返回一个矩阵。
const transform = getComputedStyle(myElement).transform;
// returns matrix(0.984808, 0.173648, -0.173648, 0.984808, 0, 0)
对于元素上具有的转换,我们不可能从矩阵中提取一个值。我不会在这里详细介绍向量、标量值和点积,但总而言之,一旦矩阵形成,您就无法提取一个值。肯定会有很多映射。
如果您只有一个转换或缩放,则可以通过字符串匹配值在矩阵中的位置来实现。但那是以后再讨论的信息。
我们可以使用自定义属性来设置这些转换的值并更新它们
.myElement {
--rotate: 10deg;
transform: rotate(var(--rotate)) scale(1.2);
}
myElement.style.setProperty('--rotate', '15deg');
但是,我们需要知道自定义属性的名称,并且我们仍然传入字符串。
输入类型化 OM。让我们看看computedStyleMap
返回的内容
myElement.computedStyleMap().get('transform');
/* returns
CSSTransformValue {
0: CSSRotate {...}
1: CSSScale {...}
} */
每个转换值都有自己的类型。对于上面的代码,有CSSRotate
和CSSScale
。以及所有其他类型,如倾斜和平移。因此,我们可以创建这些类型并使用它们应用CSSTransformValue
,而不是处理矩阵或仍然使用字符串。
const newTransform = new CSSTransformValue([
new CSSRotate(CSS.deg(15)),
new CSSScale(CSS.number(1.2), CSS.number(1.2))
])
myElement.attributeStyleMap.set('transform', newTransform);
请注意,我们是如何使用类方法和new
关键字创建转换类型的,而不是使用数值使用的工厂方法。
我们可以更好地控制每个单独的值,这在我们声明多个 CSS 值时非常需要。
它是基础
随着我们开始更加熟悉 Houdini 套件中的其他 API,所有这一切的好处将变得更加明显。例如,当我们使用属性和值 API 声明新的自定义属性时,我们会设置类型并获得自动错误处理。这些值类型也会传递到 Paint API 和 Layout API 的工作线程中,因此我们也可以在那里使用它的功能。
还有更多我没有提到的类型,还有更多即将推出的类型,以及更多需要撰写的内容。如果还没有,类型化 OM 目前正在所有主要浏览器中实施。它确实激发了我在今年的兴趣,因此请留意 2020 年的到来!
感谢您提供的清晰示例,这确实有助于了解此新 API 的潜力——肯定会有用。干杯!