摘要

  • W3C 2016 年 6 月首份公开草案提出通过 JavaScript 注册自定义属性,声明类型、初始值与继承方式;文中的颜色停靠点示例借此实现渐变动画。
  • 2019 年草案加入 CSS @property 写法。2024 年草案进一步解释计算值阶段的类型检查,以及同一注册名称在整个文档中的共同含义。

设计师手里有红色和绿色两个色样,希望渐变上的颜色停靠点用一秒钟从一端走到另一端。她把颜色放进 --stop-color,写了过渡。自定义属性接过两个值很爽快,浏览器却要回答一件更具体的事:红与绿之间每一帧该是什么?名字里写着 color 不等于类型声明。变量带着一箱值去面试,简历上的“专业技能”仍是空白;动画只好一步跨过所有中间色。

W3C 2016 年 6 月 7 日的首份公开草案给这张简历加了三栏:类型、初始值、继承行为。那时的入口是 JavaScript CSS.registerProperty()。草案示例把 --stop-color 注册为 <color>,设透明色为起点、inherits: false,再在悬停时把红色换成绿色。浏览器知道手里拿的是颜色,便能计算走过的色调。变量名称此前没有提供这项本领。

2017 年 11 月 9 日草案继续发展这种登记方式与类型动画。原件里的协议仍由 JavaScript 写给浏览器。今天更熟悉的 @property 规则,当时还不在这两份草案里。先出现的是“作者告诉浏览器值是什么”这件事;后出现的是“作者能否直接在 CSS 里讲清楚”。时间顺序决定了这段历史的重心。

到了 2019 年 10 月 25 日草案,门开了两扇:脚本中的 CSS.registerProperty(),样式表中的 @property。后者把 syntax、inherits、initial-value 写在使用该名字的样式附近。读者看到控制圆形大小的 --radius 时,也能看到它是长度、从零开始、默认不传给子元素。类型合同终于贴在工作台旁,不必跑到另一份脚本里找。

2020 年 10 月 13 日草案保留两种登记方式和动画示例。登记后的颜色可以经过其他颜色;登记后的长度可以经过其他长度。若 --radius 的类型是 <length>,画出来的圆便能从十像素长到五十像素,中途每帧都有可计算的半径。浏览器拿到的是量得出的数值,而不只是写着“小圆”“大圆”的两张纸条。

2024 年 3 月 26 日草案把这份合同的细节交代得更严。有效的 @property 需要 syntax 和 inherits;如果类型是明确的颜色、长度等,而非通配的 *,还须提供有效、可独立计算的 initial-value。这三项分别回答能收什么值、还没赋值时从哪里起步、子元素默认接不接手。必填栏空着,整条注册规则便无效。浏览器不会替变量编造职业资格。

类型检查发生在计算值时,而非 CSS 刚被读入时。草案解释了其中的成本:某个名称可能在声明已被解析之后才由脚本注册。若浏览器早早扔掉那些暂时不符合未知类型的声明,等注册到来时,只能把扔掉的东西全留着,或重新解析整份样式表。于是类型要在计算值阶段、var() 替换之前接受检查。就连面试也得约在正确的工位。

注册名称还有一层公共性。2024 年草案规定,文档中的注册映射共同适用,包括写在 Shadow DOM 内的规则。多个有效的同名 @property 规则,按样式表顺序由最后一条决定;JavaScript 对同名属性的注册又优先于这些规则。两个组件都把 --radius 当自己的私有变量,浏览器却只能依一份共同的类型合同工作。草案也说明这道取舍:组件想有自己的空间,外部页面又需要把经过类型检查的值送进去。

W3C 发布记录串起 2016、2017、2019、2020 与 2024 年的步骤。变量交出了类型、起点与继承规则,面试终于结束。红色到绿色的路,不必再靠一帧跳过去。