Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Houdini

 Houdini

A look into what's coming with Houdini, the umbrella term for customising CSS and getting hooks into the browser rendering pipeline.

ryanseddon

April 13, 2016
Tweet

More Decks by ryanseddon

Other Decks in Technology

Transcript

  1. Show that we care about extending the browser, and continue

    to iterate on it. I don’t think we can fix or even think of everything to fix from the beginning, it needs to evolve. — Daniel Glazman, CSS WG co-chair
  2. THE EXTENSIBLE WEB VISION Houdini is about enabling low-level access

    to previously impossible tasks on the web. #extendthewebforward.
  3. UMBRELLA TERM > Worklets > Parser API > Box Tree

    API > CSS Typed OM > Font Metrics API > Properties and Values
  4. UMBRELLA TERM > Worklets > Parser API > Box Tree

    API > CSS Typed OM > Font Metrics API > Properties and Values
  5. REGISTER A NEW PROPERTY CSS.registerProperty({ name: '--stop-color', syntax: '<color>', inherits:

    false, initialValue: 'rgba(255, 0, 0, 0.5)' }); .button { background: linear-gradient(var(--stop-color), black); transition: --stop-color 0.5s; } .button:hover { --stop-color: papayawhip; }
  6. NO MORE STRINGS <div style="width: calc(90% - 50px)"> Old way

    elem.style.width; // "calc(90% - 50px)" New way elem.styleMap.get('width'); // { percent: 90, px: 50 }
  7. EASILY DIVIDE, SUBTRACT, ADD ETC const width = elem.styleMap.get('width'); const

    height = new SimpleLength(width.divide(16/9), 'px'); // set element to have 16:9 ratio elem.styleMap.set('height', height);
  8. an API for running scripts in stages of the rendering

    pipeline independent of the main JavaScript execution environment.
  9. PAINTWORKLET Allows you to run code at the paint stage

    of the browser rendering pipeline.
  10. REGISTER A PAINTWORKLET window.paintWorklet.import('paintworklet.js').then(() => { // worklets returns a

    promise so you can do stuff when it loads }).catch(() => { // or when it fails });
  11. REGISTERPAINT registerPaint('circle', class { // ES2015 class uses static to

    allow user customisation static get inputProperties() { return ['--circle-color']; } paint(context, geometry, styleMap) { const color = styleMap.get('--circle-color'); context.fillStyle = color; // Paint happens after layout so we have access to the box geometry const x = geometry.width / 2; const y = geometry.height / 2; const radius = Math.min(x, y); // paint worklet gives you a canvas like API context.beginPath(); context.arc(x, y, radius, 0, 2 * Math.PI, false); context.fill(); } });
  12. LAYOUTWORKLET Allows you to run code at the layout stage

    and define new layout primitives not available in the browser.
  13. REGISTERLAYOUT registerLayout('masonry', class { static get inputProperties() { return ['width',

    'height'] } static get childrenInputProperties() { return ['x', 'y'] } layout(children, constraintSpace, styleMap) { // The dimensions of the space we have to work with const { width, height } = constraintSpace; // Loop over all direct children and lay them out. for (let child of children) { // Complex code to layout out each child child.doLayout(); } return { minContent: 0, maxContent: 0, width: width, height: height, fragments: [], unPositionedChildren: [], breakToken: null }; } });
  14. USING IT IN YOUR CSS #main { display: layout('masonry'); //

    that easy! } .thing { display: inline-layout('inline-thing'); }
  15. COMPOSITORWORKER1 var scrollerProxy = new CompositorProxy($('#scroller'), ['scrollTop']); var backgroundProxy =

    new CompositorProxy($('.background'), ['transform']); var worker = compositorWorker('paralax.js'); worker.postMessage([scrollerProxy, backgroundProxy]); 1 https://github.com/w3c/css-houdini-drafts/blob/master/composited-scrolling-and-animation/ Explainer.md#example-2-parallax
  16. onmessage = e => { const [scroller, background] = e.data;

    const update = timestamp => { const transform = background.transform; transform.m42 = 0.8 * scroller.scrollTop; // scroll y at 0.8 speed. background.transform = transform; requestAnimationFrame(update, [scroller]); }; requestAnimationFrame(update, [scroller]); }