LAYOUT API

The CSS Layout API Level 1, or Layout API for short, lets us play Tetris with our site, unleashing all sorts of new creative possibilities.

Try it out!

The layout of the header is powered by the Layout API! Change the value of --padding and --offset to see how the letters change position!

.layout-api { display: layout(blueprint); --padding: 5; --offset: .25; }

Layout API Concepts

The Layout API introduces and uses a number of concepts that may be unfamiliar, so we're going to go over them before diving in.

Layout Overview

An overview of how the Layout API "thinks". We start at the Current Layout, which is the layout algorithm for the current box we're laying out. That element's direct parent, the element with the display: layout(custom) on it that's requesting layout be performed, is the Parent Layout. The Parent Layout has borders, padding, and scroll bars, and those collectively are its Layout Edges; the remaining space after we remove the Layout Edges, where we can actually lay out a Parent Layout's children is the Layout Constraints. The Child Layout is the layout algorithm for the LayoutChild of the Current Layout (I know, a little confusing, bear with me.

The LayoutChild is basically a container to calculate stuff from, and only gets generated under certain conditions. The LayoutChild can be used to generate a Fragment, which is used to actually perform layout

LayoutChild Overview

A LayoutChild has two main bits of functionality; the first is including the Typed OM styleMap of all properties that the layout says it wants (via childInputProperties) (think like grid-column in CSS Grid for placement). The second is the ability to generate a Fragment by using that information and calculating the Intrinsic Size of the box being laid out. A Fragement's Intrinsic Size is two values: the min-content-size (smallest a box can be without overflowing, minContentSize), and the max-content-size ("ideal" size of a box given infinite available space, usually smallest it can be while still fitting around its contents, maxContentSize).

Fragment Overview

Fragments contain the calculated inline and block (which are abstract dimensions) offsets and sizes. The sizes are calculated and cannot be changed, but the offsets aren't! We can set these offsets to position our box around, thus doing a layout!

Layout Edges Overview

Layout Edges also have inline and block dimensions, for padding, border, and scrollbar. They've got all options to group them all together, and inline and block start and end values.

Layout API Worklet

Register Worklet from Main JavaScript

await CSS.layoutWorklet.addModule('path/to/layout-worklet.js');

Worklet Overview

// From https://drafts.css-houdini.org/css-layout-api/ April 24, 2018 Editor's Draft

registerLayout('sample-layout', class {
  // Properties to look for on calling element
  static get inputProperties() { return ['--foo']; }
  // Properties to look for on direct child elements
  static get childrenInputProperties() { return ['--bar']; }
  // Options for the Layout
  // `childDisplay` can be 'block' or 'normal'. 'block' is similar to children of flex and grid containers, 'normal'. Otherwise boxes won't be blockified
  // `sizing` can be 'block-like' or 'manual'. 'block-like' will make the Layout Constraints's inline size be fixed, and block size be calculated like border-box. Otherwise, it's just the calculated inlineSize and blockSize
  static get layoutOptions() {
    return {
      childDisplay: 'normal',
      sizing: 'block-like'
    };
  }

  // Generator functions instead of normal functions to support async/parallel layout engines
  // Determines how a box fits its content or fits in to our layout context
  *intrinsicSizes(children, edges, styleMap) {
    // children - Child elements of box being laid out
    // edges - Layout Edges of the box being
    // styleMap - Typed OM style map of box being laid out

    // Intrinsic sizes code goes here.
  }

  *layout(children, edges, constraints, styleMap, breakToken) {
    // children - Child elements of Parent Layout
    // edges - `LayoutEdges` of Parent Layout
    // constraints - `Layout Constraints` of Parent Layout
    // styleMap - Typed OM style map of Parent Layout
    // breakToken - Token (if paginating for printing for example) to resume layout at

    // Layout code goes here.
  }
});

Play with the Layout API

Now it's your turn! Below are two examples of the Layout API in action, each showcasing something a little different, for you to see and play with! The Centered Blocks example is fairly basic, showing how to use input and child input properties to lay items out stacked one on top of another, centered. The Masonry example comes from Google Chrome Labs and is, well, masonry!

Each one of these examples are fully editable, and you'll see the changes live as you type! You can change the Worklet code, the userland JavaScript, the CSS, and the HTML. Worklets get added automagically, and the userland JavaScript runs after its loaded.

You're preloaded with the Centered Blocks example. Use the other buttons to switch examples. The Custom button will give you a blank Layout API worklet scaffolding to start from for you to experiment from scratch! Copy the URL once you've started making a Custom example to get back to your work later!