Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

Houdini – Demystifying CSS

Surma
May 20, 2016

Houdini – Demystifying CSS

Google I/O 2016

Surma

May 20, 2016
Tweet

More Decks by Surma

Other Decks in Technology

Transcript

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

    existing features [...] allowing authors to understand and replicate them.”
  2. Typed Object Model const h = new CSSSimpleLength(50, 'vh') .subtract(new

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

    CSSSimpleLength(20, ‘px')); $('#element').styleMap.set('height', h); // h == calc(50vh - 20px); Experimental
  4. Custom Properties :root { --main-color: #444; --accent-color: #c00; } body

    h1 { color: var(--main-color); } Strings! String replacement!
  5. Custom Properties .drawer { transition: --width 1s ease-in-out; --width: 50px;

    width: var(--width); } .drawer.open { --width: 250px; } X
  6. 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
  7. 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
  8. 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
  9. 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
  10. 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
  11. 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
  12. 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
  13. 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
  14. 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
  15. 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
  16. 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
  17. Paint Worklet registerPaint('image-with-placeholder', class { static get inputProperties() { return

    ['--image']; } paint(ctx, geom, properties) { // ... } }); Experimental
  18. 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