Houdini

programming in CSS

Frontend Developer
at
@AdevintaEng

 

PerfReviewer

at @PerfReviews_

 

Creative Coder

at @CodingGirona

Joan León

.Hola {

}

#CSS

#PostCSS

#Animation

#SVG

#Javascript

#CreartiveCoding

.                            {

}

CSS

.CSS { } 

.CSS { } 

CSS Houdini

.CSS-Houdini { } 

The objective of the CSS-TAG Houdini Task Force (CSS Houdini) is to jointly develop features that explain the “magic” of Styling and Layout on the web. - CSS Houdini

.CSS-Houdini { } 

.CSS-Houdini { } 

Extends CSS

Worklets

    .Extends-CSS { } 

    .Extends-CSS .Worklets { }

Worklet connects to the browser engine

Is a Javascript Module

Without control over execution

It has no impact on performance

    .Extends-CSS .Worklets { }

if ('paintWorklet' in CSS) {
    CSS.paintWorklet.addModule('PlaceholderBoxPainter.js');
}
class PlaceholderBoxPainter {
    paint(ctx, size) {
        // Magic 🎩
    }
}

registerPaint('placeholder-box', PlaceholderBoxPainter);

worklet

js

    .Extends-CSS .Worklets { }

Paint API

    .Extendes-CSS { } 

    .Extends-CSS .Paint-API{ }

if ('paintWorklet' in CSS) {
    CSS.paintWorklet.addModule('PlaceholderBoxPainter.js');
}
@supports (background: paint(slanted-bg)) {
  .el span {
    background: paint(slanted-bg);
  }
}

css

js

class SlantedBg {
  constructor () {
    this.hue = 110;
  }
  paint (ctx, geom, props, args) {
    // draw random colors
    ctx.fillStyle = 'hsl(' + this.hue + ', 100%, 50%)';
    this.hue += 10;

    ...
  }
}

registerPaint('slanted-bg', SlantedBg)

worklet

registerPaint('slanted-bg', class {
  constructor () {
    this.hue = 110;
  }
  paint (ctx, geom, props, args) {
    // draw random colors
    ctx.fillStyle = 'hsl(' + this.hue + ', 100%, 50%)';
    this.hue += 10;

    ...
  }
})

    .Extends-CSS .Paint-API{ }

    .Extends-CSS .Paint-API{ }

DEMO

Canvas with p5.js

CSS Houdini

Canvas

Houdini

Properties & Values API

    .Extends-CSS { } 

    .Extends-CSS .Properties-Values-API { } 

CSS.registerProperty({
  name: '--line-with',
  syntax: '<number>',
  inherits: false,
  initialValue: 1
});

js

CSS Properties Syntax

'<length>' accepts length values.
'<length> | <percentage>' accepts lengths, percentages, percentage calc expressions, and length calc expressions, but not calc expressions containing a combination of length and percentage values.​
'<length-percentage>' accepts all values that "<length> | <percentage>" would accept, as well as calc expressions containing a combination of both length..
'big | bigger | BIGGER' accepts the ident "big", or "bigger", or  "BIGGER".
'<length>+' accepts a space-separated list of length values.

'<length>'
'<number>'
'<percentage>'
'<length-percentage>'
'<color>'
'<image>'
'<url>'
'<integer>'
'<angle>'
'<time>'
'<resolution>'
'<transform-function>'
'<custom-ident>'

    .Extends-CSS .Properties-Values-API { } 

    .Extends-CSS .Properties-Values-API { } 

    .Extends-CSS .Properties-Values-API { } 

    .Extends-CSS .Properties-Values-API { } 

@property --theme {
  syntax: '<color>+';
  initial-value: #fff;
  inherits: true;
}
if ("registerProperty" in CSS) {
  CSS.registerProperty({
    name: "--theme",
    syntax: "<color>+",
    initialValue: "#fff",
    inherits: true
  });
}

input

output

    .Extends-CSS .Properties-Values-API { } 

@property --highlight-color {
  inherits: true;
  initial-value: red;
  syntax: "<color>";
}

@property --gap-spacing {
  inherits: false;
  initial-value: 1em;
  syntax: "<length-percentage>";
}
[
  {
    "name": "--highlight-color",
    "inherits": true,
    "initialValue": "red",
    "syntax": "<color>"
  },
  {
    "name": "--gap-spacing",
    "initialValue": "1em",
    "syntax": "<length-percentage>"
  }
]
import properties from './styles.css.properties.json';

if (window.CSS && CSS.registerProperty) {
  for (const descriptor of properties) {
    CSS.registerProperty(descriptor);
  }
}

input

output

js

    .Extends-CSS .Properties-Values-API { } 

Typed OM API

    .Extends-CSS { } 

    .Extends-CSS .Typed-OM-API { } 

The Type OM API is an extension of the existing CSS object model (CSSOM) that exposes CSS values as typed JavaScript objects, rather than a simple string of text as they are today.

With Type OM API, CSS values are now members of a new base class CSSStyleValue.

CSSUnitValue

CSSKeywordValue

CSSPositionValue

CSSImageValue

CSSTransformValue

CSSMathValue

el.style.opacity = 0.5;
window.getComputedStyle(el).opacity === "0.5" // Strings!

CSSOM

el.attributeStyleMap.set('opacity', 0.5);
el.computedStyleMap().get('opacity').value // 0.5

Typed OM

    .Extends-CSS .Typed-OM-API { } 

calc(1px - 2 * 3em)


new CSSMathSum(
  CSS.px(1),
  new CSSMathNegate(
    new CSSMathProduct(2, CSS.em(3))
  )
);

Nested expressions

    .Extends-CSS .Typed-OM-API { } 

el.attributeStyleMap.set('font-size', CSS.em(2));
el.attributeStyleMap.get('font-size');
// CSSUnitValue { value: 2, unit: 'em' }


el.attributeStyleMap.set('opacity', CSS.number(.5));
el.attributeStyleMap.get('opacity');
// CSSUnitValue { value: 0.5, unit: 'number' }

attributeStyleMap

    .Extends-CSS .Typed-OM-API { } 

Animation Worklet

    .Extends-CSS { } 

    .Extends-CSS Animation-Worlet { } 

Layout API

    .Extends-CSS { } 

    .Extends-CSS { } 

Image by Una

    .Extends-CSS  .Layout-API {}

Support

Conclusions

    .Conclusions { } 

Polyfills

This is not for me

Houdini is NOT like a Babel for CSS

Free will

🤪

I see another talk...

CSS

is

Awesome

Resources

    .Resources { } 

⭐️ are welcome 😊

.Talk::after {

}

content: "Any question?";

.Thanks {

}

Houdini: programming in CSS { May '19 }

By Joan León

Houdini: programming in CSS { May '19 }

Barcelona May '19: CSS has always been considered the least controllable, complicated, magical and sometimes somewhat random part. Houdini offers us a set of APIs and Javascript tools that give us the possibility to extend CSS to access the design process and style of the browser rendering engine.

  • 1,902