Joan León PRO
⚡️ Web Performance Consultant | Speaker | Staff Frontend Engineer at @AdevintaSpain | @GoogleDevExpert in #WebPerf | @cloudinary Ambassador

.CSS { }


.CSS { }

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

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


'<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.5Typed 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 {}

.Conclusions { }
Polyfills
This is not for me
Houdini is NOT like a Babel for CSS
Free will
🤪
I see another talk...

.Resources { }
⭐️ are welcome 😊

Joan León
#Javascript
#CSS
#PostCSS
#Animation
#SVG




@carlosvillu
@midudev




By Joan León
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.