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

Houdini – Demystifying CSS

8314890e50d87c60b2ab5fdab90a9630?s=47 Surma
May 20, 2016

Houdini – Demystifying CSS

Google I/O 2016

8314890e50d87c60b2ab5fdab90a9630?s=128

Surma

May 20, 2016
Tweet

Transcript

  1. None
  2. Houdini – Demystifying CSS Surma @DasSurma

  3. Houdini “Maybe The Most Exciting Development in CSS” bit.ly/smashingmag-houdini

  4. bit.ly/surma-houdini

  5. Houdini sounds like the best thing since sliced bread

  6. History

  7. None
  8. someDiv.createShadowRoot(); customElements.define("my-element", class MyElement extends HTMLElement { // ... }

    ); Shadow DOM Custom Elements
  9. Shadow DOM <video poster="poster.png" controls> <source src="devstories.webm" type="video/webm"> <source src="devstories.mp4"

    type="video/mp4"> </video> Where do these come from?!
  10. None
  11. None
  12. extensiblewebmanifesto.org

  13. extensiblewebmanifesto.org “The web platform should expose low-level capabilities that explain

    existing features [...] allowing authors to understand and replicate them.”
  14. Houdini

  15. Houdini

  16. Houdini

  17. Houdini

  18. $('#element').style.transform = 'translate(' + this.width + ‘px,' + (this.height +

    20) + 'px)'; ES5
  19. $('#element').style.transform = `translate(${this.width}px,${this.height + 20}px)`; ES2015

  20. Typed Object Model

  21. Typed Object Model $('#element').styleMap .set('opacity', new CSSNumberValue(0.5)); $('#element').styleMap .set('height', new

    CSSSimpleLength(50, 'px')); Experimental
  22. Typed Object Model $('#element').styleMap .set('height', new CSSSimpleLength(50, 'px')); $('#element').styleMap .get('height').value;

    // 50 $('#element').styleMap .get('height').type; // ‘px’ Experimental
  23. Typed Object Model $('#element').styleMap .set('height', new CSSCalcLength('50vh - 20px')); $('#element').styleMap.get('height').vh;

    // 50 $('#element').styleMap.get('height').px; // -20 Experimental
  24. Typed Object Model $('#element').styleMap .set("height", new CSSCalcLength({ vh: 50, px:

    -20, })); Experimental
  25. Typed Object Model const h = new CSSSimpleLength(50, 'vh') .subtract(new

    CSSSimpleLength(20, ‘px')); $('#element').styleMap.set('height', h); Experimental
  26. Typed Object Model const h = new CSSSimpleLength(50, 'vh') .subtract(new

    CSSSimpleLength(20, ‘px')); $('#element').styleMap.set('height', h); // h == calc(50vh - 20px); Experimental
  27. bit.ly/houdini-typed-om-types

  28. None
  29. Refreshing!

  30. Houdini

  31. Custom Properties :root { --main-color: #444; --accent-color: #c00; } body

    h1 { color: var(--main-color); } Strings! String replacement!
  32. --width: 50px;

  33. --width: 250px;

  34. Custom Properties .drawer { transition: --width 1s ease-in-out; --width: 50px;

    width: var(--width); } .drawer.open { --width: 250px; } X
  35. Properties & Values

  36. Properties & Values registerProperty({ name: '--my-color', syntax: '<color>', inherits: true,

    initialValue: 'red' }); Experimental
  37. Houdini

  38. None
  39. Do you even will-change? Paul Lewis @aerotwist

  40. None
  41. bit.ly/best-effort-scroll position: static;

  42. bit.ly/best-effort-scroll position: static; position: fixed; + JS transform

  43. Compositor Worklet

  44. Compositor Worklet

  45. Compositor Worklet

  46. Compositor Worklet

  47. Compositor Worklet

  48. Compositor Worklet window.compositorWorklet.import('compworklet.js') .then(function() { var animator = new CompositorAnimator('social-header');

    animator.postMessage([ new CompositorProxy($('window'), ['scrollTop']), new CompositorProxy($('.avatar'), ['transform']), new CompositorProxy($('.bar'), ['transform', 'opacity']) ]); }); Experimental
  49. Compositor Worklet window.compositorWorklet.import('compworklet.js') .then(function() { var animator = new CompositorAnimator('social-header');

    animator.postMessage([ new CompositorProxy($('window'), ['scrollTop']), new CompositorProxy($('.avatar'), ['transform']), new CompositorProxy($('.bar'), ['transform', 'opacity']) ]); }); Experimental
  50. Compositor Worklet class SocialHeader { onmessage(e) { this.initialized = true;

    this.scroller = e.data[0]; this.avatar = e.data[1]; this.bar = e.data[2]; }; tick() { /* ... */ } } registerCompositorAnimator('social-header', SocialHeader); Experimental
  51. Compositor Worklet class SocialHeader { onmessage(e) { this.initialized = true;

    this.scroller = e.data[0]; this.avatar = e.data[1]; this.bar = e.data[2]; }; tick() { /* ... */ } } registerCompositorAnimator('social-header', SocialHeader); Experimental
  52. Compositor Worklet class SocialHeader { onmessage(e) { this.initialized = true;

    this.scroller = e.data[0]; this.avatar = e.data[1]; this.bar = e.data[2]; }; tick() { /* ... */ } } registerCompositorAnimator('social-header', SocialHeader); Experimental
  53. Compositor Worklet class SocialHeader { onmessage(e) { this.initialized = true;

    this.scroller = e.data[0]; this.avatar = e.data[1]; this.bar = e.data[2]; }; tick() { /* ... */ } } registerCompositorAnimator('social-header', SocialHeader); Experimental
  54. Compositor Worklet class SocialHeader { onmessage(e) { this.initialized = true;

    this.scroller = e.data[0]; this.avatar = e.data[1]; this.bar = e.data[2]; }; tick() { /* ... */ } } registerCompositorAnimator('social-header', SocialHeader); Experimental
  55. Compositor Worklet window.compositorWorklet.import('compworklet.js') .then(function() { var animator = new CompositorAnimator('social-header');

    animator.postMessage([ new CompositorProxy($('window'), ['scrollTop']), new CompositorProxy($('.avatar'), ['transform']), new CompositorProxy($('.bar'), ['transform', 'opacity']) ]); }); Experimental
  56. Compositor Worklet window.compositorWorklet.import('compworklet.js') .then(function() { var animator = new CompositorAnimator('social-header');

    animator.postMessage([ new CompositorProxy($('window'), ['scrollTop']), new CompositorProxy($('.avatar'), ['transform']), new CompositorProxy($('.bar'), ['transform', 'opacity']) ]); }); Experimental
  57. Compositor Worklet window.compositorWorklet.import('compworklet.js') .then(function() { var animator = new CompositorAnimator('social-header');

    animator.postMessage([ new CompositorProxy($('window'), ['scrollTop']), new CompositorProxy($('.avatar'), ['transform']), new CompositorProxy($('.bar'), ['transform', 'opacity']) ]); }); Experimental
  58. Compositor Worklet window.compositorWorklet.import('compworklet.js') .then(function() { var animator = new CompositorAnimator('social-header');

    animator.postMessage([ new CompositorProxy($('window'), ['scrollTop']), new CompositorProxy($('.avatar'), ['transform']), new CompositorProxy($('.bar'), ['transform', 'opacity']) ]); }); Experimental
  59. None
  60. None
  61. Houdini

  62. Paint Worklet

  63. Paint Worklet <div id="myElement"></div> <style> #myElement { --image: url('#someUrlWhichIsLoading'); background-image:

    paint(image-with-placeholder); } </style> Experimental
  64. Paint Worklet <script> document.registerProperty({ name: '--image', syntax: '<image>' }); window.paintWorklet.import('paintworklet.js');

    </script> Experimental
  65. Paint Worklet registerPaint('image-with-placeholder', class { static get inputProperties() { return

    ['--image']; } paint(ctx, geom, properties) { // ... } }); Experimental
  66. Paint Worklet paint(ctx, geom, properties) { const img = properties.get('--image');

    switch (img.state) { case 'ready': ctx.drawImage(img, 0, 0, geom.width, geom.height); break; case 'pending': drawMountains(ctx); break; case 'invalid': default: drawSadFace(ctx); } } Experimental
  67. Houdini

  68. Layout ?

  69. None
  70. gridstylesheets.org

  71. Font Metrics ?

  72. None
  73. Parser ?

  74. Soon (tm) Paint API Typed OM Compositor Worklet

  75. None
  76. developers.google.com/web/updates

  77. Ian Kilpatrick @bfgeek Chrome Engineer & Houdini Lead Surma @DasSurma

    Surma
  78. extensiblewebmanifesto.org

  79. Surma @DasSurma