Houdini - 揭秘 CSS

您有没有想过 CSS 所做的工作量很大?您更改了单个 属性,您的整个网站会突然以不同的布局显示。时间是 魔法。到目前为止,我们 - 网络开发者社区 只能目睹并观察魔法。如果我们想提出 自己的魔法?如果我们想成为魔术师,该怎么办?

胡迪尼上场!

Houdini 任务组由来自 Mozilla、Apple、Opera、 微软、惠普、Intel 和 Google 共同合作,公开了 Web 开发者的 CSS 引擎。该任务小组正在收集 目的是让 W3C 能够接受这些草稿 标准。他们设定了几个宏观的目标,最终变成了 而这也催生了一系列支持 较低级别的规范草案

当有人谈论提及这些草稿时,通常意味着 “Houdini”。在撰写本文时,草稿列表为 而且有些草稿只是占位符

规范

Worklet(规范

Worklet 本身的用处并不大。它们是一个概念, 以便日后的许多初稿成为可能当您想到 Web Workers 读“worklet”,没有错。它们在概念上有很多重叠。为什么 一种新事物呢?

Houdini 的目标是公开新的 API, 可让网络开发者将自己的代码连接到 CSS 引擎和 环境假设其中一些 每个代码段都必须运行一次。。帧。其中一些人不得不 它的定义引用 Web Worker 规范

<ph type="x-smartling-placeholder">

这意味着 Web Worker 无法实现 Houdini 计划要做的事情。 因此,我们发明了 Worklet。Worklet 使用 ES2015 类来定义 方法的集合,这些方法的签名由 Worklet 的类型。它们是轻量级的,而且生命周期很短。

CSS Paint API(规范

在 Chrome 65 中,Paint API 默认处于启用状态。阅读 详细说明

合成器 Worklet

此处介绍的 API 已过时。合成器 Worklet 经过重新设计,现建议为“动画 Worklet”。阅读更多 API 的当前迭代

尽管合成器 Worklet 规范已移至 WICG 中, 它的规格最让我感到兴奋。部分 操作都由 CSS 提供商外包到您计算机的显卡上 但这取决于您的显卡和设备 。

浏览器通常会采用 DOM 树,并根据特定条件 决定为一些分支和子树提供自己的层。 这些子树会自行绘制到其上(可能会使用 )。最后,将所有这些现在已绘制的图层堆叠在一起, 并将它们叠放在一起,遵从 Z 轴索引、3D 转换和 这样才能生成屏幕上可见的最终图像。此过程 称为合成,并由合成器执行。

合成过程的优点是 这些元素会在页面稍微滚动时重新绘制相反, 可以重复使用前一帧中的层,只需使用以下代码重新运行合成器 更新后的滚动位置。这样可以提高速度。这有助于我们达到 60fps。

合成器 Worklet。

顾名思义,合成器 Worklet 可让您连接到合成器 并影响已绘制的元素层 放置在其他层之上。

想要多一点 您可以告诉浏览器,您想连接到合成视频 特定 DOM 节点的进程,并且可以请求访问某些属性,例如 滚动位置 transformopacity。这会强制该元素 自己的层,并且在每一帧上调用您的代码。你可以移动图层 方法是处理层来转换和更改其属性(例如 opacity) 可让您以 60 fps 的速度进行花哨的炫酷操作。

以下是使用合成器实现视差滚动的完整实现 Worklet。

// main.js
window.compositorWorklet.import('worklet.js')
    .then(function() {
    var animator = new CompositorAnimator('parallax');
    animator.postMessage([
        new CompositorProxy($('.scroller'), ['scrollTop']),
        new CompositorProxy($('.parallax'), ['transform']),
    ]);
    });

// worklet.js
registerCompositorAnimator('parallax', class {
    tick(timestamp) {
    var t = self.parallax.transform;
    t.m42 = -0.1 * self.scroller.scrollTop;
    self.parallax.transform = t;
    }

    onmessage(e) {
    self.scroller = e.data[0];
    self.parallax = e.data[1];
    };
});

Robert Flack 为 因此你可以试一试 性能提升幅度

布局 Worklet(规范

第一个真正的规范草稿已提出。实施 好不好。

同样,此规范实际上是空的,但其概念 引人入胜:自行编写布局!布局 Worklet 应该可以让您 display: layout('myLayout') 并运行 JavaScript,以排列节点的 所有子节点

当然,运行 CSS flex-box 布局的完整 JavaScript 实现 比运行等效的原生实现要慢一些, 设想在这样一种情形下,切断行动可以带来更好的效果。设想一下 只用瓷砖(如 Windows 10 或砖石结构)建造而成的网站, 布局。不使用绝对定位和固定定位,z-index 和 元素曾经重叠或者有边框或溢出。能够跳过 所有这些对重新布局的检查都可能带来性能提升。

registerLayout('random-layout', class {
    static get inputProperties() {
        return [];
    }
    static get childrenInputProperties() {
        return [];
    }
    layout(children, constraintSpace, styleMap) {
        const width = constraintSpace.width;
        const height = constraintSpace.height;
        for (let child of children) {
            const x = Math.random()*width;
            const y = Math.random()*height;
            const constraintSubSpace = new ConstraintSpace();
            constraintSubSpace.width = width-x;
            constraintSubSpace.height = height-y;
            const childFragment = child.doLayout(constraintSubSpace);
            childFragment.x = x;
            childFragment.y = y;
        }

        return {
            minContent: 0,
            maxContent: 0,
            width: width,
            height: height,
            fragments: [],
            unPositionedChildren: [],
            breakToken: null
        };
    }
});

类型化 CSSOM(规范

<ph type="x-smartling-placeholder">

类型化 CSSOM(CSS 对象模型或层叠样式表对象模型) 我们可能都遇到过,刚刚学会忍受的问题。 让我们用一行 JavaScript 来说明一下:

    $('#someDiv').style.height = getRandomInt() + 'px';

我们正在进行数学运算,将数字转换为字符串,然后在后面附加一个单位, 浏览器会解析该字符串,并将其转换回供 CSS 引擎使用的数字。 如果使用 JavaScript 操控转换,情况会更糟。 不行了!CSS 即将进行一些输入。

此草稿是较成熟的草稿之一,而 polyfill 。(免责声明:使用 polyfill 会增加更多计算开销。重点在于展示 API 是的。)

您将处理元素的 StylePropertyMap,而不是字符串,其中 每个 CSS 属性都有自己的键和对应的值类型。属性 (例如 width)使用 LengthValue 作为其值类型。LengthValue是 包含所有 CSS 单元(例如 emrempxpercent 等)的字典。设置 height: calc(5px + 5%) 会生成 LengthValue{px: 5, percent: 5}。部分 像 box-sizing 这样的属性只接受特定的关键字,因此具有 KeywordValue 值类型。然后可以检查这些属性的有效性 。

<div style="width: 200px;" id="div1"></div>
<div style="width: 300px;" id="div2"></div>
<div id="div3"></div>
<div style="margin-left: calc(5em + 50%);" id="div4"></div>
var w1 = $('#div1').styleMap.get('width');
var w2 = $('#div2').styleMap.get('width');
$('#div3').styleMap.set('background-size',
    [new SimpleLength(200, 'px'), w1.add(w2)])
$('#div4')).styleMap.get('margin-left')
    // => {em: 5, percent: 50}

属性和值

规范

您是否了解 CSS 自定义属性(或其非官方别名“CSS 变量”)? 这些只不过是类型而已!到目前为止,变量只能包含字符串值, 他们采用了简单的搜索并替换方法。此草稿不支持 您只为变量指定类型,但还需要定义默认值和 使用 JavaScript API 影响继承行为。从技术上讲 还可以使自定义属性通过标准 CSS 过渡获得动画效果 和动画,我们也在考虑这方面的内容。

["--scale-x", "--scale-y"].forEach(function(name) {
document.registerProperty({
    name: name,
    syntax: "<number>",
    inherits: false,
    initialValue: "1"
    });
});

字体指标

字体指标正如其名。什么是边界框(或 以 Z 大小呈现字体 Y 的字符串 X 时,会发生什么情况?如果我使用 Ruby 注解?这一要求的数量越来越多,Houdini 最终应该 让这些愿望得以实现

但不止如此!

Houdini 的草稿列表中还有更多规范, 也并不只是想法的占位图片。 示例包括:自定义溢出行为、CSS 语法扩展 API、扩展 以及具有类似目标的功能,所有这些都可以 在 Web 平台上实现前所未有的广阔体验。

演示

我已开放演示代码的源代码 (使用 polyfill 的实时演示)。