Houdini - CSS に関する誤解の解消

CSS の作業量について考えたことはありますか?1 つの属性を変更すると、突然ウェブサイト全体が別のレイアウトで表示されます。これは魔法のようなものです。私たちウェブ開発者のコミュニティはこれまで、 その魔法を目の当たりにし、観察できただけです。独自の魔法を考案したい場合は どうすればよいでしょうかマジシャンになりたいとしたら?

Houdini に登場!

Houdini のタスクフォースは Mozilla、Apple、Opera、Microsoft、HP、Intel、Google のエンジニアが連携し、CSS エンジンの特定部分をウェブ デベロッパーに公開しています。このタスクフォースは、W3C に承認されて実際のウェブ標準になることを目指して、ドラフトのコレクションに取り組んでいます。チームはいくつかの上位レベルの目標を設定し、それを仕様のドラフトに変換し、それからサポートの下位レベルの仕様のドラフトを作成しました。

これらのドラフトのコレクションは、通常、誰かが「Houdini」について話すときに使用されます。このドキュメントの作成時点では、ドラフトのリストは完全ではなく、一部のドラフトは単なるプレースホルダです。

仕様

ワークレット(spec

ワークレットだけではあまり役に立ちません。これらは今後の下書きの多くを 実現するために導入されたコンセプトです「ワークレット」と聞いてウェブワーカーを思い浮かべたならば 間違いではありませんコンセプトは重複する部分が多くあります。では なぜすでにワーカーがあるのに 新しいものを作り出すのでしょうか

Houdini の目標は、新しい API を公開して、ウェブ デベロッパーが独自のコードを CSS エンジンと周辺システムにフックできるようにすることです。これらのコード フラグメントの一部が単一のフレームごとに実行しなければならないと考えるのは、おそらく非現実的ではありません。定義上必要なものもあります。ウェブワーカーの仕様の引用:

つまり、Web ワーカーは Houdini の計画を実行に移すことができません。そのため、ワークレットが考案されました。ワークレットは、ES2015 クラスを利用してメソッドのコレクションを定義します。メソッドのシグネチャは、ワークレットのタイプによって事前定義されています。軽量で短命です。

CSS Paint API(spec

Chrome 65 では、Paint API がデフォルトで有効になっています。詳細な概要を読む。

コンポジタ ワークレット

ここで説明する API は古いものです。コンポジタ ワークレットは再設計され、「アニメーション ワークレット」として提案されました。詳細については、現在の API のイテレーションをご覧ください。

コンポジタ ワークレットの仕様は WICG に移行され、イテレーションされる予定ですが、この仕様が最も興味をそそります。一部の処理は CSS エンジンによってパソコンのグラフィック カードにアウトソーシングされますが、通常はグラフィック カードとデバイスの両方に依存します。

通常、ブラウザは DOM ツリーを取得し、特定の基準に基づいて、ブランチやサブツリーに独自のレイヤを設けることを決定します。これらのサブツリーは自身を描画します(将来的にはペイント ワークレットが使用される可能性があります)。最後のステップとして、ペイントされたこれらの個々のレイヤがすべてスタックされ、Z インデックスや 3D 変換などを考慮して重ねられて、画面に表示される最終画像が生成されます。このプロセスは合成と呼ばれ、コンポジタによって実行されます。

合成プロセスの利点は、ページが少しスクロールしたときにすべての要素を再描画する必要がないことです。代わりに、前のフレームのレイヤを再利用し、更新されたスクロール位置でコンポジタを再実行できます。処理が速くなります。これにより 60 fps を達成できます。

コンポジタ ワークレット。

その名前が示すように、コンポジタ ワークレットを使用すると、コンポジタに接続し、すでにペイントされている要素のレイヤを他のレイヤの上に配置してレイヤ化する方法に影響を与えることができます。

もう少し具体的に説明すると、特定の DOM ノードの合成プロセスにフックし、スクロール位置、transformopacity などの特定の属性へのアクセスをリクエストできることをブラウザに伝えます。これにより、この要素は専用のレイヤと、コードが呼び出される各フレームに強制的に適用されます。レイヤ変換を操作することでレイヤを移動し、その属性(opacity など)を変更することで、60 fps で華やかな処理を行うことができます。

コンポジタ ワークレットを使用した視差スクロールの完全な実装を次に示します。

// 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 が作成したコンポジタ ワークレットのpolyfillを試してみましょう。明らかにパフォーマンスへの影響が大幅に高くなります。

レイアウト ワークレット(spec

最初の実際の仕様ドラフトが提案されました。実装まで少し時間がかかります

この仕様は実質的に空ですが、コンセプトは魅力的です。つまり、独自のレイアウトを記述するのです。レイアウト ワークレットは、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(spec

型指定 CSSOM(CSS オブジェクト モデルまたはカスケーディング スタイル シート オブジェクト モデル)は、誰もが直面し、最近学習した問題に対応するものです。JavaScript の例で説明します。

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

ここでは数値を文字列に変換して単位を追加し、ブラウザでその文字列を解析し、CSS エンジンで使用する数値に変換します。これは、JavaScript で変換を操作すると、さらに難しくなります。いやだ!CSS が入力しようとしています。

このドラフトは、より成熟したドラフトの 1 つで、polyfillはすでに開発中です。(免責条項: ポリフィルを使用すると、明らかに計算上のオーバーヘッドがさらに増加します。その API の便利さを示すことがポイントです)。

文字列ではなく、要素の StylePropertyMap を使用します。各 CSS 属性には、独自のキーと対応する値の型があります。width などの属性には、値の型として LengthValue があります。LengthValue は、emrempxpercent など、すべての CSS ユニットの辞書です。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}

プロパティと値

(spec)

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、ネイティブのスクロール動作の拡張などが挙げられます。これらはすべて、以前は不可能だったウェブ プラットフォームで実現できたものです。

デモ

デモのコード(ポリフィルを使用したライブデモ)をオープンソース化しました。