CSS Houdini's Layout API explained
Tags: javascript, webdev, css, tutorial
Published: 2020-07-20 05:40:06

<small>This post has been [originally published on Smashing Magazine](https://www.smashingmagazine.com/2020/03/practical-overview-css-houdini/) and I decided to split it into parts to make it more digestible. I'll be converting the post into markdown and publish a part of it on DEV every week. If you want to read it right away in its entirety, feel free to read it on Smashing Magazine until all parts are available on DEV. Thank you.</small>

<hr/>


## Layout API
<p>The <em>Layout</em> API allows developers to extend the browser’s layout rendering process by defining new layout
    modes that can be used in <code>display</code> CSS property. Layout API introduces new concepts, is very complex and
    offers a lot of options for developing custom layout algorithms.</p>
<p>Similarly to other Worklets, the layout Worklet needs to be registered and defined first.</p>

```js
registerLayout('exampleLayout', class {
  static get inputProperties() { return ['--exampleVariable']; }

  static get childrenInputProperties() { return ['--exampleChildVariable']; }

  static get layoutOptions() {
    return {
      childDisplay: 'normal',
      sizing: 'block-like'
    };
  }

  intrinsicSizes(children, edges, styleMap) {
    /* ... */
  }

  layout(children, edges, constraints, styleMap, breakToken) {
    /* ... */
  }
});
```

<p>Worklet register contains the following methods:</p>
<ul>
    <li><code>inputProperties</code>: An array of CSS custom properties that the Worklet will keep track of that
        belongs to a Parent Layout element, i.e. the element that calls this layout. This array represents dependencies
        of a Layout Worklet.</li>
    <li><code>childrenInputProperties</code>: An array of CSS custom properties that the Worklet will keep track of
        that belong to child elements of a Parent Layout element, i.e. the children of the elements that set this
        layout.</li>
    <li><code>layoutOptions</code>: defines the following layout properties:<ul>
            <li><code>childDisplay</code>: can have a pre-defined value of <code>block</code> or <code>normal</code>.
                Determines if the boxes will be displayed as blocks or inline.</li>
            <li><code>sizing</code>: can have a pre-defined value of <code>block-like</code> or <code>manual</code>. It
                tells the browser to either pre-calculate the size or not to pre-calculate (unless a size is explicitly
                set), respectively.</li>
        </ul>
    </li>
    <li><code>intrinsicSizes</code>: defines how a box or its content fits into a layout context.<ul>
            <li><code>children</code>: child elements of a Parent Layout element, i.e. the children of the element that
                call this layout.</li>
            <li><code>edges</code>: Layout Edges of a box</li>
            <li><code>styleMap</code>: typed OM styles of a box</li>
        </ul>
    </li>
    <li><code>layout</code>: the main function that performs a layout.<ul>
            <li><code>children</code>: child elements of a Parent Layout element, i.e. the children of the element that
                call this layout.</li>
            <li><code>edges</code>: Layout Edges of a box</li>
            <li><code>constraints</code>: constraints of a Parent Layout</li>
            <li><code>styleMap</code>: typed OM styles of a box</li>
            <li><code>breakToken</code>: break token used to resume a layout in case of pagination or printing.</li>
        </ul>
    </li>
</ul>
<p>Like in the case of a Paint API, the browser rendering engine determines when the paint Worklet is being called. It
    only needs to be added to an HTML or main JavaScript file.</p>

```js
CSS.layoutWorklet.addModule('path/to/worklet/file.js');
```

<p>And, finally, it needs to be referenced in a CSS file</p>

```css
.exampleElement {
  display: layout(exampleLayout);
}
```

<h3>How Layout API Performs Layout</h3>
<p>In the previous example, <code>exampleLayout</code> has been defined using the Layout API.</p>

```css
.exampleElement {
  display: layout(exampleLayout);
}
```

<p>This element is called a <strong>Parent Layout</strong> that is enclosed with <strong>Layout Edges</strong> which
    consists of paddings, borders and scroll bars. Parent Layout consists of child elements which are called
    <strong>Current Layouts</strong>. Current Layouts are the actual target elements whose layout can be customized
    using the Layout API. For example, when using <code>display: flex;</code> on an element, its children are being
    repositioned to form the flex layout. This is similar to what is being done with the Layout API.</p>
<p>Each <strong>Current Layout</strong> consists of <strong>Child Layout</strong> which is a layout algorithm for the
    LayoutChild (element, <code>::before</code> and <code>::after</code> pseudo-elements) and
    <strong>LayoutChild</strong> is a CSS generated box that only contains style data (no layout data). LayoutChild
    elements are automatically created by browser rendering engine on style step. Layout Child can generate a
    <strong>Fragment</strong> which actually performs layout render actions.</p>
<h3>Example</h3>
<p>Similarly to the Paint API example, this example is importing a masonry layout Worklet directly from <a
        href="https://github.com/GoogleChromeLabs/houdini-samples/blob/master/layout-worklet/masonry/masonry.js">Google
        Chrome Labs repository</a>, but in this example, it’s used with image content instead of text. Complete source
    code is available on the <a
        href="https://github.com/codeAdrian/houdini-examples/tree/master/layout-api-example">example repository</a>.</p>

<figure>
![Masonry layout example](https://dev-to-uploads.s3.amazonaws.com/i/w68919j76r0thw9sgoum.gif)
<figcaption>Masonry layout example (uses Masonry Worklet by Google Chrome Labs</figcaption>
</figure>

<h3>Feature Detection</h3>

```js
if (CSS.layoutWorklet) {
  /* ... */
}
```

<h3>W3C Specification Status</h3>
<ul>
    <li><a href="https://drafts.css-houdini.org/css-layout-api/">First Public Working Draft</a>: ready for community
        review, prone to specification change</li>
</ul>
<h3>Browser Support</h3>
<table>
    <thead>
        <tr>
            <th>Google Chrome</th>
            <th>Microsoft Edge</th>
            <th>Opera Browser</th>
            <th>Firefox</th>
            <th>Safari</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Partial support (*)</td>
            <td>Partial support (*)</td>
            <td>Partial support (*)</td>
            <td>Not supported</td>
            <td>Not supported</td>
        </tr>
    </tbody>
</table>
<p><sup>*</sup> <em>supported with “Experimental Web Platform features” flag enabled.</em></p>
<p><em>Data source: <a href="https://ishoudinireadyyet.com/">Is Houdini Ready Yet?</a></em></p>


<hr/>
These articles are fueled by coffee. So if you enjoy my work and found it useful, consider buying me a coffee! I would really appreciate it.

<a href="https://www.buymeacoffee.com/ubnZ8GgDJ" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-red.png" alt="Buy Me A Coffee" style="height: 51px !important;width: 217px !important;" ></a>

Thank you for taking the time to read this post. Keep an eye out for the next part in the series. If you've found this useful, please give it a ❤️ or 🦄, share and comment.