the future of CSS

DEMYSTIFYING

WITH SPARKLES OF JS

ibevanmeenen.me/houdini - May 2018

JS

CSS

CANT KEEP TRACK...

JS

YAJ NEW STUFF, BUT eum...

CSS

why?

new feature

pace of innovation

USING A NEW FEATURE

javascript

Day 0

Javascript

new feature

Polyfill released, let's use it!

pace of innovation

USING A NEW FEATURE

javascript

Day 1 - ...

Javascript

Day 0

target browsers support it, drop polyfill

new feature

Polyfill released, let's use it!

pace of innovation

USING A NEW FEATURE

javascript

Day ...

Javascript

Day 1 - ...

Day 0

pace of innovation

Using a new feature

css

new feature

CSS

Day 0

pace of innovation

Using a new feature

css

new feature

Complain about slow browser Adoption...

CSS

Day 1 - ...

Day 0

pace of innovation

Using a new feature

css

target browsers support it, Finally...

new feature

Complain about slow browser Adoption...

CSS

Day ...

Day 1 - ...

Day 0

pace of innovation

creating your own Feature

javascript

Great idea for new feature

Javascript

Day 0

pace of innovation

creating your own Feature

javascript

Great idea for new feature

Made it, let's use it

Javascript

Day 10 - ...

Day 0

pace of innovation

creating your own Feature

javascript

browsers Adopt your great idea

Great idea for new feature

Made it, let's use it

Javascript

Day ...

Day 10 - ...

Day 0

pace of innovation

creating your own Feature

css

Great idea for new feature

CSS

Day 0

pace of innovation

creating your own Feature

css

Great idea for new feature

CSS

Day 0

...

WHY?

rendering pipeline

Current access

BIG MAGIC BOX

MY.SCSS

Writing your own Polyfill/feature

AWESOME RESULT

MY.CSS

PREPROCESSOR

rendering pipeline

Current access

RENDERING ENGINE

Current acces for developers

AWESOME RESULT

MY.CSS

BLINK

GECKO

EDGE

WEBKIT

...

rendering pipeline

Current access

RENDERING ENGINE

Current acces for developers

AWESOME RESULT

MY.CSS

JAVASCRIPT ENGINE

V8

SPIDERMONKEY

...

BLINK

GECKO

EDGE

WEBKIT

...

rendering pipeline

Current access

Parser

CSSOM

Cascade

Layout

Paint

Composite

DOM

Current acces for developers

RENDERING ENGINE

rendering pipeline

Current access

Current acces for developers

JAVASCRIPT
LOGIC

Parser

DOM

CSSOM

Cascade

Layout

Paint

Composite

No Access

Limited JS Access

Full JS Access

RENDERING ENGINE

Flow of writing your own css feature/polyfill

rendering pipeline

Current access

Writing your own Polyfill/feature

rendering pipeline

Current access

STEP 1

Write your basic logic

Writing your own Polyfill/feature

rendering pipeline

Current access

YOU As
an developer

Writing your own Polyfill/feature

rendering pipeline

Current access

But wait...

Writing your own Polyfill/feature

rendering pipeline

Current access

Checking the rest of the CSS for matching rules, and then only replace the rule as an inline style if it's the last matching rule. Wait, that won't work, because we have to account for specificity, so we'll have to manually parse each selector to calculate its specificity. Then we can sort the matching rules in specificity order from low to high, and only apply the declarations from the most specific selector. Oh and then there's @mediarules, so we'll have to manually check for matches there as well. And speaking of at-rules, there's also @supports — can't forget about that. And lastly we'll have to account for property inheritance, so for each element we'll have to traverse up the DOM tree and inspect all its ancestors to get the full set of computed properties. Oh, sorry, one more thing: we'll also have to account for !important, which is calculated per-declaration instead of per-rule, so we'll have to maintain a separate mapping for that to figure out which declaration will ultimately win.

What about...

Writing your own Polyfill/feature

rendering pipeline

Current access

YOU As
an developer

Writing your own Polyfill/feature

rendering pipeline

Current access

Your
Performance

Writing your own Polyfill/feature

rendering pipeline

Current access

YOU As
an developer

Writing your own Polyfill/feature

rendering pipeline

Current access

YOU As
an developer

A Couple years later...

Writing your own Polyfill/feature

rendering pipeline

Current access

Current acces for developers

JAVASCRIPT
LOGIC

Parser

DOM

CSSOM

Cascade

Layout

Paint

Composite

No Access

Limited JS Access

Full JS Access

RENDERING ENGINE

cSS is not extendable...

rendering pipeline

Current access

Current acces for developers

“Without low-level styling primitives, innovation will move at the pace of the slowest-adopting browser

 MORE?

Making CSS as a language user-extensible

Houdini

We believe that allowing developers to extend CSS is good for the ecosystem

Houdini

Working group


“If a developer wanted an additional feature they could implement it themselves. E.g. if the developer wanted a new type of dashed border, they shouldn't have to wait for browsers to implement this”

Houdini

Working group

Houdini

APIs

Working group

Properties And Values
API

Worklets

Parser
API

Typed ObjectModel
API (v2)

Font Metrics
API

TBD

Box Tree
API

Layout
API

Paint
API

Animation
API

Scroll Custom.
API

Parser

CSSOM

Cascade

Layout

Paint

Composite

DOM

Full JS Access

Houdini

Working group

Properties And Values
API

Worklets

Parser
API

Typed ObjectModel
API (v2)

Font Metrics
API

TBD

Box Tree
API

Layout
API

Paint
API

Animation
API

Scroll Custom.
API

focus of this talk

Parser

CSSOM

Cascade

Layout

Paint

Composite

DOM

Full JS Access

PROPERTIES AND VALUES

API

PROPERTIES AND VALUES

API

Originally sold and used as CSS-Variables

but is actually meant as an extension point.

Current state

PROPERTIES AND VALUES

API

:root {
  --theme-background: #46cdcf;
  --theme-color: #fff;
}

body {
  color: var(--theme-color);
  background: var(--theme-background);
}

.a-button {
  color: var(--theme-color);
}

...

Current state

*.css

PROPERTIES AND VALUES

API

Current state

const root = document.documentElement;

const switchTheme = (e) => {
  switch(e.target.value) {
    case 'dark':
      setTheme('#111', '#fff');
      break;
    case 'light':
      setTheme('#fff', '#111');
      break;
    case 'tomato':
      setTheme('tomato', '#fff');
      break;
   case 'broken':
      setTheme('thisIsNotAColor', 'thisIsAlsoNotAColor');
      break;
  }
};

const setTheme = (background, color) => {
  root.style.setProperty('--theme-color', color);
  root.style.setProperty('--theme-background', background);
};

*.js

PROPERTIES AND VALUES

API

Current state - Strengths

1. Easy access for js

2. Use of the Cascade

3. limited dom-manipulations

WANNA LEARN MORE?

:root {
  --theme-background: #46cdcf;
  --theme-color: #fff;
}

body {
  color: var(--theme-color);
  background: var(--theme-background);
}

body.fixed-color {
  color: #000;
} 

@media screen and (min-width: 40rem) {
  body {
    color: tomato;
    background: #fff;
  }
}

*.css

PROPERTIES AND VALUES

API

Current state - Strengths

"--" as an prefix is used to prevent preprocessors of compiling custom properties.

FYI

PROPERTIES AND VALUES

API

Current state - Strengths

PROPERTIES AND VALUES

API

just ONe big problem tho...

Current state - Problems

PROPERTIES AND VALUES

API

ua BE LIKe

 

Current state - Problems

PROPERTIES AND VALUES

API

ALL STRINGS

Current state - Problems

PROPERTIES AND VALUES

API

Current state - Problems

1. Not animatable

2. no way for ua to optimize​ or fallback

3. No editor or dev-tools support

Downsides

PROPERTIES AND VALUES

API

Solution

DEFINE IT

Solution:

PROPERTIES AND VALUES

API

Enter Properties and values api

SOLution

PROPERTIES AND VALUES

API

CSS.registerProperty({
  name: '--theme-color',
  syntax: '<color>',
  inherits: true,
  initialValue: '#fff'
});

CSS.registerProperty({
  name: '--theme-background',
  syntax: '<color>',
  inherits: true,
  initialValue: '#454468'
});

*.js

STEP 1: DEFINE

how

PROPERTIES AND VALUES

API

Possible values for <SYNTAX>

<number> // 0, 2, 4.1, ...
<length> // 0, px, rem, ...
<percentage> // 10%, 0.5%, ...
<length-percentage> // px, rem, %, ...
<color> // #fff, rgba(0, 0, 0, .5), ...
<url> // url()
<image> // url, image-list, gradient, ...
<integer> // 1, 2, ...
<angle> // deg, grad, rad, ...
<time> // s, ms
<resolution> // dpi, dpcm, ...
<transform-list> // scale(), translate(), ...
<custom-ident> // test, ground-level, ...

how

CSS.registerProperty({
  name: '--theme-color',
  syntax: '<color>',
  inherits: true,
  initialValue: '#fff'
});

CSS.registerProperty({
  name: '--theme-background',
  syntax: '<color>',
  inherits: true,
  initialValue: '#454468'
});

*.js

PROPERTIES AND VALUES

API

Possible NOtations for <SYNTAX>

syntax: "<length> | <percentage>",
Accept both, not in calc() combinations

syntax: "<length-percentage>",
Accept both and combination in calc()

syntax="<length>+"
accepts a list of length values

how

    --prop: 20rem;

    --prop: 10%;

    --prop: calc(20rem * 10%);
    --prop: 20rem;

    --prop: 10%;

    --prop: calc(20rem * 10%);
    --prop: 20rem, 10vw, 1px;

PROPERTIES AND VALUES

API

<inherits> TRUE

how

CSS.registerProperty({    
  name: '--vertical-spacing',
  syntax: '<length>',
  inherits: true,
  initialValue: 0
});

*.js

.article {
  --vertical-spacing: 5rem;

  max-width: 20rem;
  margin: var(--vertical-spacing) auto; /* 5rem */
}

.article__fig {
  margin: var(--vertical-spacing) 0; /* 5rem */
}

.article__fig__img {
  margin: var(--vertical-spacing) 0; /* 5rem */
}

*.css

<article class="article">
 <figure class="article__fig">
  <img class="article__fig__img" src="/awesome-image.jpg" alt="Awesome" >
  ...

*.html

PROPERTIES AND VALUES

API

how

.article {
  --vertical-spacing: 5rem;

  max-width: 20rem;
  margin: var(--vertical-spacing) auto; /* 5rem */
}

.article__fig {
  margin: var(--vertical-spacing) 0; /* 0 */
}

.article__fig__img {
  margin: var(--vertical-spacing) 0; /* 0 */
}

*.css

<inherits> false

CSS.registerProperty({    
  name: '--vertical-spacing',
  syntax: '<length>',
  inherits: false,
  initialValue: 0
});

*.js

<article class="article">
 <figure class="article__fig">
  <img class="article__fig__img" src="/awesome-image.jpg" alt="Awesome" >
  ...

*.html

PROPERTIES AND VALUES

API

STEP 2: USE

body {
  color: var(--theme-color);
  background: var(--theme-background);
}

*.css

CSS.registerProperty({
  name: '--theme-color',
  syntax: '<color>',
  inherits: true,
  initialValue: '#fff'
});

STEP 1: DEFINE

how

CSS.registerProperty({
  name: '--theme-background',
  syntax: '<color>',
  inherits: true,
  initialValue: '#454468'
});

*.js

PROPERTIES AND VALUES

API

Example

body {
  color: var(--theme-color);
  background: var(--theme-background);
  
  transition: --theme-color .3s ease, 
              --theme-background .3s ease;
}

*.css

PROPERTIES AND VALUES

API

Example

Warning: still behind a flag!

Check if available:

if (CSS.registerProperty) {
    CSS.registerProperty({
      name: '--theme-color',
      syntax: '<color>',
      ...

*.js

PROPERTIES AND VALUES

API

Conclusion

1. Easy access by Javascript

2. Use of the c in css (cascade

3. limited dom-manipulations

4. properties are animatable

5. ua can optimize​ and fallback

6. editor and dev-tools support

Paint

WORKLET

Paint

WORKLET

Allows you to write a paint function which allows us to draw directly into an elements background, border, or content.

What

Paint

WORKLET

why

1. reduction of dom

2. Efficiency Gains

3. Extensibility of CSS

Results in Performance gains

#batterylife

WHY?

WORKLET?

The Worklet is a lightweight version of Web Workers and gives developers access to low-level parts of the rendering pipeline.

 

With Worklets, you can run JavaScript and WebAssembly code to do graphics rendering or audio processing where high performance is required.

WORKLET

What

WORKLET

What

Worklet

off
main thread

web worker

has
Dom ACCESS

Fast initialization

YES

YES

NO

YES

NO

YES

WORKLET

Types

- Paint Worklet

- Animation worklet

- Layout Worklet

- Audio worklet

current worklets

WORKLET

how

registerPaint('my-module-name', class {
  // Do awesome stuff
});

my-module.paint-module.js

access the worklet

By writing your own modules

WORKLET

how

await CSS.paintWorklet.addModule('my-module.paint-module.js');

*.js

access the worklet

And plug them in to your desired worklet

WORKLET

how

Promise.all([
    window.paintWorklet.addModule('my-module.paint-module.js'),
    window.layoutWorklet.addModule('my-module.layout-module.js')
]).then(() => {
    // Both modules are loaded, let's do some stuff
});

*.js

access the worklet

Wait for multiple modules to be loaded if needed

back to paint

Let's draw a circle

Paint

WORKLET

how

registerPaint('circle', class {
  static get inputProperties() {}

  paint(ctx, size, properties) {}
});

circle.paint-module.js

STEP 1: CREATE THE PAINT module

Paint

WORKLET

HOw

STEP 2: ADD TO PAINT WORKLET

if ('paintWorklet' in CSS) {
  CSS.paintWorklet.addModule('circle.paint-module.js');
}

*.js

Paint

WORKLET

HOw

registerPaint('circle', class {
  static get inputProperties() {}

  paint(ctx, size, properties) {}
});

circle.paint-module.js

STEP 1: CREATE THE PAINT module

STEP 2: ADD TO PAINT WORKLET

if ('paintWorklet' in CSS) {
 CSS.paintWorklet.addModule('circle.paint-module.js');
}

*.js

registerPaint('circle', class {
  static get inputProperties() {}

  paint(ctx, size, properties) {}
});

circle.paint-module.js

STEP 1: CREATE THE PAINT module

STEP 3: USE

.circle-btn {
  background-image: paint(circle);
}

*.css

Paint

WORKLET

HOw

registerPaint('circle', class {
  static get inputProperties() {}

  paint(ctx, size, properties) {
    const x = size.width / 2;
    const y = size.height / 2;
    const radius = Math.min(x, y);
    
    ctx.fillStyle = '#454468';
    ctx.beginPath();
    ctx.arc(x, y, radius, 0, 2 * Math.PI);
    ctx.fill();
  }
});

circle.paint-module.js

Paint

WORKLET

Draw the circle

PAINT-MODULE: Paint the cricle

Paint

WORKLET

Draw the circle

.circle-btn {
  background-image: paint(circle);
}

*.css

Add a dynamic circle color

Paint

WORKLET

Add dynamic background

.circle-btn {
  --circle-color: #454468;

  background: paint(circle);
  transition: --circle-color 1s ease;
}

.circle-btn:hover {
  --circle-color: tomato;
}

*.css

CSS.registerProperty({
  name: '--circle-color',
  syntax: '<color>',
  inherits: false,
  initialValue: '#fff'
});

*.js

Paint

WORKLET

Add dynamic background

registerPaint('circle', class {
  static get inputProperties() {
    return ['--circle-color'];
  }

  paint(ctx, size, properties) {
    const fill = properties.get('--circle-color');
    const x = size.width / 2;
    const y = size.height / 2;
    const radius = Math.min(x, y);
    
    ctx.fillStyle = fill;
    ctx.beginPath();
    ctx.arc(x, y, radius, 0, 2 * Math.PI);
    ctx.fill();
  }
});

circle.paint-module.js

Paint

WORKLET

Add dynamic background

Paint

WORKLET

Add dynamic background

.circle-btn {
  --circle-color: #454468;

  background: paint(circle);
  transition: --circle-color 1s ease;
}

.circle-btn:hover {
  --circle-color: tomato;
}

*.css

Paint

WORKLET

Add dynamic background

Circle where we click

CSS.registerProperty({
  name: '--circle-x',
  syntax: '<number>',
  inherits: false,
  initialValue: 0
});
const setPosition = (event, el) => {
  const x = event.offsetX;
  const y = event.offsetY;

  el.style.cssText = `--circle-x: ${x}; --circle-y: ${y};`;
}

el.addEventListener('click', event => setPosition(event, el), false);

*.js

CSS.registerProperty({
  name: '--circle-y',
  syntax: '<number>',
  inherits: false,
  initialValue: 0
});

*.js

Paint

WORKLET

circle where we click

registerPaint('circle', class {
  static get inputProperties() {
    return ['--circle-color', '--circle-x', '--circle-y'];
  }

  paint(ctx, size, properties) {
    const fill = properties.get('--circle-color');
    const x = properties.get('--circle-x');
    const y = properties.get('--circle-y');
    const radius = Math.min(x, y);

    ctx.fillStyle = fill;
    ctx.beginPath();
    ctx.arc(x, y, radius, 0, 2 * Math.PI);
    ctx.fill();
  }
});

circle.paint-module.js

Paint

WORKLET

circle where we click

Paint

WORKLET

circle where we click

.circle-btn {
  --circle-color: #454468;

  background-image: paint(circle);
  transition: --circle-color 1s ease;
}

.circle-btn:hover {
  --circle-color: tomato;
}

*.css

Paint

WORKLET

circle where we click

.circle-btn {
  --circle-color: #454468;

  background-image: paint(circle);
  transition: --circle-color 1s ease, 
              --circle-x 1s ease, 
              --circle-y 1s ease;
}

.circle-btn:hover {
  --circle-color: tomato;
}

*.css

Paint

WORKLET

Fade out and expand

Fade out and expand

CSS.registerProperty({
  name: '--animation-tick',
  syntax: '<number>',
  inherits: false,
  initialValue: 0
});

*.js

.circle-btn {
  --animation-duration: 1s;
  --circle-color: #c6efeb;
}

.circle-btn.-animating {
  --animation-tick: 1000;

  background-image: paint(circle);
  transition: --animation-tick var(--animation-duration) ease;
}

*.css

Paint

WORKLET

Fade out

CSS.registerProperty({
  name: '--animation-duration',
  syntax: '<time>',
  inherits: false,
  initialValue: '0.3s'
});
const ANIM_CLASS = '-animating';

const setPosition = (event, el) => { ... }; // Set X and Y
const startAnimation = el => { el.classList.add(ANIM_CLASS); }; // Add animation class
const stopAnimation = el => { el.classList.remove(ANIM_CLASS); }; // Remove animation class

const setupElement = el => {
  const duration = CSSNumericValue
                    .parse(getComputedStyle(el).getPropertyValue('--animation-duration'))
                    .to('ms').value || 1000;

  let timeout;

  el.addEventListener('click', event => {
    stopAnimation(el);
    setPosition(event, el);
    startAnimation(el);

    window.clearTimeout(timeout);
    timeout = window.setTimeout(() => stopAnimation(el), duration);
  }, false);
};

*.js

Paint

WORKLET

Fade out

registerPaint('circle', class {
  static get inputProperties() {
    return ['--circle-color', '--animation-tick', '--animation-duration', '--circle-x', '--circle-y'];
  }

  paint(ctx, size, properties) {
    const tick = properties.get('--animation-tick');
    const duration = properties.get('--animation-duration').to('ms').value;
    const fill = properties.get('--circle-color');
    const x = properties.get('--circle-x');
    const y = properties.get('--circle-y');
    const radius = size.width * (tick / duration);

    ctx.fillStyle = fill;
    ctx.beginPath();
    ctx.globalAlpha = 1 - (tick / duration);
    ctx.arc(x, y, radius, 0, 2 * Math.PI);
    ctx.fill();
  }
});

circle.paint-module.js

Paint

WORKLET

Fade out

Paint

WORKLET

Fade out

.circle-btn {
  --animation-duration: 1s;
  --circle-color: #c6efeb;
}

.circle-btn.-animating {
  --animation-tick: 1000;

  background-image: paint(circle);
  transition: --animation-tick var(--animation-duration) ease;
}

*.css

Paint

WORKLET

Awesome!

Conclusion

Paint

WORKLET

Draw the circle

.circle-btn {
  --animation-duration: 1s;
  --circle-color: #c6efeb;
}

.circle-btn.-animating {
  --animation-tick: 1000;

  background-image: paint(circle);
  transition: --animation-tick var(--animation-duration) ease;
}

*.css

1. No extra dom-elements

2. Reactive on changes

4. Browser can optimize

(canvas, div, ::before, ::after, ...)

3. Use of cascade

Paint

WORKLET

Conclusion

CODE

Paint

WORKLET

Conclusion

Polyfill available!

2 weeks old

LAYOUT

WORKLET

LAYOUT

WORKLET

“ Gives you the ability to write their own layout algorithms in addition to the native algorithms user agents ship with today ”

LAYOUT

WORKLET

1. Box flow layout

2. Flex layout

3. Grid Layout

LAYOUT

WORKLET

5. Masonry layout

4. Constraint layouts

1. Box flow layout

2. Flex layout

3. Grid Layout

LAYOUT

WORKLET

EARLY STAGES

Let's create a
new layout

LAYOUT

WORKLET

how

registerLayout('ratio', class {
  static get inputProperties() {}

  *intrinsicSizes() { /* Note: Not yet implemented */ }
  
  *layout(children, edges, constraints, properties) {}
});

ratio.layout-module.js

STEP 1: CREATE THE LAYOUT module

LAYOUT

WORKLET

how

STEP 2: ADD TO LAYOUT WORKLET

if ('layoutWorklet' in CSS) {
  CSS.layoutWorklet.addModule('ratio.layout-module.js');
}

*.js

ratio.layout-module.js

LAYOUT

WORKLET

how

registerLayout('ratio', class {
  static get inputProperties() {}

  *intrinsicSizes() {}
  
  *layout(children, edges, constraints, properties) {}
});

STEP 1: CREATE THE Layout module

STEP 2: ADD TO layout WORKLET

if ('layoutWorklet' in CSS) {
  CSS.layoutWorklet.addModule('masonry.layout-module.js');
}

*.js

STEP 3: USE

.my-element {
  --aspect-ratio: 1.2;

  display: layout(ratio);
}

*.css

LAYOUT

WORKLET

how

registerLayout('ratio', class {
  static get inputProperties() {}

  *intrinsicSizes() {}
  
  *layout(children, edges, constraints, properties) {}
});

STEP 1: CREATE THE Layout module

ratio.layout-module.js

LAYOUT

WORKLET

ratio

registerLayout('ratio', class {
  static get inputProperties() {
    return ['--aspect-ratio'];
  }

  *intrinsicSizes() {}

  *layout(children, edges, constraints, properties) {
    const ratio = properties.get('--aspect-ratio');

    const autoBlockSize = constraints.fixedInlineSize * ratio;

    return { autoBlockSize };
  }
});

ratio.layout-module.js

LAYOUT

WORKLET

ratio

LAYOUT

WORKLET

Masonry

Let's create a
masonry layout

registerLayout(
  'masonry',
  class {
    static get inputProperties() {
      return ['--masonry-padding', '--masonry-columns'];
    }

    *layout(children, edges, constraints, properties) {
      const inlineSize = constraints.fixedInlineSize;

      const padding = parseInt(properties.get('--masonry-padding'));
      const columnValue = properties.get('--masonry-columns').toString();

      // We also accept 'auto', which will select the BEST number of columns.
      let columns = parseInt(columnValue);
      if (columnValue === 'auto' || !columns) {
        columns = Math.ceil(inlineSize / 350); // MAGIC NUMBER \o/.
      }

      // Layout all children with simply their column size.
      const childInlineSize = (inlineSize - (columns + 1) * padding) / columns;
      const childFragments = yield children.map(child => {
        return child.layoutNextFragment({ fixedInlineSize: childInlineSize });
      });

      let autoBlockSize = 0;
      const columnOffsets = Array(columns).fill(0);

      childFragments.forEach(childFragment => {
        // Select the column with the least amount of stuff in it.
        const min = columnOffsets.reduce(
          (acc, val, idx) => {
            if (!acc || val < acc.val) {
              return { idx, val };
            }

            return acc;
          },
          { val: +Infinity, idx: -1 }
        );

        childFragment.inlineOffset = padding + (childInlineSize + padding) * min.idx;
        childFragment.blockOffset = padding + min.val;

        columnOffsets[min.idx] = childFragment.blockOffset + childFragment.blockSize;
        autoBlockSize = Math.max(autoBlockSize, columnOffsets[min.idx] + padding);
      });

      return { autoBlockSize, childFragments };
    }
  }
);

masonry.layout-module.js

LAYOUT

WORKLET

Masonry

by Google Chrome Labs

LAYOUT

WORKLET

masonry

me BE LIKe


LAYOUT

WORKLET

Masonry

 

This is a COMPLEX API and it uses foreign terminology. But we really want to give you, the web developer, the power that the rendering engines have when it comes to layout. Enjoy! :) ”

LAYOUT

WORKLET

masonry

MORE

possibilities

more possibilities

houdini

more

Properties And Values
API

Worklets

Parser
API

Typed ObjectModel
API (v2)

Font Metrics
API

TBD

Box Tree
API

Layout
API

Paint
API

Animation
API

Scroll Custom.
API

Parser

CSSOM

Cascade

Layout

Paint

Composite

DOM

Full JS Access

Paint

WORKLET

Conclusion

MORE DEMOS!?

by Vincent De Oliveira

by Google Chrome Labs

Want?

use it

Use it

houdini

Use it

houdini

Everyone
is invested!

Use it

houdini

What about now?

Use it

houdini

1. Start using CSS Custom Properties

2. Register Custom properties when available

- Performance improvements

- Progressive enhancement

3. EXPERIMENT AND HAVE FUN WITH THE WORKLETS

4. Already polyfill AVAILABLE for the paint worklet

TRiggered?

triggered?

houdini

Follow the news

...

triggered?

houdini

let the vendors know you care

triggered?

houdini

Spread the word

1. DO Demo's

2. write about it

3. give talks about it

Making CSS as a language user-extensible

Houdini


“If a developer wanted an additional feature they could implement it themselves. E.g. if the developer wanted a new type of dashed border, they shouldn't have to wait for browsers to implement this”

Houdini

Working group

THANKS!