Houdini

programming in CSS

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 { } 

Paint API

Typed OM API

Properties & Values API

Animation Worklet

Layout API

Worklets

Font Metrics API

Box Tree API

Parser API

.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{ }

Houdini-Paint-API-Circles

    .Extends-CSS .Paint-API{ }

Houdini-Paint-API-Circles-props

    .Extends-CSS .Paint-API{ }

Houdini-Paint-API-Circles-args

    .Extends-CSS .Paint-API{ }

Houdini-Paint-API-Circles-props-JS

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 { } 

.foo { background-position: center bottom 10px; transform: translateX(1em) rotate(50deg) skewX(10deg); vertical-align: baseline; width: calc(100% - 3em); }

css

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

const cs = document.querySelector('.foo').computedStyleMap(); cs.get('vertical-align'); // CSSKeywordValue { // value: 'baseline', // } cs.get('background-position').x; // CSSUnitValue { // value: 50, // unit: 'percent', // } cs.get('background-position').y; // CSSMathSum { // operator: 'sum', // values: CSSNumericArray { // 0: CSSUnitValue { value: -10, unit: 'px' }, // 1: CSSUnitValue { value: 100, unit: 'percent' }, // }, // } cs.get('width'); // CSSMathSum { // operator: 'sum', // length: 2, // values: CSSNumericArray { // 0: CSSUnitValue { value: -90, unit: 'px' }, // 1: CSSUnitValue { value: 100, unit: 'percent' }, // }, // } cs.get('transform'); // CSSTransformValue { // is2d: true, // length: 3, // 0: CSSTranslate { // is2d: true, // x: CSSUnitValue { value: 20, unit: 'px' }, // y: CSSUnitValue { value: 0, unit: 'px' }, // z: CSSUnitValue { value: 0, unit: 'px' }, // }, // 1: CSSRotate { // is2d: true, // angle: CSSUnitValue { value: 50, unit: 'deg' }, // x: CSSUnitValue { value: 0, unit: 'number' }, // y: CSSUnitValue { value: 0, unit: 'number' }, // z: CSSUnitValue { value: 1, unit: 'number' }, // }, // 2: CSSSkewX { // is2d: true, // ax: CSSUnitValue { value: 10, unit: 'deg' }, // }, // }

computedStyleMap

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

Animation Worklet

    .Extends-CSS { } 

    .Extends-CSS Animation-Worlet { } 

Layout API

    .Extends-CSS { } 

    .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 😊

Developer Advocate 🥑
at
@SchibstedSpain

 

Co-Founder & UI Engineers

at @sublime_codes

Joan León

.Hello {

}

#Javascript

#CSS

#PostCSS

#Animation

#SVG

SUI Components

@carlosvillu

@midudev

.Talk::after {

}

content: "Any question?";

.Thanks {

}

Houdini: programming in CSS

By Joan León

Houdini: programming in CSS

Codemotion Madrid 2018: CSS siempre se ha considerado la parte menos controlable, complicada, mágica y en ocasiones algo aleatoria. Houdini nos ofrece un conjunto de APIs y herramientas Javascript que nos dan la posibilidad de extender CSS para acceder al proceso de diseño y estilo del motor de renderizado del navegador.

  • 3,026