CSSレイアウトAPI レベル1

W3C 初版公開作業草案,

このバージョン:
https://www.w3.org/TR/2018/WD-css-layout-api-1-20180412/
最新公開バージョン:
https://www.w3.org/TR/css-layout-api-1/
編集者草案:
https://drafts.css-houdini.org/css-layout-api-1/
フィードバック:
public-houdini@w3.org 件名欄に “[css-layout-api] … メッセージのトピック …” を記載してください (アーカイブ)
課題追跡:
GitHub
仕様内インライン
編集者:
(Microsoft)
(Google)
Tab Atkins-Bittner (Google)
(Google)
(Microsoft)

概要

本仕様は、開発者が計算済みスタイルやボックスツリーの変更に応じて ボックスツリーをレイアウトできるAPIについて記述します。

この文書のステータス

このセクションは、公開時点での文書のステータスについて説明します。他の文書が本書に取って代わる場合があります。現在のW3C出版物および本技術報告の最新版は、W3C技術報告インデックス(https://www.w3.org/TR/)で確認できます。

本書は初公開作業草案です。

初公開作業草案として公開されたことは、W3C会員による承認を意味しません。本書は草案であり、随時更新、置換、廃止される可能性があります。進行中の作業以外の文献として本書を引用するのは不適切です。

GitHub Issuesにて仕様の議論を推奨します。 イシュー登録時はタイトルに「css-layout-api」を含め、できれば 「[css-layout-api] …コメント概要…」の形式でお願いします。 すべてのイシューやコメントはアーカイブされています。

本書はCSS作業グループによって作成されました。

本書はW3C特許ポリシーのもとで運営されるグループによって作成されています。W3Cはグループ成果物に関する特許開示の公開リストを管理しています。このページには特許開示方法も記載されています。該当する特許について知っている場合は、必須クレームを含むと考えられる場合、W3C特許ポリシー第6節に従い開示してください。

本書は2018年2月1日版W3Cプロセス文書に従って管理されています。

1. はじめに

このセクションは規定的ではありません。

CSSのレイアウト段階は、フラグメントボックスツリーから生成および配置する役割を持ちます。

この仕様は、開発者が計算済みスタイルやボックスツリーの変更に応じて ボックスツリーをレイアウトできるAPIについて記述します。

2. レイアウトAPIコンテナー

新しいalternative値が <display-inside>生成式に追加されます: layout(<ident>)

layout()
この値は要素にレイアウトAPIコンテナボックスを生成させます。

レイアウトAPIコンテナは、<display-inside>計算値としてlayout()を持つ要素によって生成されるボックスです。

レイアウトAPIコンテナはその内容に対して新しいレイアウトAPI整形コンテキストを確立します。これはブロック整形コンテキストを確立するのと同様ですが、ブロックレイアウトの代わりに著者提供のレイアウトが使用されます。 例えば、フロートはレイアウトAPIコンテナに侵入せず、コンテナのマージンは内容のマージンと折り畳まれません。

レイアウトAPIコンテナの流れの中のすべての子はレイアウトAPI子要素と呼ばれ、著者定義のレイアウトによってレイアウトされます。

レイアウトAPIコンテナは内容に対してブロックコンテナと全く同じように包含ブロックを形成します。[CSS21]

注: 将来の仕様レベルでは包含ブロックの挙動を上書きする方法が追加される可能性があります。

overflowプロパティはレイアウトAPIコンテナに適用されます。詳細は§4.3 オーバーフローで説明します。

レイアウトが完全に著者の裁量であるため、他のレイアウトモード(例:フレックス・ブロック)で使用されるプロパティは適用されない場合があります。例えば、著者が子要素のmarginプロパティを尊重しない場合があります。

2.1. レイアウトAPIコンテナのペインティング

レイアウトAPIコンテナの子要素は、インラインブロック[CSS21]と全く同じように描画されますが、 レイアウトメソッドから返される順序(childFragments経由)が生の文書順の代わりに使用され、 z-indexauto以外の場合、positionstaticでもスタッキングコンテキストが作成されます。

2.2. ボックスツリーの変換

レイアウトAPI子要素は、layout options'childDisplay (クラスのlayoutOptionsで設定)値によって異なる振る舞いをします。

layout options'childDisplay の値が"block"の場合、その子のdisplay値はブロック化されます。これはフレックスコンテナグリッドコンテナの子と似ています。 詳細は[css3-display]を参照してください。

layout options'childDisplay の値が"normal"の場合、ブロック化は行われません。 代わりに、<display-outside>計算値inlineルートインラインボックス)の場合、 LayoutFragmentが各行を表す形で layoutNextFragment()呼び出し時に生成されます。

注: これにより著者は各行の利用可能なインラインサイズを調整し、個別に行を配置できます。

LayoutChildが表すルートインラインボックスの子にも追加の変換があります。

上記いずれの場合も、子要素はアトミックインラインとなります。

注: ユーザーエージェントはブロックレベルボックスに遭遇した際、インライン分割や断片化は行いません。

注: 以下の例では "inline-span" が単一のLayoutChildとして表され、 "block"と"float"は両方ともアトミックインラインとなります。
<span id="inline-span">
  Text
  <div id="block"></div>
  <div id="float"></div>
  Text
</span>

3. レイアウトAPIのモデルと用語

このセクションでは著者が利用できるレイアウトAPIの概要を説明します。

現在のレイアウトとは、 現在レイアウトを実行しているボックスのレイアウトアルゴリズムである。

親レイアウトとは、 ボックスの直接の親のレイアウトアルゴリズム(現在のレイアウトの実行を要求しているレイアウト アルゴリズム)である。

子レイアウトとは、 現在のレイアウトLayoutChild に対するレイアウトアルゴリズムである。

3.1. レイアウトの子要素

[Exposed=LayoutWorklet]
interface LayoutChild {
    readonly attribute StylePropertyMapReadOnly styleMap;

    IntrinsicSizesRequest intrinsicSizes();
    LayoutFragmentRequest layoutNextFragment(LayoutConstraints constraints, ChildBreakToken breakToken);
};

LayoutChildは内部スロットを持ちます:


LayoutChildは、CSSによって生成されたボックス(レイアウト前)を表します。(ボックスはすべてdisplayの計算値がnone以外です)。

LayoutChildは自体にレイアウト情報(インラインサイズやブロックサイズなど)は持たず、LayoutFragment(レイアウト情報を持つ)を生成するために使われます。

著者はこのAPIでLayoutChildを構築することはできません。これはレンダリングエンジンの別の段階(スタイル解決後)で行われます。

LayoutChildは以下によって生成されます:

注: 以下の例は3つのLayoutChildに分割されます:
<style>
  #box::before { content: 'hello!'; }
</style>
<div id="box">A block level box with text.</div>
<img src="..." />
注: 以下の例は単一のLayoutChildにまとめられます(共通のルートインラインボックスを共有しているため):
This is a next node, <span>with some additional styling,
that may</span> break over<br>multiple lines.

複数の非アトミックインラインは同じLayoutChildにまとめられ、レンダリングエンジンが要素間でテキストシェーピングを行えるようにします。

注: 以下の例は1つのLayoutFragmentを生成しますが、 3つの非アトミックインラインから構成されます:
ع<span style="color: blue">ع</span>ع

現在レイアウト中のボックスの子要素を表すLayoutChildの配列がレイアウトメソッドに渡されます。

styleMapは、LayoutChild thisから取得する場合、ユーザーエージェントは以下の手順を実行しなければなりません:
  1. thisStylePropertyMapReadOnly[[styleMap]]内部スロット)を返す。

layoutNextFragment(constraints, breakToken) メソッドがLayoutChild thisで呼び出された場合、ユーザーエージェントは以下の手順を実行しなければなりません:
  1. requestを新しいLayoutFragmentRequestとして生成し、内部スロットを持つ:

  2. requestを返す。

intrinsicSizes()メソッドがLayoutChild thisで呼び出された場合、ユーザーエージェントは以下の手順を実行しなければなりません:
  1. requestを新しいIntrinsicSizesRequestとして生成し、内部スロットを持つ:

  2. requestを返す。

注: layoutNextFragment() および intrinsicSizes() は同期的に実行されません。詳細は§5.5.1 リクエストオブジェクトを参照してください。

3.1.1. LayoutChildrenとボックスツリー

boxは、[[layoutChildMap]]という内部スロットを持ちます。これは、マップであり、LayoutWorkletGlobalScopeからLayoutChildへの対応関係を保持します。

ユーザーエージェントがworkletGlobalScopenameboxを指定してレイアウト子要素を取得したい場合、次の手順を実行しなければなりません:
  1. 以下を確認する:

  2. layoutChildMapbox[[layoutChildMap]]とする。

  3. もしlayoutChildMap[workletGlobalScope]が存在しない場合、次の手順を実行する:

    1. definitionレイアウト定義の取得nameworkletGlobalScopeを渡して得る。

      レイアウト定義の取得が成功し、definition"invalid"でないことを確認する。

    2. childInputPropertiesdefinition子入力プロパティとする。

    3. layoutChildを新しいLayoutChildとして、以下の内部スロットを持たせて生成する:

    4. セット layoutChildMap[workletGlobalScope]にlayoutChildを設定する。

  4. 取得したlayoutChildMap[workletGlobalScope]を返す。

ユーザーエージェントは、boxボックスツリーに挿入された際に、すべてのLayoutWorkletGlobalScopeに対して[[layoutChildMap]]を事前に生成してもよい。

ユーザーエージェントは、boxボックスツリーから削除された際、[[layoutChildMap]]を必ずクリアしなければなりません。

ユーザーエージェントがboxを指定してレイアウト子要素のスタイル更新を行いたい場合、以下の手順を実行しなければなりません:
  1. 以下を確認する:

  2. もしbox包含ブロックレイアウトAPIコンテナでない場合、すべての手順を中止する。

  3. layoutChildMapbox[[layoutChildMap]]とする。

  4. 全てのlayoutChildについてlayoutChildMap内を反復する:

    1. styleMaplayoutChild[[styleMap]]とする。

    2. styleMap宣言boxの新しい計算済みスタイルに基づき更新する。

boxの計算済みスタイルが変更されたとき、ユーザーエージェントはレイアウト子要素のスタイル更新アルゴリズムを実行しなければなりません。

3.2. レイアウトフラグメント

[Exposed=LayoutWorklet]
interface LayoutFragment {
    readonly attribute double inlineSize;
    readonly attribute double blockSize;

    attribute double inlineOffset;
    attribute double blockOffset;

    readonly attribute any data;

    readonly attribute ChildBreakToken? breakToken;
};

LayoutFragmentは内部スロットを持ちます:


LayoutFragmentは、LayoutChildのレイアウト後のCSSフラグメントを表します。これはlayoutNextFragment()メソッドによって生成されます。

LayoutFragmentには、inlineSizeblockSize属性があり、それぞれ子要素のレイアウトアルゴリズムによって設定されます。これらはCSSフラグメントborder boxサイズであり、現在のレイアウトの書字モードに相対的です。

inlineSizeblockSize属性は変更できません。 現在のレイアウトで異なるinlineSizeまたはblockSizeが必要な場合、著者は異なる引数でlayoutNextFragment()を再度実行しなければなりません。

現在のレイアウト内の著者は、生成されたLayoutFragmentinlineOffsetblockOffset属性を設定することで位置を指定できます。著者が設定しない場合はデフォルトでゼロになります。inlineOffsetblockOffset属性は、LayoutFragmentの親のborder boxに対する位置を表し、transformやpositioning(例えばフラグメントが相対配置された場合)を適用する前の値です。

レイアウトアルゴリズムはブロック風のレイアウト(フラグメントをブロック方向に順次配置)を実行し、子要素をインライン方向で中央揃えします。
registerLayout('block-like', class {
    *intrinsicSizes(children, edges, styleMap) {
      const childrenSizes = yield children.map((child) => {
          return child.intrinsicSizes();
      });

      const maxContentSize = childrenSizes.reduce((max, childSizes) => {
          return Math.max(max, childSizes.maxContentSize);
      }, 0) + edges.all.inline;

      const minContentSize = childrenSizes.reduce((max, childSizes) => {
          return Math.max(max, childSizes.minContentSize);
      }, 0) + edges.all.inline;

      return {maxContentSize, minContentSize};
    }

    *layout(children, edges, constraints, styleMap) {
        const availableInlineSize = constraints.fixedInlineSize - edges.all.inline;
        const availableBlockSize = (constraints.fixedBlockSize || Infinity) - edges.all.block;

        const childFragments = [];
        const childConstraints = { availableInlineSize, availableBlockSize };

        const childFragments = yield children.map((child) => {
            return child.layoutNextFragment(childConstraints);
        });

        let blockOffset = edges.all.blockStart;
        for (let fragment of childFragments) {
            // フラグメントをブロック方向に配置し、インライン方向で中央揃えする
            fragment.blockOffset = blockOffset;
            fragment.inlineOffset = Math.max(
                edges.all.inlineStart,
                (availableInlineSize - fragment.inlineSize) / 2);

            blockOffset += fragment.blockSize;
        }

        const autoBlockSize = blockOffset + edges.all.blockEnd;

        return {
            autoBlockSize,
            childFragments,
        };
    }
});

レイアウトAPIコンテナは、data属性を利用して他のレイアウトAPIコンテナと通信できます。これはdataメンバーでFragmentResultOptions辞書にセットされます。

LayoutFragmentbreakTokenは、LayoutChildが最後に断片化された場所を指定します。breakTokenがnullの場合、そのLayoutChildはそのトークンチェーンに対してこれ以上LayoutFragmentを生成しません。breakTokenは、layoutNextFragment()関数に渡すことで、特定の子要素の次のLayoutFragmentを生成できます。breakTokenは変更できません。 現在のレイアウトで異なるbreakTokenが必要な場合は、著者は異なる引数でlayoutNextFragment()を再度実行する必要があります。

ユーザーエージェントがgeneratorlayoutFragmentRequestinternalFragmentを指定してレイアウトフラグメントを生成したい場合、次の手順を実行しなければなりません:
  1. targetRealmgeneratorRealmとする。

  2. fragmentを新しいLayoutFragmentとして、以下の設定で生成する:

  3. fragmentを返す。

3.3. 本来サイズ

[Exposed=LayoutWorklet]
interface IntrinsicSizes {
  readonly attribute double minContentSize;
  readonly attribute double maxContentSize;
};

IntrinsicSizesオブジェクトは内部スロットを持ちます:


IntrinsicSizesオブジェクトは、CSSのmin-contentサイズおよびmax-contentサイズを表します。これは、minContentSize属性とmaxContentSize属性を持ち、LayoutChildborder boxのmin/max-content寄与を現在のレイアウトについて表します。これらの属性は、現在のレイアウトの書字方向のインライン方向に対する相対値です。

minContentSizemaxContentSizeは変更できません。 これらは、現在のレイアウトパス内でLayoutChildについて変化しないものとします。

以下は2つの子要素のborder-box本来サイズの例です。
<style>
.child-0 {
  width: 380px;
  border: solid 10px;
}

.child-1 {
  border: solid 5px;
}

.box {
  display: layout(intrinsic-sizes-example);
  font: 25px/1 Ahem;
}
</style>

<div class="box">
  <div class="child-0"></div>
  <div class="child-1">XXX XXXX</div>
</div>
registerLayout('intrinsic-sizes-example', class {
    *intrinsicSizes(children, edges, styleMap) {
      const childrenSizes = yield children.map((child) => {
          return child.intrinsicSizes();
      });

      childrenSizes[0].minContentSize; // 400, (380+10+10) 固定サイズの子。
      childrenSizes[0].maxContentSize; // 400, (380+10+10) 固定サイズの子。

      childrenSizes[1].minContentSize; // 100, "XXXX"のサイズ。
      childrenSizes[1].maxContentSize; // 200, "XXX XXXX"のサイズ。
    }

    *layout() {}
});
ユーザーエージェントがintrinsicSizesRequestinternalIntrinsicSizesを指定して本来サイズオブジェクトを生成したい場合、次の手順を実行しなければなりません:
  1. intrinsicSizesを新しいIntrinsicSizesとして、以下の設定で生成する:

  2. intrinsicSizesを返す。

3.4. レイアウト制約

[Constructor(optional LayoutConstraintsOptions options),Exposed=LayoutWorklet]
interface LayoutConstraints {
    readonly attribute double availableInlineSize;
    readonly attribute double availableBlockSize;

    readonly attribute double? fixedInlineSize;
    readonly attribute double? fixedBlockSize;

    readonly attribute double percentageInlineSize;
    readonly attribute double percentageBlockSize;

    readonly attribute double? blockFragmentationOffset;
    readonly attribute BlockFragmentationType blockFragmentationType;

    readonly attribute any data;
};

dictionary LayoutConstraintsOptions {
    double availableInlineSize = 0;
    double availableBlockSize = 0;

    double fixedInlineSize;
    double fixedBlockSize;

    double percentageInlineSize;
    double percentageBlockSize;

    double blockFragmentationOffset;
    BlockFragmentationType blockFragmentationType = "none";

    any data;
};

enum BlockFragmentationType { "none", "page", "column", "region" };

LayoutConstraints オブジェクトが layout メソッドに渡され、現在のレイアウトがレイアウトを実行するためのすべての制約を表します。また、このオブジェクトは利用可能なスペースの情報を 子レイアウトに渡すためにも使用されます。

LayoutConstraints オブジェクトには availableInlineSizeavailableBlockSize 属性があります。これは、レイアウトが尊重すべき 利用可能なスペースLayoutFragment のために表します。

注: 一部のレイアウトでは、このサイズを超える LayoutFragment を生成する必要があります。例えば 置換要素 などです。親レイアウトはこれが発生することを想定し、適切に対応する必要があります。

親レイアウト現在のレイアウトが正確に特定のサイズであることを要求する場合があります。fixedInlineSizefixedBlockSize が指定されている場合、現在のレイアウトは指定された方向に指定されたサイズの LayoutFragment を生成する必要があります。

レイアウトアルゴリズムは、インライン方向の余分なスペースをフレックスボックスのように分配します。 子のインラインサイズを固定するような子レイアウト制約を生成します。
registerLayout('flex-distribution-like', class {
    *intrinsicSizes(children, edges, styleMap) {
      const childrenSizes = yield children.map((child) => {
          return child.intrinsicSizes();
      });

      const maxContentSize = childrenSizes.reduce((sum, childSizes) => {
          return sum + childSizes.maxContentSize;
      }, 0) + edges.all.inline;

      const minContentSize = childrenSizes.reduce((max, childSizes) => {
          return sum + childSizes.minContentSize;
      }, 0) + edges.all.inline;

      return {maxContentSize, minContentSize};
    }

    *layout(children, edges, constraints, styleMap) {

        const availableInlineSize =
            constraints.fixedInlineSize - edges.all.inline;
        const availableBlockSize =
            (constraints.fixedInlineSize || Infinity) - edges.all.block;

        const childConstraints = { availableInlineSize, availableBlockSize };

        const unconstrainedChildFragments = yield children.map((child) => {
            return child.layoutNextFragment(childConstraints);
        });

        const unconstrainedSizes = [];
        const totalSize = unconstrainedChildFragments.reduce((sum, fragment, i) => {
            unconstrainedSizes[i] = fragment.inlineSize;
            return sum + fragment.inlineSize;
        }, 0);

        // 余分なスペースを子要素間で分配する。
        const remainingSpace = Math.max(0, inlineSize - totalSize);
        const extraSpace = remainingSpace / children.length;

        const childFragments = yield children.map((child, i) => {
            return child.layoutNextFragment({
                fixedInlineSize: unconstrainedSizes[i] + extraSpace,
                availableBlockSize
            });
        });

        // フラグメントの位置決め。
        let inlineOffset = 0;
        let maxChildBlockSize = 0;
        for (let fragment of childFragments) {
            fragment.inlineOffset = inlineOffset;
            fragment.blockOffset = edges.all.blockStart;

            inlineOffset += fragment.inlineSize;
            maxChildBlockSize = Math.max(maxChildBlockSize, fragment.blockSize);
        }

        return {
            autoBlockSize: maxChildBlockSize + edges.all.block,
            childFragments,
        };
    }
});

LayoutConstraints オブジェクトには percentageInlineSizepercentageBlockSize 属性があります。これらは、レイアウトのパーセンテージがレイアウト実行時にどのサイズを基準に解決されるかを表します。

LayoutConstraints には blockFragmentationType 属性があります。現在のレイアウトは、可能であれば LayoutFragmentblockFragmentationOffset で断片化する必要があります。

現在のレイアウトは、LayoutChildblockFragmentationType に基づき断片化しない選択をすることができます。例えば、子に break-inside: avoid-page; のようなプロパティがある場合です。

ユーザーエージェントが sizingMode、box|、 および internalLayoutConstraints を指定して レイアウト制約オブジェクトを作成する場合、 次の手順を実行しなければならない:
  1. sizingMode"block-like" の場合:

    1. fixedInlineSize を、ブロックコンテナの場合とまったく同様に boxborder-box インラインサイズbox の書字 モードを基準とする)を計算した結果とする。

    2. boxブロックサイズauto の場合、fixedBlockSize を null とし、それ以外の場合は、 ブロックコンテナの場合とまったく同様に boxborder-box ブロックサイズを計算した 結果とする。

    3. 次の設定を持つ新しい LayoutConstraints オブジェクトを返す:

      • fixedInlineSize および availableInlineSizefixedInlineSize に設定する。

      • percentageInlineSizeinternalLayoutConstraints の インライン軸におけるパーセンテージ解決サイズ(box の 書字モードを基準とする)に設定する。

      • fixedBlockSizefixedBlockSize に設定する。

      • availableBlockSize を、fixedBlockSize が null でない場合はそれに設定し、 それ以外の場合は internalLayoutConstraints のブロック軸における 利用可能な空間box の書字モードを基準とする)に設定する。

      • percentageBlockSizeinternalLayoutConstraints の ブロック軸におけるパーセンテージ解決サイズ(box の 書字モードを基準とする)に設定する。

  2. sizingMode"manual" の場合:

    1. 次の設定を持つ新しい LayoutConstraints オブジェクトを返す:

3.5. 分割と断片化

[Exposed=LayoutWorklet]
interface ChildBreakToken {
    readonly attribute BreakType breakType;
    readonly attribute LayoutChild child;
};

[Exposed=LayoutWorklet]
interface BreakToken {
    readonly attribute sequence<ChildBreakToken> childBreakTokens;
    readonly attribute any data;
};

dictionary BreakTokenOptions {
    sequence<ChildBreakToken> childBreakTokens;
    any data = null;
};

enum BreakType { "none", "line", "column", "page", "region" };

LayoutChild は複数の LayoutFragment を生成することができます。 LayoutChild は、blockFragmentationType が none でなければブロック方向に断片化する場合があります。さらに、LayoutChildインラインレベル コンテンツを表す場合、レイアウトオプションchildDisplaylayoutOptions により設定)が "normal" の場合、行ごとに断片化することがあります。

後続の LayoutFragment は、前の LayoutFragmentbreakToken を使用して生成されます。これによって、子レイアウトLayoutFragmentChildBreakToken に記録された地点から生成することができます。

この例は、一定数の 行について子フラグメントをインデントする単純なレイアウトを示す。

この例では、LayoutFragment の以前の breakToken を使用して、LayoutChild の次のフラグメントを生成する方法も示す。

また、LayoutConstraintsblockFragmentationType に従うために BreakToken を使用する方法も示しており、以前の BreakToken からレイアウトを再開する。 レイアウトの再開に使用される breakToken を持つ FragmentResultOptions を返す。

registerLayout('indent-lines', class {
    static layoutOptions = {childDisplay: 'normal'};
    static inputProperties = ['--indent', '--indent-lines'];

    *layout(children, edges, constraints, styleMap, breakToken) {

        // 自身の(内側の)利用可能サイズを決定する。
        const availableInlineSize =
            constraints.fixedInlineSize - edges.all.inline;
        const availableBlockSize =
            (constraints.fixedBlockSize || Infinity) - edges.all.block;

        // インデントする行数とインデント量を決定する。
        const indent = resolveLength(constraints, styleMap.get('--indent'));
        let lines = styleMap.get('--indent-lines').value;

        const childFragments = [];

        let childBreakToken = null;
        if (breakToken) {
            childBreakToken = breakToken.childBreakTokens[0];

            // すでにフラグメントを生成したすべての子を削除する。
            children.splice(0, children.indexOf(childBreakToken.child));
        }

        let blockOffset = edges.all.blockStart;
        let child = children.shift();
        while (child) {
            const shouldIndent = lines-- > 0;

            // インデントに合わせてインラインサイズを調整する。
            const childAvailableInlineSize = shouldIndent ?
                availableInlineSize - indent : availableInlineSize;

            const childConstraints = {
                availableInlineSize: childAvailableInlineSize,
                availableBlockSize,
                percentageInlineSize: availableInlineSize,
                blockFragmentationType: constraints.blockFragmentationType,
            };

            const fragment = yield child.layoutNextFragment(childConstraints,
                                                            childBreakToken);
            childFragments.push(fragment);

            // フラグメントを配置する。
            fragment.inlineOffset = shouldIndent ?
                edges.all.inlineStart + indent : edges.all.inlineStart;
            fragment.blockOffset = blockOffset;
            blockOffset += fragment.blockSize;

            // ブロック断片化の制限を超えたかどうかを確認する。
            if (constraints.blockFragmentationType != 'none' &&
                blockOffset > constraints.blockSize) {
                break;
            }

            if (fragment.breakToken) {
                childBreakToken = fragment.breakToken;
            } else {
                // フラグメントにブレークトークンがない場合、
                // 次の子に進む。
                child = children.shift();
                childBreakToken = null;
            }
        }

        const autoBlockSize = blockOffset + edges.all.blockEnd;

        // フラグメントを返す。
        const result = {
            autoBlockSize,
            childFragments: childFragments,
        }

        if (childBreakToken) {
            result.breakToken = {
                childBreakTokens: [childBreakToken],
            };
        }

        return result;
    }
});

3.6. エッジ

[Exposed=LayoutWorklet]
interface LayoutEdgeSizes {
  readonly attribute double inlineStart;
  readonly attribute double inlineEnd;

  readonly attribute double blockStart;
  readonly attribute double blockEnd;

  // Convenience attributes for the sum in one direction.
  readonly attribute double inline;
  readonly attribute double block;
};

[Exposed=LayoutWorklet]
interface LayoutEdges {
  readonly attribute LayoutEdgeSizes border;
  readonly attribute LayoutEdgeSizes scrollbar;
  readonly attribute LayoutEdgeSizes padding;

  readonly attribute LayoutEdgeSizes all;
};

LayoutEdges オブジェクトは layout メソッドに渡されます。これは、現在レイアウトされているボックスの ボックスモデルのエッジのサイズを表します。

LayoutEdges には borderscrollbarpadding 属性があります。これらはそれぞれのエッジの幅を表します。

LayoutEdges には all 属性があります。これは borderscrollbarpadding エッジの合計値を表す便利な属性です。

LayoutEdgeSizes オブジェクトは、各 抽象的な寸法 (inlineStartinlineEndblockStartblockEnd) のエッジの幅を CSS ピクセル単位で表します。

inlineblockLayoutEdgeSizes オブジェクト上の便利な属性で、その方向の合計値を表します。

次の例は、CSS でスタイルされたノードと、それに対応する LayoutEdges の内容を示します。
<style>
.container {
  width: 50px;
  height: 50px;
}

.box {
  display: layout(box-edges);

  padding: 10%;
  border: solid 2px;
  overflow-y: scroll;
}
</style>

<div class="container">
  <div class="box"></div>
</div>
registerLayout('box-edges', class {
    *layout(children, edges, constraints, styleMap, breakToken) {
        edges.padding.inlineStart; // 5 (10% * 50px = 5px)
        edges.border.blockEnd; // 2
        edges.scrollbar.inlineEnd; // UA依存、0か16など
        edges.all.block; // 14 (2 + 5 + 5 + 2)
    }
}

4. 他のモジュールとの相互作用

このセクションでは、他の CSS モジュールが CSS Layout API とどのように相互作用するかを説明します。

4.1. サイズ指定

ユーザーエージェントは LayoutConstraints オブジェクトを使って、現在のレイアウトにフラグメントの希望サイズを伝えなければなりません。

ユーザーエージェントがボックスにサイズを強制したい場合、fixedInlineSizefixedBlockSize 属性を使います。

レイアウト API コンテナは、レイアウトオプションsizing の値によって、様々な方法でサイズ情報を受け取ることができます(クラスの layoutOptions で設定)。

レイアウトオプションsizing の値が "block-like" の場合、レイアウト API コンテナに渡される LayoutConstraints は:

レイアウトオプションsizing の値が "manual" の場合、ユーザーエージェントは fixedInlineSizefixedBlockSize を事前に計算してはなりません。 ただし、参加している整形コンテキストによって特定のサイズが強制される場合は例外です。例えば:

注: 下記の例では レイアウト API コンテナ のインラインサイズは 50 に設定されています。
<style>
  #container {
    width: 100px;
    height: 100px;
    box-sizing: border-box;
    padding: 5px;
  }
  #layout-api {
    display: layout(foo);
    margin: 0 20px;
  }
</style>
<div id="container">
  <div id="layout-api"></div>
</div>

4.1.1. 配置されたレイアウトのサイズ指定

レイアウト API コンテナがフロー外で配置されている場合、ユーザーエージェントは 配置サイズの方程式(CSS Positioned Layout 3 §8.1 絶対/固定配置非置換要素の幅CSS Positioned Layout 3 §8.3 絶対/固定配置非置換要素の高さ)を解決し、 適切な fixedInlineSizefixedBlockSize を設定しなければなりません。

注: 下記の例では レイアウト API コンテナ のインラインサイズとブロックサイズは 80 に固定されています。
<style>
  #container {
    position: relative;
    width: 100px;
    height: 100px;
  }
  #layout-api {
    display: layout(foo);
    top: 10px;
    bottom: 10px;
    left: 10px;
    right: 10px;
    position: absolute;
  }
</style>
<div id="container">
  <div id="layout-api"></div>
</div>

4.2. 配置

この仕様レベルにおけるすべての配置はユーザーエージェントによって処理されます。

その結果:

注: 下記の例では:
<style>
  #container {
    display: layout(foo);
    position: relative; /* container は包含ブロック */
    width: 100px;
    height: 100px;
  }
  #child-relative {
    position: relative;
    left: 5px;
    top: 10px;
  }
</style>
<div id="container">
  <div id="child-relative"></div>
  <div id="child-absolute"></div>
</div>

4.3. オーバーフロー

スクロール可能オーバーフローは、レイアウト API コンテナの場合、この仕様レベルではユーザーエージェントによって処理されます。

著者の レイアウト API コンテナ は、ブロックコンテナと同様にスクロール可能オーバーフローを計算するべきです。

たとえ著者の レイアウト API コンテナ がフラグメントを スクロール可能オーバーフロー領域に配置しても、相対位置や変形によってフラグメントが移動し、スクロール可能オーバーフロー領域となり、オーバーフローが発生しない場合もあります。

4.4. 断片化

親レイアウトは、現在のレイアウト断片化を要求するために、 blockFragmentationTypeblockFragmentationOffset を設定できます。

例:[css-multicol-1] のレイアウトでは、blockFragmentationType"column" を設定し、blockFragmentationOffset に子要素を断片化したい位置を指定します。

4.5. アラインメント

レイアウト API コンテナの最初/最後のベースラインセットは、ブロックコンテナと同様に生成されます(CSS Box Alignment 3 §9.1 Determining the Baselines of a Box参照)。ただし、インフロー子要素の順序は、document order ではなく layout メソッド(childFragments 経由)で返された順序で決定されるべきです。

注: 仕様の将来のレベルでは、著者自身がベースラインを定義できる機能が追加される予定です。これは以下のような形となります:

LayoutChild からベースライン情報を取得する場合:

const fragment = yield child.layoutNextFragment({
  fixedInlineSize: availableInlineSize,
  baselineRequests: ['alphabetic', 'middle'],
});
fragment.baselines.get('alphabetic') === 25 /* など */;

親レイアウト向けにベースライン情報を生成する場合:

registerLayout('baseline-producing', class {
  *layout(children, edges, constraints, styleMap) {
    const result = {baselines: {}};

    for (let baselineRequest of constraints.baselineRequests) {
      // baselineRequest === 'alphabetic' など
      result.baselines[baselineRequest] = 25;
    }

    return result;
  }
});

5. レイアウト

このセクションでは、CSS Layout API がユーザーエージェントのレイアウトエンジンとどのように相互作用するかを説明します。

5.1. 概念

レイアウト定義とは、著者が定義したレイアウトについて、LayoutWorkletGlobalScopeが必要とする情報を記述する構造体です(layout()関数で参照できます)。次の要素から成ります:

文書レイアウト定義とは、著者が定義したレイアウトについて、文書が必要とする情報を記述する構造体です(layout()関数で参照できます)。次の要素から成ります:

5.2. レイアウトの無効化

ボックスには、関連付けられたレイアウト有効フラグがあります。これはlayout-validまたはlayout-invalidのいずれかになります。初期値はlayout-invalidです。

ボックスには、関連付けられた内在サイズ有効フラグがあります。これはintrinsic-sizes-validまたはintrinsic-sizes-invalidのいずれかになります。初期値はintrinsic-sizes-invalidです。

ユーザーエージェントが レイアウト関数を無効化する場合(boxを指定)、ユーザーエージェントは以下の手順を必ず実行します:
  1. layoutFunctionbox の計算スタイルの display プロパティの layout() 関数とする(存在する場合)。他の型の値(例:grid)の場合は、これらの手順を中止する。

  2. namelayoutFunction の最初の引数とする。

  3. documentDefinition文書レイアウト定義を取得nameを指定)した結果とする。

    文書レイアウト定義を取得が失敗した場合、またはdocumentDefinition"invalid" の場合は、これらの手順を中止する。

  4. inputPropertiesdocumentDefinition入力プロパティとする。

  5. childInputPropertiesdocumentDefinition子入力プロパティとする。

  6. inputProperties の各 property について、property計算値が変化していれば、レイアウト有効フラグboxに対してlayout-invalidに設定し、内在サイズ有効フラグintrinsic-sizes-invalidに設定する。

  7. childInputProperties の各 property について、property計算値が変化していれば、レイアウト有効フラグboxに対してlayout-invalidに設定し、内在サイズ有効フラグintrinsic-sizes-invalidに設定する。

レイアウト関数の無効化は、ユーザーエージェントがボックスの計算スタイルを再計算したとき、またはそのボックスの子の計算スタイルが再計算されたときに必ず実行されます。

LayoutChildで表現される子ボックスボックスツリーに追加・削除された場合、または計算スタイルの変更や子孫の変更によりレイアウトが無効化された場合、かつその無効化がボックスツリー上位に伝播すべき場合、現在のレイアウト有効フラグlayout-invalidに、現在の内在サイズ有効フラグintrinsic-sizes-invalidに設定します。

レイアウト API コンテナの計算スタイルが変更され、その変更がLayoutEdgesオブジェクト内部の値に影響する場合、ボックスのレイアウト有効フラグlayout-invalidに、ボックスの内在サイズ有効フラグintrinsic-sizes-invalidに設定します。

計算スタイルの変更がLayoutConstraintsオブジェクト内部の値に影響する場合は、ボックスの内在サイズ有効フラグのみintrinsic-sizes-invalidに設定します。

注: LayoutConstraintsオブジェクトはレイアウト関数だけに渡されるので、内在サイズを無効化する必要はありません。

注: 例として、以下のプロパティはLayoutEdgesオブジェクトを変更する可能性があります:

また、以下のプロパティはLayoutConstraintsオブジェクトを変更する可能性があります:

注: これは CSS Layout API に関連するレイアウト無効化のみを説明しています。すべてのボックスは概念的にレイアウト有効フラグを持ち、これらの変更はボックスツリーを通して伝播します。

5.3. レイアウトワークレット

layoutWorklet属性は、レイアウトに関連するすべてのクラスを管理するWorkletへアクセスすることができます。

layoutWorkletワークレットグローバルスコープ型LayoutWorkletGlobalScopeです。

partial interface CSS {
    [SameObject] readonly attribute Worklet layoutWorklet;
};

LayoutWorkletGlobalScopeは、layoutWorkletのグローバル実行コンテキストです。

[Global=(Worklet,LayoutWorklet),Exposed=LayoutWorklet]
interface LayoutWorkletGlobalScope : WorkletGlobalScope {
    void registerLayout(DOMString name, VoidFunction layoutCtor);
};

5.4. レイアウトの登録

[Exposed=LayoutWorklet]
dictionary LayoutOptions {
  ChildDisplayType childDisplay = "block";
  LayoutSizingMode sizing = "block-like";
};

[Exposed=LayoutWorklet]
enum ChildDisplayType {
    "block",
    "normal",
};

[Exposed=LayoutWorklet]
enum LayoutSizingMode {
    "block-like",
    "manual",
};

documentmap 型の 文書レイアウト定義 を持ちます。 最初はこの map は空ですが、registerLayout(name, layoutCtor) が呼び出されたときに値が追加されます。

LayoutWorkletGlobalScopemap 型の レイアウト定義 を持ちます。 最初はこの map は空ですが、registerLayout(name, layoutCtor) が呼び出されたときに値が追加されます。

box のうち layout API container に該当するものは、 map 型の レイアウトクラスインスタンス を持ちます。最初はこの map は空ですが、ユーザーエージェントが 内在サイズの決定 または フラグメント生成 を行う際に値が追加されます。

registerLayout(name, layoutCtor) メソッドが呼び出されたとき、ユーザーエージェントは以下の手順を必ず実行します:
  1. name が空文字列なら、throwTypeError を投げて、以降の手順を中止する。

  2. layoutDefinitionMapLayoutWorkletGlobalScopeレイアウト定義 map とする。

  3. layoutDefinitionMap[name] が 存在する場合、throw で "InvalidModificationError" DOMException を投げて、以降の手順を中止する。

  4. inputProperties を空の sequence<DOMString> とする。

  5. inputPropertiesIterableGet(layoutCtor, "inputProperties") の結果とする。

  6. inputPropertiesIterable が undefined でなければ、inputProperties変換した値(sequence<DOMString>)を格納する。例外が thrown された場合は例外を投げて以降の手順を中止する。

    注: input properties getter が返す CSS プロパティのリストは、カスタムもしくはネイティブ CSS プロパティどちらでもよい。

    注: CSS プロパティのリストにはショートハンドも含まれる可能性がある。

    注: レイアウトクラスを将来互換にするには、ユーザーエージェントで現在無効な CSS プロパティも含めることができる(例:margin-bikeshed-property)。

  7. childInputProperties を空の sequence<DOMString> とする。

  8. childInputPropertiesIterableGet(layoutCtor, "childInputProperties") の結果とする。

  9. childInputPropertiesIterable が undefined でなければ、childInputProperties変換した値(sequence<DOMString>)を格納する。例外が thrown された場合は例外を投げて以降の手順を中止する。

  10. layoutOptionsValueGet(layoutCtor, "layoutOptions") の結果とする。

  11. layoutOptions変換した LayoutOptions とする。 例外が thrown された場合は例外を投げて以降の手順を中止する。

  12. IsConstructor(layoutCtor) が false なら、throwTypeError を投げて以降の手順を中止する。

  13. prototypeGet(layoutCtor, "prototype") の結果とする。

  14. Type(prototype) が Object でないなら throwTypeError を投げて以降の手順を中止する。

  15. intrinsicSizesGet(prototype, "intrinsicSizes") の結果とする。

  16. IsCallable(intrinsicSizes) が false なら throwTypeError を投げて以降の手順を中止する。

  17. intrinsicSizes[[FunctionKind]] 内部スロットが "generator" でないなら throwTypeError を投げて以降の手順を中止する。

  18. layoutGet(prototype, "layout") の結果とする。

  19. IsCallable(layout) が false なら throwTypeError を投げて以降の手順を中止する。

  20. layout[[FunctionKind]] 内部スロットが "generator" でないなら throwTypeError を投げて以降の手順を中止する。

  21. definition を新しい レイアウト定義として以下の内容で生成する:

  22. Set layoutDefinitionMap[name] に definition を設定する。

  23. Queue a task で以下を実行:

    1. documentLayoutDefinitionMap を関連づけられた document文書レイアウト定義 map とする。

    2. documentDefinition を新しい 文書レイアウト定義として以下の内容で生成する:

    3. documentLayoutDefinitionMap[name] が 存在する場合、以下を実行:

      1. existingDocumentDefinitionget(documentLayoutDefinitionMap[name]) の結果とする。

      2. existingDocumentDefinition"invalid" なら以降の手順を中止する。

      3. existingDocumentDefinitiondocumentDefinition が等価でない場合 (入力プロパティ子入力プロパティレイアウトオプション が異なる場合)、次を行う:

        Set documentLayoutDefinitionMap[name] に "invalid" を設定する。

        同じクラスが異なる inputPropertieschildInputPropertieslayoutOptions で登録された旨のエラーをデバッグコンソールに出力する。

    4. それ以外の場合は、set documentLayoutDefinitionMap[name] に documentDefinition を設定する。

注: クラスの形は以下のとおりです:
class MyLayout {
    static get inputProperties() { return ['--foo']; }
    static get childrenInputProperties() { return ['--bar']; }
    static get layoutOptions() {
      return {childDisplay: 'normal', sizing: 'block-like'}
    }

    *intrinsicSizes(children, edges, styleMap) {
        // 内在サイズの処理。
    }

    *layout(children, edges, constraints, styleMap, breakToken) {
        // レイアウト処理。
    }
}

5.5. レイアウトエンジン

Issue: 現在 API は generator 形式ですが、実装経験と web 開発者の意見によって、promise ベースの API に変更される可能性があります。どちらにも利点と欠点があります。

Promises

Generator

5.5.1. リクエストオブジェクト

[Exposed=LayoutWorklet]
interface IntrinsicSizesRequest {
};

[Exposed=LayoutWorklet]
interface LayoutFragmentRequest {
};

typedef (IntrinsicSizesRequest or LayoutFragmentRequest)
    LayoutFragmentRequestOrIntrinsicSizesRequest;

IntrinsicSizesRequest は内部スロット:

LayoutFragmentRequest は内部スロット:


著者定義の layout メソッドと intrinsic sizes メソッドは、通常の javascript 関数ではなく generator 関数となっています。これはユーザーエージェントが非同期・並列レイアウトエンジンをサポートするためです。

著者が layoutNextFragment()LayoutChild に呼び出すと、ユーザーエージェントは LayoutFragment を同期的に生成して返すのではなく、LayoutFragmentRequest を返します。これは著者には完全に不透明なオブジェクトですが、内部スロットとして layoutNextFragment() の呼び出し情報を持ちます。

LayoutFragmentRequest(複数の場合もある)が レイアウトジェネレーターオブジェクトから yield されると、ユーザーエージェントの レイアウトエンジンは、そのアルゴリズムを他の処理と非同期に、かつ/または別の実行スレッドで 実行することがある。エンジンによって LayoutFragment(複数の場合もある)が 生成されると、ユーザーエージェントは、結果として得られた LayoutFragment(複数の場合もある)でジェネレーターオブジェクトを「tick」 する。

intrinsicSizes() メソッドも同様です。

以下は javascript で書かれたレイアウトエンジンの例です。
class LayoutEngine {
  // rootBox、LayoutConstraints、BreakToken を受け取って LayoutFragment を生成する。
  layoutEntry(rootBox, rootPageConstraints, breakToken) {
    return layoutFragment({
      box: rootBox,
      layoutConstraints: rootPageConstraints,
      breakToken: breakToken,
    });
  }

  // LayoutFragmentRequest を受け取り、対応するレイアウトアルゴリズムを呼び出して LayoutFragment を生成する。
  layoutFragment(fragmentRequest) {
    const box = fragmentRequest.layoutChild;
    const algorithm = selectLayoutAlgorithmForBox(box);
    const fragmentRequestGenerator = algorithm.layout(
        fragmentRequest.layoutConstraints,
        box.children,
        box.styleMap,
        fragmentRequest.breakToken);

    let nextFragmentRequest = fragmentRequestGenerator.next();

    while (!nextFragmentRequest.done) {
      // UA はフラグメント生成を並列(別スレッド)で行うこともできる。例は同期処理のみ。
      let fragments = nextFragmentRequest.value.map(layoutFragment);

      // UA は他の処理(GC等)で yield することもできる。例は同期で進める。
      nextFragmentRequest = fragmentRequestGenerator.next(fragments);
    }

    return nextFragmentRequest.value; // 最終的な LayoutFragment を返す。
  }
}

5.6. レイアウトの実行

// 著者定義 layout() メソッドの最終返却値。
dictionary FragmentResultOptions {
    double inlineSize = 0;
    double blockSize = 0;
    double autoBlockSize = 0;
    sequence<LayoutFragment> childFragments = [];
    any data = null;
    BreakTokenOptions breakToken = null;
};

dictionary IntrinsicSizesResultOptions {
    double maxContentSize;
    double minContentSize;
};

5.6.1. 内在サイズの決定

内在サイズの決定アルゴリズムは、ユーザーエージェントが著者定義レイアウトから box内在サイズ情報を取得する方法を定義します。

注: 内在サイズの決定アルゴリズムは、ユーザーエージェントが過去の呼び出し結果を任意の数キャッシュして再利用できるようにしています。

ユーザーエージェントが、与えられた box, childBoxesLayout API フォーマッティングコンテキスト内在サイズの決定をしたい場合、以下の手順を必ず実行します:
  1. layoutFunctionboxlayout()計算値<display-inside>)とする。

  2. layoutFunction内在サイズ有効フラグintrinsic-sizes-valid なら、ユーザーエージェントは前回の内在サイズ値を再利用してもよい。その場合は以降の手順を中止してキャッシュ値を使う。

  3. layoutFunction内在サイズ有効フラグintrinsic-sizes-valid に設定する。

  4. namelayoutFunction の第1引数とする。

  5. documentDefinition文書レイアウト定義取得name指定)した結果とする。

    もし 文書レイアウト定義取得 が失敗、または documentDefinition"invalid" なら、 boxflow layout にフォールバックし、以降の手順を中止。

  6. workletGlobalScope をレイアウト LayoutWorkletGlobalScopeWorkletGlobalScopesリストから取得)とする。

    ユーザーエージェントは、リストに少なくとも2つの LayoutWorkletGlobalScope を持ち、選択しなければならない(メモリ制約下を除く)。

    注: グローバルオブジェクトやクラス上の再生成不可能な状態に依存しないための仕様です。

    また、ユーザーエージェントはこのタイミングでレイアウト Workletに対して WorkletGlobalScope を作成してもよい。

  7. 内在サイズコールバック呼び出しname, box, childBoxes, workletGlobalScope、必要に応じて並列で実行)を実行する。

    注: ユーザーエージェントがintrinsic sizes コールバックを呼び出す処理を スレッド上で並列に 実行する場合、そのスレッドで使用できるレイアウトワークレットグローバルスコープを 選択するべきである。

ユーザーエージェントが、nameboxchildBoxes、および workletGlobalScope を指定して内在サイズコールバックを呼び出す場合、次の 手順を実行しなければならない:
  1. definition を、name および workletGlobalScope を指定して レイアウト 定義を取得する処理の結果とする。

    レイアウト定義を取得する処理が失敗を返した場合、 boxフロー レイアウトにフォールバックさせ、これらの手順をすべて中止する。

  2. layoutInstance を、boxdefinitionworkletGlobalScope を指定して レイアウト クラスインスタンスを取得する処理の結果とする。

    レイアウトクラスインスタンスを取得する処理が失敗を返した場合、 boxフロー レイアウトにフォールバックさせ、これらの手順をすべて中止する。

  3. inputPropertiesdefinition入力プロパティとする。

  4. children を新しいリストとする。

  5. childBoxes 内の各 childBox についてそれぞれ次のサブステップを 実行する:

    1. layoutChild を、workletGlobalScopename、および childBox を指定して レイアウト子を取得する 処理の結果とする。

    2. layoutChildchildren付加する

  6. edges を、box のすべてのボックス モデルの辺についての算出値を設定した新しい LayoutEdgeSizes とする。

  7. styleMap を、box について inputProperties に列挙されたプロパティの算出値のみを設定した新しい StylePropertyMapReadOnly とする。

    layoutInstance と同様に、 代わりに styleMapbox に保存することを検討してもよい。

  8. この段階で、childrenstyleMap が前回の呼び出しと同等である場合、 ユーザーエージェントは前回の呼び出しによる内在サイズを再利用してもよい。その場合、 内在サイズをキャッシュされた内在サイズとし、これらの手順をすべて中止する。

  9. intrinsicSizesGeneratorFunctiondefinition内在サイズジェネレーター 関数とする。

  10. intrinsicSizesGenerator呼び出す(intrinsicSizesGeneratorFunction, layoutInstance, «children, edges, styleMap») の結果とする。

    例外がスローされた場合、boxフローレイアウトにフォールバックさせ、これらの手順を すべて中止する。

  11. intrinsicSizesValue を、intrinsicSizesGenerator および "intrinsic-sizes" を指定して ジェネレーターを実行する処理の結果とする。

    ジェネレーターを 実行する処理が失敗を返した場合、boxフロー レイアウトにフォールバックさせ、これらの手順をすべて中止する。

  12. intrinsicSizes を、intrinsicSizesValueIntrinsicSizesResultOptions変換する処理の結果とする。 例外がスローされた場合、boxフローレイアウトにフォールバックさせ、これらの手順をすべて中止する。

  13. box内在サイズを設定する:

5.6.2. フラグメント生成

フラグメント生成アルゴリズムは、ユーザーエージェントが著者定義レイアウト用の boxfragment を生成する方法を定義します。

注: フラグメント生成アルゴリズムも、ユーザーエージェントが過去の呼び出し結果を任意の数キャッシュして再利用できるようになっています。

ユーザーエージェントが、指定された boxchildBoxesinternalLayoutConstraints、および オプションの internalBreakToken に対して、Layout API 整形 コンテキストフラグメントを生成する場合、次の手順を実行しなければならない:
  1. layoutFunction を、box に対する <display-inside>算出値layout() とする。

  2. layoutFunctionレイアウト 有効フラグレイアウト有効である場合、ユーザー エージェントは前回の呼び出しによる内在サイズを使用してもよい。その場合、これらの手順をすべて 中止し、内在サイズに前回の値を使用してもよい。

  3. layoutFunctionレイアウト 有効フラグレイアウト有効に設定する。

  4. namelayoutFunction の第 1 引数とする。

  5. documentDefinition を、name を指定して 文書 レイアウト定義を取得する処理の結果とする。

    文書レイアウト定義を取得する処理が failure を返した場合、または documentDefinition"invalid" である場合、 boxフロー レイアウトにフォールバックさせ、これらの手順をすべて 中止する。

  6. workletGlobalScope を、レイアウト Workletワークレットの WorkletGlobalScopes のリストから選択した LayoutWorkletGlobalScope とする。

    ユーザーエージェントは、メモリ制約下にある場合を除き、ワークレットの WorkletGlobalScopesリスト内に、 少なくとも 2 つの LayoutWorkletGlobalScopeを 保持し、その中から選択しなければならない。

    注: これは、作者がグローバル オブジェクトに状態を保存できること、またはクラスに再生成不可能な状態を保存できることに依存しないようにするためである。

    ユーザーエージェントは、この時点で、レイアウト Worklet を指定して、WorkletGlobalScope を作成することもできる。

  7. nameboxchildBoxesinternalLayoutConstraintsinternalBreakToken、および workletGlobalScope を指定して、必要に応じて 並列に レイアウトコールバックを呼び出す処理を実行する。

    注: ユーザーエージェントがintrinsic sizes コールバックを呼び出す処理を スレッド上で並列に 実行する場合、そのスレッドで使用できるレイアウトワークレットグローバルスコープを 選択するべきである。

ユーザーエージェントが、nameboxchildBoxesinternalLayoutConstraintsinternalBreakToken、および workletGlobalScope を指定してレイアウトコールバックを呼び出す場合、次の 手順を実行しなければならない:
  1. definition を、name および workletGlobalScope を指定して レイアウト 定義を取得する処理の結果とする。

    レイアウト定義を取得する処理が failure を返した場合、 boxフロー レイアウトにフォールバックさせ、これらの手順をすべて中止する。

  2. layoutInstance を、boxdefinitionworkletGlobalScope を指定して レイアウト クラスインスタンスを取得する処理の結果とする。

    レイアウトクラスインスタンスを取得する処理が failure を返した場合、 boxフロー レイアウトにフォールバックさせ、これらの手順をすべて中止する。

  3. sizingModedefinitionレイアウトオプションsizing プロパティとする。

  4. inputPropertiesdefinition入力プロパティとする。

  5. children を新しいリストとする。

  6. childBoxes 内の各 childBox についてそれぞれ次のサブステップを実行する:

    1. layoutChild を、workletGlobalScopename、および childBox を指定して レイアウト子を取得する 処理の結果とする。

    2. layoutChildchildren付加する

  7. edges を、box のすべての ボックス モデルの辺についての 算出値を設定した新しい LayoutEdgeSizes とする。

  8. layoutConstraints を、internalLayoutConstraintsbox、および sizingMode を指定して レイアウト制約オブジェクトを作成する処理の結果とする。

  9. styleMap を、box について inputProperties に列挙されたプロパティの算出値のみを設定した、新しい StylePropertyMapReadOnly とする。

    代わりに、 layoutInstance と同様に styleMapbox に保存することを検討してもよい。

  10. breakToken を、internalBreakToken から適切な情報を設定した新しい BreakToken とする。

    internalBreakToken が null の場合、breakToken を null とする。

  11. この段階で、childrenstyleMaplayoutConstraintsbreakToken が以前の呼び出しと同等である場合、ユーザーエージェントは以前の呼び出しによる フラグメントを 再利用してもよい。その場合、フラグメント出力をそのキャッシュされたフラグメントとし、これらの手順をすべて中止する。

  12. layoutGeneratorFunctiondefinitionレイアウトジェネレーター関数とする。

  13. layoutGenerator呼び出す(layoutGeneratorFunction, layoutInstance, «children, edges, layoutConstraints, styleMap, breakToken») の結果とする。

    例外がスローされた場合、boxフローレイアウトにフォールバックさせ、これらの手順を すべて中止する。

  14. fragmentValue を、layoutGenerator および "layout" を指定して ジェネレーターを実行する処理の結果とする。

    ジェネレーターを 実行する処理が failure を返した場合、boxフロー レイアウトにフォールバックさせ、これらの手順をすべて中止する。

  15. fragment を、fragmentValueFragmentResultOptions変換する処理の結果とする。 例外がスローされた場合、boxフローレイアウトにフォールバックさせ、これらの手順をすべて中止する。

  16. fragmentchildFragments 内の各 childFragment についてそれぞれ次のサブステップを実行する:

    1. childFragment[[generator]] 内部スロットが layoutGenerator と等しくない場合、 boxフローレイアウトにフォールバックさせ、これらの手順をすべて中止する。

  17. sizingMode"block-like" の場合:

    • 次のようにする:

      1. inlineSizelayoutConstraintsfixedInlineSize とする。("block-like" サイズ指定を使用する場合、この 値は設定されていなければならない)。

      2. blockSize を、fragmentautoBlockSize を「内在 高さ」として、ブロックコンテナの場合とまったく同様に boxborder-box ブロックサイズbox の 書字モードを基準とする)を計算した結果とする。

    • それ以外の場合(sizingMode"manual" の場合):

      1. inlineSizefragmentinlineSize とする。

      2. blockSizefragmentblockSize とする。

  18. box に対して、次の内容を持つ フラグメントを返す:

5.6.3. ユーティリティアルゴリズム

このセクションでは、内在サイズの決定アルゴリズムとフラグメント生成アルゴリズムで共通して使われるアルゴリズムを示します。

ユーザーエージェントが文書レイアウト定義取得nameで行いたいとき、以下の手順を必ず実行します:
  1. documentLayoutDefinitionMapを、関連するdocument文書レイアウト定義mapとする。

  2. documentLayoutDefinitionMap[name]が存在しない場合、失敗を返して以降の手順を中止する。

  3. get documentLayoutDefinitionMap[name]の結果を返す。

ユーザーエージェントがレイアウト定義取得nameworkletGlobalScopeで行いたいとき、以下の手順を必ず実行します:
  1. layoutDefinitionMapworkletGlobalScopeレイアウト定義mapとする。

  2. layoutDefinitionMap[name]が存在しない場合、以下を実行:

    1. Queue a taskで以下を実行:

      1. documentLayoutDefinitionMapを関連するdocument文書レイアウト定義mapとする。

      2. Set documentLayoutDefinitionMap[name]に"invalid"を設定する。

      3. ユーザーエージェントは、すべてのLayoutWorkletGlobalScopeでクラスが登録されていない旨のエラーをデバッグコンソールに推奨で出力するべきです。

    2. 失敗を返して、以降の手順を中止する。

  3. get layoutDefinitionMap[name]の結果を返す。

ユーザーエージェントがレイアウトクラスインスタンス取得boxdefinitionworkletGlobalScopeで行いたいとき、以下の手順を必ず実行します:
  1. layoutClassInstanceMapboxレイアウトクラスインスタンスmapとする。

  2. layoutInstanceget layoutClassInstanceMap[workletGlobalScope]の結果とする。layoutInstanceがnullの場合、以下を実行:

    1. definitionコンストラクター有効フラグがfalseの場合、失敗を返して以降の手順を中止する。

    2. layoutCtordefinitionクラスコンストラクターとする。

    3. layoutInstanceConstruct(layoutCtor)の結果とする。

      constructが例外を投げた場合はdefinitionコンストラクター有効フラグをfalseに設定し、失敗を返して以降の手順を中止する。

    4. Set layoutClassInstanceMap[workletGlobalScope]にlayoutInstanceを設定する。

  3. layoutInstanceを返す。

ユーザーエージェントがジェネレーター実行generatorgeneratorTypeで行いたいとき、以下の手順を必ず実行します:
  1. donefalseで初期化したbooleanとする。

  2. nextValueをundefinedとする。

  3. donetrueになるまで以下を繰り返す:

    1. nextFunctionGet(generator, "next")の結果とする。

    2. IsCallable(nextFunction)がfalseならthrowTypeErrorを投げて以降の手順を中止する。

    3. nextResultInvoke(nextFunction, generator, «nextValue»)の結果とする。

      例外発生時は失敗を返して以降の手順を中止する。

    4. Type(nextResult)がObjectでない場合はthrowTypeErrorを投げて以降の手順を中止する。

    5. requestOrRequestsGet(nextResult, "value")の結果とする。

    6. doneGet(nextResult, "done")の結果とする。

    7. GetMethod(requestOrRequests, @@iterable)が存在する場合:

      1. resultsリストとする。

      2. requests変換(requestOrRequestssequence<LayoutFragmentRequestOrIntrinsicSizesRequest>へ)したものとする。

        例外発生時は例外を投げて以降の手順を中止する。

      3. request について:

        1. resultジェネレーター結果生成(request, generator, generatorType)したものとする。

        2. Append resultresultsに追加。

      4. nextValueresultsに設定する。

      5. 続行。

    8. request変換(requestOrRequestsLayoutFragmentRequestOrIntrinsicSizesRequestへ)したものとする。

      例外発生時は例外を投げて以降の手順を中止する。

    9. resultジェネレーター結果生成(request, generator, generatorType)したものとする。

      ジェネレーター結果生成が失敗を返した場合、失敗を返して以降の手順を中止する。

    10. nextValueresultに設定する。

    11. 続行。

    ユーザーエージェントは上記ループを順不同・並列で実行してもよい。ただしrequestsresultsの順序は必ず一貫性が必要。

    注: これはユーザーエージェントが適切なレイアウトアルゴリズムを別スレッドや非同期(例えば他の処理とタイムスライス)で実行可能にするためです。並列実行の場合、外側ループは全スレッドの完了を待ってからジェネレーターを再度呼び出す必要があります。著者に部分結果を返してはいけません。

  4. Get(nextResult, "value")の結果を返す。

ユーザーエージェントがジェネレーター結果生成requestgeneratorgeneratorTypeで行いたいとき、以下の手順を必ず実行します:
  1. requestIntrinsicSizesRequestなら:

    1. layoutChildrequestの内部スロット[[layoutChild]]から取得。

    2. boxlayoutChildの内部スロット[[box]]から取得。

    3. boxbox tree接続されていないなら、失敗を返して中止する。

      注: 著者は前の呼び出しからLayoutChildを保持する場合がありますが、boxは一度だけbox-treeに接続され、再利用されないことが想定されています。

    4. internalIntrinsicSizesをユーザーエージェントがboxborder boxのmin/max content contributionを計算した結果とする。

    5. 内在サイズオブジェクト生成(request, internalIntrinsicSizes)の結果を返す。

  2. requestLayoutFragmentRequestかつgeneratorType"layout"なら:

    1. layoutChildrequestの内部スロット[[layoutChild]]から取得。

    2. boxlayoutChildの内部スロット[[box]]から取得。

    3. boxbox tree接続されていないなら、失敗を返して中止する。

      注: 著者は前の呼び出しからLayoutChildを保持する場合がありますが、boxは一度だけbox-treeに接続され、再利用されないことが想定されています。

    4. childLayoutConstraintsrequestの内部スロット[[layoutConstraints]]から取得。

    5. childBreakTokenrequestの内部スロット[[breakToken]]から取得。

    6. internalFragmentをユーザーエージェントがboxchildLayoutConstraintschildBreakTokenから生成したfragmentとする。

    7. レイアウトフラグメント生成(generator, request, internalFragment)の結果を返す。

  3. (上記分岐に該当しない場合)失敗を返す。

6. セキュリティ考慮事項

これらの機能によって新たなセキュリティ問題は知られていません。

7. プライバシー考慮事項

これらの機能によって新たなプライバシー問題は知られていません。

適合性

文書の規約

適合性要件は、記述的な断言とRFC 2119の用語を組み合わせて表現されています。主要語「MUST」, 「MUST NOT」, 「REQUIRED」, 「SHALL」, 「SHALL NOT」, 「SHOULD」, 「SHOULD NOT」, 「RECOMMENDED」, 「MAY」, 「OPTIONAL」は、規範的な部分においてRFC 2119の定義通りに解釈されます。 ただし、可読性を高めるため、本仕様ではこれらの語はすべて大文字では表記されていません。

本仕様の全てのテキストは、明示的に非規範的と記載されたセクション、例、および注記を除き規範的です。 [RFC2119]

本仕様の例は、「例えば」という語で始まるか、class="example"を用いて規範的な本文から区別されています。例えば:

これは情報提供的な例です。

情報提供的な注記は「注:」で始まり、class="note"で規範的な本文から区別されています。例えば:

注: これは情報提供的な注記です。

勧告は規範的なセクションであり、特別な注意を喚起するようにスタイリングされ、<strong class="advisement">で他の規範的な本文と区別されます。例えば: UAは必ずアクセシブルな代替手段を提供しなければなりません。

適合性クラス

本仕様への適合性は、次の三つの適合性クラスで定義されます:

スタイルシート
CSS スタイルシート
レンダラー
UAで、スタイルシートの意味を解釈し、それを用いる文書をレンダリングするもの。
オーサリングツール
UAで、スタイルシートを作成するもの。

本モジュールで定義された構文を用いる全ての文が、汎用CSS文法および各機能の個別文法に従って有効である場合、そのスタイルシートは本仕様に適合しているとみなされます。

レンダラーは、スタイルシートを適切な仕様通りに解釈することに加えて、本仕様で定義された全ての機能を正しく解析し、文書を適切にレンダリングすることで本仕様に適合しているとみなされます。ただし、デバイスの制限によりUAが文書を正しくレンダリングできない場合でも、そのUAは非適合とはなりません。(例えば、UAは白黒モニター上で色を表示する必要はありません。)

オーサリングツールは、汎用CSS文法および本モジュールの各機能ごとの文法に従い構文的に正しいスタイルシートを書き、さらに本モジュールで記載されたスタイルシートの全ての適合性要件を満たしている場合、本仕様に適合しています。

部分実装

著者が将来互換性のあるパース規則を活用してフォールバック値を指定できるよう、CSSレンダラーは必ず、有効なレベルのサポートがない at-規則、プロパティ、プロパティ値、キーワード、その他の構文を無効として(必要に応じて無視)扱う必要があります。特に、ユーザーエージェントは絶対に、単一の複数値プロパティ宣言で未サポートの値だけを無視してサポートされている値を適用することをしてはなりません。値の一部が無効とみなされる場合(未サポート値は必ず無効とみなされる)、CSSでは宣言全体を無視する必要があります。

不安定及び独自機能の実装について

将来の安定したCSS機能との衝突を避けるため、CSSWGはベストプラクティスに従った不安定機能および独自拡張機能の実装を推奨します。

非実験的実装

仕様がCandidate Recommendationの段階に到達すると、非実験的な実装が可能となり、実装者は仕様通りに正しく実装できるCRレベルの機能については、ベンダープレフィックスなしの実装をリリースすべきです。

CSSの実装間で相互運用性を確立・維持するため、CSSワーキンググループは、非実験的なCSSレンダラーが実装レポート(必要に応じてそのテストケースも含む)をW3Cに提出することを推奨します。W3Cに提出されたテストケースはCSSワーキンググループによってレビュー・修正される場合があります。

テストケースおよび実装レポートの提出方法については、CSSワーキンググループのウェブサイト https://www.w3.org/Style/CSS/Test/ を参照してください。 質問は public-css-testsuite@w3.org メーリングリストまで。

索引

本仕様で定義されている用語

参照によって定義される用語

参考文献

規範参照文献

[CSS-BREAK-3]
Rossen Atanassov; Elika Etemad. CSS Fragmentation Module Level 3. 2017年2月9日. CR. URL: https://www.w3.org/TR/css-break-3/
[CSS-CASCADE-4]
Elika Etemad; Tab Atkins Jr.. CSS Cascading and Inheritance Level 4. 2016年1月14日. CR. URL: https://www.w3.org/TR/css-cascade-4/
[CSS-FLEXBOX-1]
Tab Atkins Jr.; Elika Etemad; Rossen Atanassov. CSS Flexible Box Layout Module Level 1. 2017年10月19日. CR. URL: https://www.w3.org/TR/css-flexbox-1/
[CSS-GRID-1]
Tab Atkins Jr.; Elika Etemad; Rossen Atanassov. CSS Grid Layout Module Level 1. 2017年12月14日. CR. URL: https://www.w3.org/TR/css-grid-1/
[CSS-INLINE-3]
Dave Cramer; Elika Etemad; Steve Zilles. CSS Inline Layout Module Level 3. 2016年5月24日. WD. URL: https://www.w3.org/TR/css-inline-3/
[CSS-OVERFLOW-3]
David Baron; Florian Rivoal. CSS Overflow Module Level 3. 2016年5月31日. WD. URL: https://www.w3.org/TR/css-overflow-3/
[CSS-PAGE-FLOATS-3]
Johannes Wilm. CSS Page Floats. 2015年9月15日. WD. URL: https://www.w3.org/TR/css-page-floats-3/
[CSS-POSITION-3]
Rossen Atanassov; Arron Eicholz. CSS Positioned Layout Module Level 3. 2016年5月17日. WD. URL: https://www.w3.org/TR/css-position-3/
[CSS-PSEUDO-4]
Daniel Glazman; Elika Etemad; Alan Stearns. CSS Pseudo-Elements Module Level 4. 2016年6月7日. WD. URL: https://www.w3.org/TR/css-pseudo-4/
[CSS-RUBY-1]
Elika Etemad; Koji Ishii. CSS Ruby Layout Module Level 1. 2014年8月5日. WD. URL: https://www.w3.org/TR/css-ruby-1/
[CSS-SIZING-3]
Tab Atkins Jr.; Elika Etemad. CSS Intrinsic & Extrinsic Sizing Module Level 3. 2018年3月4日. WD. URL: https://www.w3.org/TR/css-sizing-3/
[CSS-SYNTAX-3]
Tab Atkins Jr.; Simon Sapin. CSS Syntax Module Level 3. 2014年2月20日. CR. URL: https://www.w3.org/TR/css-syntax-3/
[CSS-TYPED-OM-1]
Shane Stephens; Tab Atkins Jr.. CSS Typed OM Level 1. 2017年8月1日. WD. URL: https://www.w3.org/TR/css-typed-om-1/
[CSS-VALUES-3]
Tab Atkins Jr.; Elika Etemad. CSS Values and Units Module Level 3. 2016年9月29日. CR. URL: https://www.w3.org/TR/css-values-3/
[CSS-WRITING-MODES-3]
Elika Etemad; Koji Ishii. CSS Writing Modes Level 3. 2017年12月7日. CR. URL: https://www.w3.org/TR/css-writing-modes-3/
[CSS21]
Bert Bos; et al. Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification. 2011年6月7日. REC. URL: https://www.w3.org/TR/CSS2/
[CSS22]
Bert Bos. Cascading Style Sheets Level 2 Revision 2 (CSS 2.2) Specification. 2016年4月12日. WD. URL: https://www.w3.org/TR/CSS22/
[CSS3-DISPLAY]
Elika Etemad. CSS Display Module Level 3. 2017年7月20日. WD. URL: https://www.w3.org/TR/css-display-3/
[CSSOM-1]
Simon Pieters; Glenn Adams. CSS Object Model (CSSOM). 2016年3月17日. WD. URL: https://www.w3.org/TR/cssom-1/
[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. 1997年3月. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119
[WebIDL]
Cameron McCormack; Boris Zbarsky; Tobie Langel. Web IDL. 2016年12月15日. ED. URL: https://heycam.github.io/webidl/
[WORKLETS-1]
Ian Kilpatrick. Worklets Level 1. 2016年6月7日. WD. URL: https://www.w3.org/TR/worklets-1/

参考情報

[CSS-BACKGROUNDS-3]
Bert Bos; Elika Etemad; Brad Kemper. CSS Backgrounds and Borders Module Level 3. 2017年10月17日. CR. URL: https://www.w3.org/TR/css-backgrounds-3/
[CSS-MULTICOL-1]
Håkon Wium Lie; Florian Rivoal; Rachel Andrew. CSS Multi-column Layout Module Level 1. 2017年10月5日. WD. URL: https://www.w3.org/TR/css-multicol-1/

IDL索引

[Exposed=LayoutWorklet]
interface LayoutChild {
    readonly attribute StylePropertyMapReadOnly styleMap;

    IntrinsicSizesRequest intrinsicSizes();
    LayoutFragmentRequest layoutNextFragment(LayoutConstraints constraints, ChildBreakToken breakToken);
};

[Exposed=LayoutWorklet]
interface LayoutFragment {
    readonly attribute double inlineSize;
    readonly attribute double blockSize;

    attribute double inlineOffset;
    attribute double blockOffset;

    readonly attribute any data;

    readonly attribute ChildBreakToken? breakToken;
};

[Exposed=LayoutWorklet]
interface IntrinsicSizes {
  readonly attribute double minContentSize;
  readonly attribute double maxContentSize;
};

[Constructor(optional LayoutConstraintsOptions options),Exposed=LayoutWorklet]
interface LayoutConstraints {
    readonly attribute double availableInlineSize;
    readonly attribute double availableBlockSize;

    readonly attribute double? fixedInlineSize;
    readonly attribute double? fixedBlockSize;

    readonly attribute double percentageInlineSize;
    readonly attribute double percentageBlockSize;

    readonly attribute double? blockFragmentationOffset;
    readonly attribute BlockFragmentationType blockFragmentationType;

    readonly attribute any data;
};

dictionary LayoutConstraintsOptions {
    double availableInlineSize = 0;
    double availableBlockSize = 0;

    double fixedInlineSize;
    double fixedBlockSize;

    double percentageInlineSize;
    double percentageBlockSize;

    double blockFragmentationOffset;
    BlockFragmentationType blockFragmentationType = "none";

    any data;
};

enum BlockFragmentationType { "none", "page", "column", "region" };

[Exposed=LayoutWorklet]
interface ChildBreakToken {
    readonly attribute BreakType breakType;
    readonly attribute LayoutChild child;
};

[Exposed=LayoutWorklet]
interface BreakToken {
    readonly attribute sequence<ChildBreakToken> childBreakTokens;
    readonly attribute any data;
};

dictionary BreakTokenOptions {
    sequence<ChildBreakToken> childBreakTokens;
    any data = null;
};

enum BreakType { "none", "line", "column", "page", "region" };

[Exposed=LayoutWorklet]
interface LayoutEdgeSizes {
  readonly attribute double inlineStart;
  readonly attribute double inlineEnd;

  readonly attribute double blockStart;
  readonly attribute double blockEnd;

  // Convenience attributes for the sum in one direction.
  readonly attribute double inline;
  readonly attribute double block;
};

[Exposed=LayoutWorklet]
interface LayoutEdges {
  readonly attribute LayoutEdgeSizes border;
  readonly attribute LayoutEdgeSizes scrollbar;
  readonly attribute LayoutEdgeSizes padding;

  readonly attribute LayoutEdgeSizes all;
};

partial interface CSS {
    [SameObject] readonly attribute Worklet layoutWorklet;
};

[Global=(Worklet,LayoutWorklet),Exposed=LayoutWorklet]
interface LayoutWorkletGlobalScope : WorkletGlobalScope {
    void registerLayout(DOMString name, VoidFunction layoutCtor);
};

[Exposed=LayoutWorklet]
dictionary LayoutOptions {
  ChildDisplayType childDisplay = "block";
  LayoutSizingMode sizing = "block-like";
};

[Exposed=LayoutWorklet]
enum ChildDisplayType {
    "block",
    "normal",
};

[Exposed=LayoutWorklet]
enum LayoutSizingMode {
    "block-like",
    "manual",
};

[Exposed=LayoutWorklet]
interface IntrinsicSizesRequest {
};

[Exposed=LayoutWorklet]
interface LayoutFragmentRequest {
};

typedef (IntrinsicSizesRequest or LayoutFragmentRequest)
    LayoutFragmentRequestOrIntrinsicSizesRequest;

// This is the final return value from the author defined layout() method.
dictionary FragmentResultOptions {
    double inlineSize = 0;
    double blockSize = 0;
    double autoBlockSize = 0;
    sequence<LayoutFragment> childFragments = [];
    any data = null;
    BreakTokenOptions breakToken = null;
};

dictionary IntrinsicSizesResultOptions {
    double maxContentSize;
    double minContentSize;
};

課題索引

課題: 現在APIは反復可能なジェネレーター形式です。実装経験やWeb開発者の意見に基づき、将来的にPromiseベースのAPIへ変更される可能性があります。それぞれに長所と短所があります。

Promise

ジェネレーター

styleMapboxに保持するべきかもしれません。layoutInstanceのように。
styleMapboxに保持するべきかもしれません。layoutInstanceのように。