CSS Houdini Painting the Web Lisi Linhart - @lisi_linhart - @storyblok

About me I’m a Frontend Engineer with a passion for web animation and UX. The past two years I’ve been lecturing about web development at the University of Applied Science Salzburg. Now I’m an Developer Experience Engineer at Storyblok. lisilinhart.info twitter.com/lisi_linhart codepen.io/lisilinhart www.storyblok.com Lisi Linhart - @lisi_linhart - @storyblok

What is CSS Houdini? ! Lisi Linhart - @lisi_linhart - @storyblok

What is CSS Houdini CSS Houdini is a W3C effort to define lower-level CSS DOM APIs for authors to understand, recreate, and extend high-level CSS authoring features. https://wiki.mozilla.org/CSS/Houdini Lisi Linhart - @lisi_linhart - @storyblok

What is CSS Houdini Extending CSS via JS Houdini introduces low-level JavaScript APIs for the browser’s render engine. This is simimlar to how Service Workers are a low-level JavaScript API for the browser’s cache. Lisi Linhart - @lisi_linhart - @storyblok

What is CSS Houdini Access to the rendering engine Houdini allows you to extend the CSS with new features using JavaScript, hook into CSS rendering engine and tell the browser how to apply CSS during a render process. Lisi Linhart - @lisi_linhart - @storyblok

Can we use it? see ishoudinireadyyet? Lisi Linhart - @lisi_linhart - @storyblok

Testing it out Activate experimental web platform features on chrome://flags/ Lisi Linhart - @lisi_linhart - @storyblok

Houdini APIs Lisi Linhart - @lisi_linhart - @storyblok

Houdini APIs The Houdini APIs allow you to work with the CSS parser, CSSOM, cascade, the layout, paint and composite rendering stages. Lisi Linhart - @lisi_linhart - @storyblok

Houdini APIs - High Level The high level apis are closely related to the browser’s rendering process (style → layout → paint → composite) → Paint API → Layout API → Animation API Lisi Linhart - @lisi_linhart - @storyblok

Paint API (High-level) An extension point for the browser’s paint rendering step where visual properties (color, background, border, etc.) are determined. → similar to a canvas drawing context → can “paint” anywhere, images are supported → has already quite good browser support (apart from Firefox) Lisi Linhart - @lisi_linhart - @storyblok

Paint API (High-level) Demo: https://css-houdini.rocks/tooltip Read more: https://houdini.glitch.me/paint Lisi Linhart - @lisi_linhart - @storyblok

Layout API (High-level) An extension point for the browser’s layout rendering step where element dimensions, position, and alignment are determined. → make your own display properties. Masonry, here we come! → Able to polyfill layout specs like Container Queries Lisi Linhart - @lisi_linhart - @storyblok

Layout API (High-level) Demo: https:// googlechromelabs.github.io/ houdini-samples/layout-worklet/ masonry/ Read more: https://houdini.glitch.me/layout Lisi Linhart - @lisi_linhart - @storyblok

Animation API (High-level) An extension point for browser’s composite rendering step where layers are drawn to the screen and animated. The Animation API allows animation effects to be tied to user input like scrolling in a performant way → Allows animations based on user input → Allows performant parallax Lisi Linhart - @lisi_linhart - @storyblok

Animation API (High-level) Demo: https:// googlechromelabs.github.io/ houdini-samples/animationworklet/twitter-header/ Read more: https://houdini.glitch.me/ animation Lisi Linhart - @lisi_linhart - @storyblok

Houdini APIs - Low Level The low level APIs form a foundation for high-level APIs. They are closely related to the parser extensions -> CSSOM, cascade → Typed Object Model API → Custom Properties & Values API → Font Metrics API → Parser API Lisi Linhart - @lisi_linhart - @storyblok

Typed Object Model API (Low-level) Before Houdini the only way for JavaScript to interact with CSS was by parsing CSS represented as string values and modifying them. The Typed OM gives shape and structure to CSS values that previously were simple strings. It’s an extension to the existing CSS Object Model (CSSOM) that exposes CSS values as typed JavaScript objects, instead of a simple strings. selectedElement.computedStyleMap().get(“font-size”); { } value: 20, unit: “px” selectedElement.attributeStyleMap.set(“font-size”, CSS.em(2)); Read more: https://houdini.glitch.me/typed-om Lisi Linhart - @lisi_linhart - @storyblok

Custom Properties & Values API (Low-level) Custom Properties give shape, structure, and constraints to CSS Variables. The CSS Properties And Values API allows developers to extend CSS variables by adding a type, initial value and define inheritance. → Types are preserved between CSS & JS → Good browser support already CSS.registerProperty({ name: “—colorPrimary”, syntax: “<color>”, inherits: false, initialValue: “blue”, }); Lisi Linhart - @lisi_linhart - @storyblok

Custom Properties & Values API (low-level) Demo: https://css-houdini.rocks/tooltip Read more: https://houdini.glitch.me/customproperties Lisi Linhart - @lisi_linhart - @storyblok

Font Metrics API (Low-level) (Very Early Stage) The Font Metrics API will provide methods for measuring dimensions of text elements that are being rendered on screen in order to allow developers to affect how text elements are being rendered on screen. Multi-line dynamic text truncation is an example of one of those features. Lisi Linhart - @lisi_linhart - @storyblok

Worklets Worklets are extension points for rendering engines. Worklets are scripts that run during render and are independent of the main JavaScript environment. Conceptually, they’re similar to Web Workers. The have very restricted access to the global scope. Houdini introduces following Worklets to extend the browser render engine: → Paint Worklet - Paint API → Animation Worklet - Animation API → Layout Worklet - Layout API https://houdini.glitch.me/worklets Lisi Linhart - @lisi_linhart - @storyblok

The Paint API Lisi Linhart - @lisi_linhart - @storyblok

The Paint API What does it do? The Paint API works very similar to the canvas drawing context. We can use JS to create custom drawing function that draw an image in CSS. We can then use this function for any CSS property that expects an image. You could use it for the background-image, the border-image or the liststyle-image. Lisi Linhart - @lisi_linhart - @storyblok

The Paint API Why do wee need it? → example: extra.css → instead of polyfills like the conic gradient polyfill → Reduce DOM nodes number, e.g. when drawing lots of particles → create fancy painting features Lisi Linhart - @lisi_linhart - @storyblok

How to use in CSS .slanted-bg { background-image: paint(slanted-bg); } Lisi Linhart - @lisi_linhart - @storyblok

How to use in CSS - Test for support .slanted-bg { background: papayawhip; } @supports (background: paint(slanted-bg)) { .slanted-bg { background: paint(slanted-bg); } } Lisi Linhart - @lisi_linhart - @storyblok

How to register in JS

  1. Declare a custom paint class 2. Register paint 3. Load worklet Lisi Linhart - @lisi_linhart - @storyblok

How to register in JS Declare class class SlantedBackground { paint(ctx, geom, props, args) { // paint implementation } } Lisi Linhart - @lisi_linhart - @storyblok

How to register in JS Register paint registerPaint(‘slanted-bg’, SlantedBackground); Lisi Linhart - @lisi_linhart - @storyblok

How to register in JS Load Worklet if (‘paintWorklet’ in CSS) { CSS.paintWorklet.addModule(‘slanted-bg-module.js’); } Lisi Linhart - @lisi_linhart - @storyblok

Paint API Example Lisi Linhart - @lisi_linhart - @storyblok

How my Houdini Journey started Lisi Linhart - @lisi_linhart - @storyblok

FFConf - 19. Nov 18 https://generativeartistry.com Lisi Linhart - @lisi_linhart - @storyblok

CSSConf - 31. May 19 Lisi Linhart - @lisi_linhart - @storyblok

How my Houdini Journey started ! Canvas & Houdini seem really similar Lisi Linhart - @lisi_linhart - @storyblok

How my Houdini Journey started https://generativeartistry.com/tutorials/tiled-lines var canvas = document.querySelector(‘canvas’); var context = canvas.getContext(‘2d’); for(var x = 0; x < size; x += step) { for(var y = 0; y < size; y+= step) { var leftToRight = Math.random() >= 0.5; if(leftToRight) { context.moveTo(x, y); context.lineTo(x + width, y + height); } else { context.moveTo(x + width, y); context.lineTo(x, y + height); } } } context.stroke(); Lisi Linhart - @lisi_linhart - @storyblok

How my Houdini Journey started Let’s try it in Houdini paint(ctx, geom) { for (let y = 0; y <= geom.height; y += size) { for (let x = 0; x <= geom.width; x += size) { let leftToRight = Math.random() >= 0.5; if (leftToRight) { ctx.moveTo(x, y + size); ctx.lineTo(x + size, y); } else { ctx.moveTo(x, y); ctx.lineTo(x + size, y + size); } } } } ctx.stroke(); Lisi Linhart - @lisi_linhart - @storyblok

How my Houdini Journey started Lisi Linhart - @lisi_linhart - @storyblok

Houdini & Generative Art https://codepen.io/lisilinhart/pen/LYEJWQQ Lisi Linhart - @lisi_linhart - @storyblok

  1. Register & Support if (CSS.paintWorklet) { CSS.paintWorklet.addModule(‘/lisilinhart/pen/LYEJWQQ.js’); } else { document.body.classList.add(‘warning’); } Lisi Linhart - @lisi_linhart - @storyblok

  1. Use in CSS .card { background: var(—c-light); background-image: paint(generative); —type: var(—drawType, lines); /* Types: lines,joyDivision,triangles */ —size: 120; —line-color: #E0AF53; —line-width: 2; } input[value=”lines”]:checked ~ .card { —drawType: lines; } Lisi Linhart - @lisi_linhart - @storyblok

  1. JS - registerPaint - input if (typeof registerPaint !== “undefined”) { registerPaint(“generative”, class { } paint(ctx, geom, properties) { … } }); Lisi Linhart - @lisi_linhart - @storyblok

The JS - paint() registerPaint(“generative”, class { static get inputProperties() { return [“—type”, “—size”, “—line-color”, “—line-width”]; } paint(ctx, geom, properties) { let drawType = String(properties.get(“—type”)).replace(’ ‘, ”); let size = Number(properties.get(“—size”)); let lineWidth = Number(properties.get(“—line-width”)); let lineColor = String(properties.get(“—line-color”)); ctx.lineWidth = lineWidth; ctx.strokeStyle = lineColor; const drawFunctions = { “lines”: () => this.drawLines(ctx, geom.width, geom.height, size), “joyDivision”: () => this.drawJoyDivision(ctx, geom.width, geom.height, size), “triangles”: () => this.drawTriangles(ctx, geom.width, geom.height, size), }; }); } drawFunctionsdrawType; Lisi Linhart - @lisi_linhart - @storyblok

The JS - drawLines() registerPaint(“generative”, class { static get inputProperties() { … } paint(ctx, geom, properties) { … } drawLines(ctx, width, height, size) { for (let y = 0; y <= height; y += size) { for (let x = 0; x <= width; x += size) { let leftToRight = Math.random() >= 0.5; if (leftToRight) { ctx.moveTo(x, y + size); ctx.lineTo(x + size, y); } else { ctx.moveTo(x, y); ctx.lineTo(x + size, y + size); } }); } } ctx.stroke(); } Lisi Linhart - @lisi_linhart - @storyblok

How does it perform compared to current CSS features? I wrote an article about it: Performance depends on various factors: → Painting performance between current features and Houdini Paint Examples are quite similar → Painting performance depends on your Houdini module complexity → CSS Houdini adds the overhead of loading the module → Consider adding a CSS fallback until it’s loaded (progressive enhancement!) Lisi Linhart - @lisi_linhart - @storyblok

Conclusion Lisi Linhart - @lisi_linhart - @storyblok

What is the CSS Houdini all about? CSS Houdini allows us to hook into the browser rendering process, so we can develop various CSS features that can be easily shared, implemented and, potentially, added to CSS specification itself. Lisi Linhart - @lisi_linhart - @storyblok

What are the advantages → close access to the CSSOM and parser → better performance than JS polyfills → great for features that depend on requestAnimationFrame or scroll interactions → build any CSS feature you want Lisi Linhart - @lisi_linhart - @storyblok

What is the Paint API all about? → Extend the browser render engine in various ways → Not all features have wide browers support: ishoudinireadyyet? → Allows you to easily include and adapt features that previously where not possible in CSS → great for reducing DOM nodes → no need for JS polyfills, we can just implement our own CSS features! Lisi Linhart - @lisi_linhart - @storyblok

What to keep in mind → Houdini is an experimental technology and is not production ready yet → always check for browser support before implementing any styles using this technique → be careful with animated effects and not do overdo it → great for progressive enhancement Lisi Linhart - @lisi_linhart - @storyblok

How do I get started? Lisi Linhart - @lisi_linhart - @storyblok

How do I get started? https://houdini.glitch.me Lisi Linhart - @lisi_linhart - @storyblok

How do I get started? https://github.com/nucliweb/awesome-css-houdini Lisi Linhart - @lisi_linhart - @storyblok

How do I get started? http://css-houdini.rock Lisi Linhart - @lisi_linhart - @storyblok

How do I get started? https://googlechromelabs.github.io/houdini-samples/ Lisi Linhart - @lisi_linhart - @storyblok

Articles → CSS Tricks - Paint API → Logrocket - Paint API → Google Developers - Houdini → Google Developers - Paint API → Smashing Magazine - CSS Houdini Lisi Linhart - @lisi_linhart - @storyblok

The End Thank you for joining! → My blog → My twitter → My Codepen → Storyblok Lisi Linhart - @lisi_linhart - @storyblok

Storyblok is a headless CMS, that helps your team to tell your story and manage content for every use-case: corporate websites, ecommerce, helpdesks, mobile apps, and screen displays. storyblok.com Lisi Linhart - @lisi_linhart - @storyblok