ホームページ > 記事 > ウェブフロントエンド > CSS_html/css_WEB-ITnose に関する Houdini ワーキング グループの秘密
CSS が (ページ レイアウトで) 実行する作業量について考えたことがありますか? (直後に) 特定の CSS プロパティの属性値を変更すると、Web サイト全体がさまざまなレイアウトで即座に目の前に表示されます。ページレイアウトに関しては、CSS にはいくつかの魔法があります。 (これらの魔法を使って今後どのように進むのか誰が教えてくれるのでしょうか?) これまでのところ、Web 開発者コミュニティの私たちはこれらの魔法を目撃し、体験することができました。独自の魔法を考え出したい場合はどうすればよいでしょうか?マジシャンになりたい場合はどうすればよいですか? Houdini ワーキング グループに参加してください。
Houdini ワーキング グループには、Mozilla、Apple、Opera、Microsoft、HP、Intel、Google のエンジニアが集まります。このワーキング グループの目的は、CSS エンジンの一部のモジュールを Web 開発者に公開することです。 Houdini ワーキング グループは、W3C 組織によって認められ、徐々に Web 標準となるドラフト セットを開発中です。 Houdini ワーキング グループは、(自分たちが作成した) ドラフトのセットをドラフト仕様に変えるという高い目標を設定していますが、これは低レベルの補助的なドラフト セットになります。誰かが「Houdini」について話すとき、それは通常、ドラフト セットについて話していることを意味します。私たちがドラフトセット(独自の準備)を作成していた時点では、ドラフトリストは未完成の状態であり、(ドラフトリスト内の)一部のドラフトはまだ計画段階にありました。これは、Houdini ワーキング グループがいかに早くから準備を進めてきたかを示しています。
免責事項: 最初に Houdini ドラフトのプレビュー バージョンをリリースしたいと考えています。そのため、Houdini ワーキング グループが正確に何を解決しようとしているのか疑問に思われるかもしれません。現在の仕様がブラウザーで部分的にサポートできる限り、コード例を示してみます。これらの仕様はまだドラフトにすぎず、不安定であることに注意してください。したがって、これらのコード ケースが近い将来に完全に正しいという保証はありません。そうでない場合は、これらの草案が実際の標準になるのを待つことによってのみ、コード ケースが完全に正しいことを確認できます。
ワークレットは、それ自体ではあまり役に立ちません。ワークレットは将来のドラフトに対して可能な限りコンテンツ導入サポートのみを提供するためです。 「ワークレット」と読んで Web ワーカーを思い浮かべるなら、その通りです。なぜなら、それらの間には概念的なクロスオーバーが多すぎるからです。そこで、すでに Web ワーカーがいるのに、なぜ Worklet が必要なのかという疑問が生じるかもしれません。 Houdini は、Web 開発者に新しい API を公開し、CSS エンジンや周辺環境にコードをマウントできるようにすることを目指しています。一部のフラグメントがすべての単一フレームを実行する必要があると想定するのは非現実的です。一部のコード スニペットを定義する必要があります。 Web Worker 仕様を引用します:
Workers[...]。これは比較的容量が大きいため、大量の処理には推奨されません。たとえば、4 メガピクセルの画像のピクセルごとにスレッドを開始することはお勧めできません。
これは、Web ワーカーが Houdini が実行する必要があるものと一致していないことを意味します。そこでワークレットが登場しました。ワークレットは ES2015 クラスを使用してメソッドのコレクションを定義し、ワークレットのデータ型を使用して事前にメソッド シグネチャを定義します。さらに、ワークレットは軽量でライフサイクルが短いです。
ペイント ワークレットには新しい概念がほとんど導入されていなかったからこそ、私はペイント ワークレットの勉強を始めました。以下の内容は、ペイント ワークレットのドラフト仕様からの抜粋です。
CSS のペイント スキャフォールディングは、主に背景の描画と要素の幾何学的構造 (レイアウト スキャフォールディングの生成に使用) に基づいたコンテンツの描画を担当します。スタイルを変更し、ハイライトを実装します。
ペイント ワークレットを使用すると、要素自体をペイントする方法を定義できるだけでなく (Web コンポーネントと組み合わせて使用することを検討してください)、既存の要素の外観を変更することもできます。波及効果を作成するためにボタンに DOM 要素を追加するなどのハックを使用する必要はありません。これを行うと、共通ビューの DOM ノードの数を大幅に減らすことができます。 5ba626b379994d53f7acf72a64f9b697 要素を使用し、要素の描画中にコードを実行するもう 1 つの利点は、描画している要素の寸法がわかり、フラグメントを適切に理解して適用できることです。
DOM ツリー内の要素を CSS エンジンで表示できるボックス モデルとして扱い、そのボックス モデルを使用して Web サイトを構築します。このモデルには、インライン要素が関与する場合に欠陥があります。 45a2772a6b6107b401db3c9b82c049c2タグの内容は折り返されます。したがって、インライン要素が唯一の DOM ノードである場合、インライン要素は 2 つのフラグメントに分割されます。 仕様では、2 つのフラグメントの境界ボックスをフラグメントテイナーと呼びます。 (冗談ではありません)
ペイント ワークレットに戻る: 実際、コードは各フラグメントによって呼び出され、コードは API のように元の 5ba626b379994d53f7acf72a64f9b697 にアクセスすることもできます。要素にも適用されます。 (ビュー検査を除く) ペイント ワークレットでは引き続きフラグメントを描画でき、「オーバーフロー」マージンの使用を要求して、ボックス シャドウ効果と同様の効果を要素の境界に描画できるようにすることもできます。
class { static get inputProperties() {return ['border-color', 'border-size']; } paint(ctx, geom, inputProperties) {/*定义了inputProperties的get操作,调用inputProperties返回一个数组,所以对inputProperties['border-size']不是很理解*/var offset = inputProperties['border-size']var colors = inputProperties['border-color'];self.drawFadingEdge( ctx, 0-offset[0], 0-offset[0], geom.width+offset[0], 0-offset[0], color[0]);self.drawFadingEdge( ctx, geom.width+offset[1], 0-offset[1], geom.width+offset[1], geom.height+offset[1], color[1]);self.drawFadingEdge( ctx, 0-offset[2], geom.height+offset[2], geom.width+offset[2], geom.height+offset[2], color[2]);self.drawFadingEdge( ctx, 0-offset[3], 0-offset[3], 0-offset[3], geom.height+offset[3], color[3]); } drawFadingEdge(ctx, x0, y0, x1, y1, color) {var gradient = ctx.createLinearGradient(x0, y0, x1, y1);gradient.addColorStop(0, color);var colorCopy = new ColorValue(color);colorCopy.opacity = 0;gradient.addColorStop(0.5, colorCopy);gradient.addColorStop(1, color); } overflow(inputProperties) {// Taking a wild guess here. The return type// of overflow() is currently specified// as `void`, lol.return { top: inputProperties['border-size'][0], right: inputProperties['border-size'][1], bottom: inputProperties['border-size'][2], left: inputProperties['border-size'][3],}; }};
Houdini ワーキング グループがドラフト セットを作成していた時点では、コンポジター ワークレットに適した提案がなかったので、これは私にとって非常に励みになりました。ご存知のとおり、CSS エンジンは一部の描画操作をコンピュータのグラフィック カードにアウトソーシングします。一般に、CSS エンジンがそれを行うかどうかは、コンピュータのグラフィック カードとデバイスによって異なります。通常、ブラウザは DOM ツリーを取得し、特定の基準に基づいてブランチとサブツリーに対応するレイヤーを与えます。これらのサブツリーは、対応するレイヤー内で自身をペイントします (おそらく近い将来ペイント ワークレットを使用します)。最後のステップでは、Z インデックス、3D 変換、その他の要素を考慮して、独立した描画 (サブツリー) レイヤーがスタックの最上位に配置され、最終的に最終的に描画されたイメージが画面に表示されます。このプロセスは「合成」と呼ばれ、この合成は「コンポジタ」を通じて実行されます。合成の利点は、ページが短い距離だけスクロールする場合、すべての要素を再描画する必要がないことです。前のフレームからこれらのレイヤーを再利用し、スクロール距離を変更しながらコンポジタを再実行できます。これを行うとアニメーションが高速になり、60fps に達する可能性があります。ポール・ルイスはこれ以上嬉しいことはありません。
名前が示すように、コンポジター ワークレットを使用すると、コンポジターをバインドし、要素をレイヤー化する (他のレイヤーの上に描画および配置する) 方法に影響を与えることができます。より具体的な情報を取得するには、合成スレッドを特定の DOM ノードにバインドし、スクロール位置、変換、透明度などのプロパティへのアクセスをリクエストし、最後にこれらをブラウザーに通知します。このアプローチでは、要素がそのレイヤーを放棄し、各フレームで作成したコードを呼び出すように強制されます。レイヤーの変換を操作してレイヤーを移動し、レイヤーのプロパティ (透明度など) を変更することで、60 fps でのみクールに感じられる操作を行うことができます。これは、コンポジター ワークレットを使用して並列スクロールを実装する完全な例です。
// main.jswindow.compositorWorklet.import('worklet.js') .then(function() {var animator = new CompositorAnimator('parallax');animator.postMessage([ new CompositorProxy($('.scroller'), ['scrollTop']), new CompositorProxy($('.parallax'), ['transform']),]); }); // worklet.jsregisterCompositorAnimator('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 がコンポジター ワークレット用のポリフィルを作成したので、パフォーマンスを体験する目的でコンポジター ワークレットを使用してみることができます。
レイアウト ワークレットの仕様はほとんど空ですが、独自のレイアウトを作成するというレイアウト ワークレットのアイデアは非常に魅力的です。レイアウト ワークレットを使用すると、表示属性 ( display:layout('myLayout') ) を使用できるようになり、JavaScript コードを実行してノード ボックス モデル内の子ノードを管理できるようになります。もちろん、JavaScript コード (CSS フレックスボックス レイアウトの実装に使用) を直接実行するのは、JavaScript コード (同じ関数をネイティブに実装する) を実行するよりも明らかに遅くなりますが、そのようなシナリオを考えるのは簡単です。これらのコードを切断すると、問題が再び発生します。パフォーマンスの問題が発生します。想像してみてください。Web サイトにはタイル (Windows 10 システムに付属) のみが含まれているか、Masonry レイアウトが直接使用されており、Z インデックスは使用されず、要素間の重複や境界線さえありません。 。また、再描画操作のすべてのチェックをスキップすることもできます (追記: 再描画操作はパフォーマンスの問題を引き起こす可能性があります)。
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 (CSS オブジェクト モデルまたは重複可能なスタイル モデル) は、私たちが遭遇する可能性があり、耐える必要があるすべての問題に対処できます。この問題を JavaScript コード行で説明してみましょう。
$('#someDiv').style.height = getRandomInt() + 'px';
数値を返す関数を実装し、次に数値を文字列に変換し、最後に単位を文字列に追加する必要があります。 (タスクが完了したら) ブラウザーは文字列内の数値を解析し、その数値を CSS エンジンに返すだけで済みます。 JavaScript コードを使用して変換を操作する場合、作成したコードの見た目が醜くなる場合もあります。もうこの問題について心配する必要はありません。なぜなら、CSS は間もなく動的入力をサポートするようになるからです。
Typed CSSOM ドラフトは成熟したドラフトの 1 つにすぎず、ポリフィルは完成しています。 (免責事項: このポリフィルを使用すると、明らかに計算オーバーヘッドが追加されます。このポリフィルは、型付き CSSOM で API を使用することがいかに便利かを示すことを目的としています。)
要素の代わりに、StylePropertyMap 属性を使用できます。 StylePropertyMap の文字列、CSS プロパティには独自のキー名と対応する値の型があります。 width 属性には、値の型として LengthValue があります。 LengthValue は、em、rem、px、パーセントなどのすべての CSS 単位を含む辞書のようなものです。 height:calc(5px+5%) を設定すると、LengthValue{px:5,percent:5} も生成されます。さらに、box-sizing のようなプロパティは特定のキーワードのみを受け入れるため、box-sizing の値の型は KeywordValue になります。これらのプロパティの有効性は実行時にチェックされます。
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 Variables有哪些非正式的别名)?CSS Variables甚至还有数据类型的概念!到目前为止,CSS变量只能被赋值为字符串而且被经常用作关于搜索以及替换的解决方案。Properties and Values草案不仅允许你为CSS变量指定类型,而且允许你为CSS变量设置默认值以及允许你使用JavaScript API来影响CSS变量之间的继承关系。从技术上来讲,Properties and Values也允许常见的属性通过使用标准CSS过渡以及动画来实现动画效果,对于这种想法我们还是可以实现的。
["--scale-x", "--scale-y"].forEach(function(name) {document.registerProperty({ name: name, syntax: "", inherits: false, initialValue: "1" });});
Font metrics和名字所描述的一样。当我们通过使用字体大小为Z的Y字体来渲染X字符串或者我们要字符折行时,我们就要问自己什么是边界框?如果存在这种情景:你喜欢使用 ruby注释 而我要在你的代码上执行所有的unicode编码,那我们该怎么办?这种情况解决需要很多条件,最后我觉得Houdini工作小组应该可以将这些愿望变成现实。
虽然Houdini的草案列表中有很多规范,但是我们也不能预测这些规范的未来,而且就拿提案来说,这些规范就不多于placeholders。这些案例(针对常见溢出,针对CSS语法扩展的API,针对原生滚动扩展)现在都可以运行在目前的web平台,但是在以前这些案例都是不能运行的。
到目前为止,Chrome没有实现Houdini工作小组制定的任何规范。然而在不久将来Chrome Canary可能会部分实现了Houdini工作小组制定的规范Beta版。
不管怎么样,我已经开源了相关 代码 (关于如何使用polyfill写案例)以及录制了与此相关的 视频案例 ,好让你们直观感受一下worklets。
如果你想更深入了解,这里有 Houdini工作小组的邮件列表
扫码关注w3ctech微信公众号