Houdini: programming in CSS

A presentation at Codemotion Madrid in December 2018 in Madrid, Spain by Joan León

Slide 1

Slide 1

Houdini programming in CSS Madrid | Nov 30 - Dec 1, 2018

Slide 2

Slide 2

CSS

Slide 3

Slide 3

.CSS { } @nucliweb

Slide 4

Slide 4

.CSS { } @nucliweb

Slide 5

Slide 5

CSS Houdini

Slide 6

Slide 6

.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 @nucliweb

Slide 7

Slide 7

.CSS-Houdini { } @nucliweb

Slide 8

Slide 8

.CSS-Houdini { } Box Tree API Parser API Layout API Paint API Properties & Values API Worklets Typed OM API Animation Worklet Font Metrics API @nucliweb

Slide 9

Slide 9

Extends CSS

Slide 10

Slide 10

.Extends-CSS .Worklets { } Worklet connects to the browser engine Is a Javascript Module Without control over execution It has no impact on performance @nucliweb

Slide 11

Slide 11

.Extends-CSS .Worklets { } @nucliweb

Slide 12

Slide 12

.Extends-CSS .Worklets { } js if ('paintWorklet' in CSS) { CSS.paintWorklet.addModule('PlaceholderBoxPainter.js'); } worklet class PlaceholderBoxPainter { paint(ctx, size) { // Magic } } registerPaint('placeholder-box', PlaceholderBoxPainter); @nucliweb

Slide 13

Slide 13

.Extendes-CSS { } Paint API @nucliweb

Slide 14

Slide 14

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

Slide 15

Slide 15

.Extends-CSS .Paint-API{ } worklet 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) @nucliweb

Slide 16

Slide 16

.Extends-CSS .Paint-API{ } worklet registerPaint('slanted-bg', class SlantedBg { class { 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) @nucliweb

Slide 17

Slide 17

.Extends-CSS .Paint-API{ } Houdini-Paint-API-Circles https://codesandbox.io/embed/yqm0y9v42v?fontsize=16 @nucliweb

Slide 18

Slide 18

.Extends-CSS .Paint-API{ } Houdini-Paint-API-Circles-props https://codesandbox.io/embed/r74pzln91q @nucliweb

Slide 19

Slide 19

.Extends-CSS .Paint-API{ } Houdini-Paint-API-Circles-args https://codesandbox.io/embed/044vkz1k6w @nucliweb

Slide 20

Slide 20

.Extends-CSS .Paint-API{ } Houdini-Paint-API-Circles-props-JS https://codesandbox.io/embed/zxyzr4l61l @nucliweb

Slide 21

Slide 21

Slide 22

Slide 22

Slide 23

Slide 23

Slide 24

Slide 24

Slide 25

Slide 25

.Extends-CSS { } Properties & Values API @nucliweb

Slide 26

Slide 26

.Extends-CSS .Properties-Values-API { } js CSS.registerProperty({ name: '--line-with', syntax: '<number>', inherits: false, initialValue: 1 }); @nucliweb

Slide 27

Slide 27

.Extends-CSS .Properties-Values-API { } 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. @nucliweb

Slide 28

Slide 28

.Extends-CSS .Properties-Values-API { } '<length>' '<number>' '<percentage>' '<length-percentage>' '<length>' accepts length values. '<color>' '<length> | <percentage>' accepts lengths, percentages,'<image>' percentage calc expressions, and length calc expressions, but not calc expressions '<url>' containing a combination of length and percentage values. '<integer>' '<length-percentage>' accepts all values that "<length> '<angle>' | <percentage>" would accept, as well as calc expressions containing a combination of both length.. '<time>' 'big | bigger | BIGGER' accepts the ident "big", or "bigger", or "BIGGER". '<resolution>' '<length>+' accepts a space-separated list of length values. '<transform-function>' '<custom-ident>' CSS Properties Syntax css-properties-values-api/#supported-syntax-strings @nucliweb

Slide 29

Slide 29

.Extends-CSS .Properties-Values-API { } https://codesandbox.io/embed/92znj0j9ow @nucliweb

Slide 30

Slide 30

.Extends-CSS .Properties-Values-API { } //codepen.io/thebabydino/embed/MrZvNm/?height=265&themeid=light&default-tab=css,result @nucliweb

Slide 31

Slide 31

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

Slide 32

Slide 32

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

Slide 33

Slide 33

.Extends-CSS .Properties-Values-API { } input @property --theme { syntax: '<color>+'; initial-value: #fff; inherits: true; } postcss-register-custom-props output if ("registerProperty" in CSS) CSS.registerProperty({ name: "--theme", syntax: "<color>+", initialValue: "#fff", inherits: true }); } (Vitalii Bobrov) @nucliweb

Slide 34

Slide 34

.Extends-CSS .Properties-Values-API { } input output @property --highlight-color { inherits: true; initial-value: red; syntax: "<color>"; } [ { "name": "--highlight-color", "inherits": true, "initialValue": "red", "syntax": "<color>" }, { "name": "--gap-spacing", "initialValue": "1em", "syntax": "<length-percentage>" } @property --gap-spacing { inherits: false; initial-value: 1em; syntax: "<length-percentage>"; } ] postcss-register-property (Jonathan Neal) @nucliweb

Slide 35

Slide 35

.Extends-CSS .Properties-Values-API { } input output @property --highlight-color { [ inherits: true; { js initial-value: red; "name": "--highlight-color", syntax: "<color>"; "inherits": true, import properties from './styles.css.properties.json'; } "initialValue": "red", "syntax":{ "<color>" if (window.CSS && CSS.registerProperty) @property --gap-spacing { }, for (const descriptor of properties) { inherits: false; { CSS.registerProperty(descriptor); initial-value: 1em; "name": "--gap-spacing", } syntax: "<length-percentage>"; "initialValue": "1em", } } "syntax": "<length-percentage>" } ] postcss-register-property (Jonathan Neal) @nucliweb

Slide 36

Slide 36

.Extends-CSS { } Typed OM API @nucliweb

Slide 37

Slide 37

.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. CSSPositionValue CSSKeywordValue CSSImageValue CSSUnitValue CSSMathValue CSSTransformValue @nucliweb

Slide 38

Slide 38

.Extends-CSS .Typed-OM-API { } CSSOM el.style.opacity = 0.5; window.getComputedStyle(el).opacity === "0.5" // Strings! Typed OM el.attributeStyleMap.set('opacity', 0.5); el.computedStyleMap().get('opacity').value // 0.5 @nucliweb

Slide 39

Slide 39

@nucliweb

Slide 40

Slide 40

@nucliweb

Slide 41

Slide 41

.Extends-CSS .Typed-OM-API { } Nested expressions calc(1px - 2 * 3em) new CSSMathSum( CSS.px(1), new CSSMathNegate( new CSSMathProduct(2, CSS.em(3)) ) ); @nucliweb

Slide 42

Slide 42

.Extends-CSS .Typed-OM-API { } attributeStyleMap 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' } @nucliweb

Slide 43

Slide 43

.Extends-CSS .Typed-OM-API { } css .foo { background-position: center bottom 10px; transform: translateX(1em) rotate(50deg) skewX(10deg); vertical-align: baseline; width: calc(100% - 3em); } @nucliweb

Slide 44

Slide 44

.Extends-CSS .Typed-OM-API { } computedStyleMap 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; @nucliweb

Slide 45

Slide 45

.Extends-CSS { } Animation Worklet @nucliweb

Slide 46

Slide 46

.Extends-CSS Animation-Worlet { } houdini.glitch.me/animation @nucliweb

Slide 47

Slide 47

.Extends-CSS { } Layout API @nucliweb

Slide 48

Slide 48

.Extends-CSS .Layout-API {} @nucliweb

Slide 49

Slide 49

Support

Slide 50

Slide 50

Slide 51

Slide 51

Slide 52

Slide 52

Conclusions

Slide 53

Slide 53

.Conclusions { } Poly lls This is not for me Free will Houdini is NOT like a Babel for CSS @nucliweb

Slide 54

Slide 54

.Conclusions { } Poly lls This is not for me Free will Houdini is NOT like a Babel for CSS @nucliweb

Slide 55

Slide 55

.Conclusions { } Poly lls This is not for me Free will I see another talk... Houdini is NOT like a Babel for CSS @nucliweb

Slide 56

Slide 56

CSS is Awesome

Slide 57

Slide 57

Resources

Slide 58

Slide 58

.Resources { } How Browsers Work: Behind the scenes of modern web browsers .Awesome-CSS-Houdini { } ⭐ are welcome Houdini samples @nucliweb

Slide 59

Slide 59

.Hello { Joan León #CSS Developer Advocate at @SchibstedSpain #Animation #PostCSS @nucliweb } Co-Founder & UI Engineers #SVG at @sublime_codes #Javascript

Slide 60

Slide 60

SUI Components @suiengineers @carlosvillu @midudev

Slide 61

Slide 61

.Talk::after { content: "Any "Any question?"; question?"; } @nucliweb

Slide 62

Slide 62

.Thanks { @nucliweb }