A presentation at @ Fondsnet in February 2016 in Berlin, Germany by Gunnar Bittersmann
Web Components
HURRICANE by Bob Dylan and Jacques Levy Here comes the story of the Hurricane The man the authorities came to blame For somethin’ that he never done Put in a prison cell, but one time he could-a been The champion of the world
HURRICANE by Bob Dylan and Jacques Levy Here comes the story of the Hurricane / The man the authorities came to blame / For somethin’ that he never done / Put in a prison cell, but one time he could-a been / The champion of the world
HURRICANE by Bob Dylan and Jacques Levy Here comes the story of the Hurricane / The man the authorities came to blame / For somethin’ that he never done / Put in a prison cell, but one time he could-a been / The champion of the world .line:not(:last-child)::after { content: ” / “; }
Custom Elements
var XLElementPrototype = Object.create(HTMLSpanElement.prototype); var XLElement = document.registerElement(‘x-l’, { prototype: XLElementPrototype });
Three bodies lyin’ there does Patty see And another man named Bello, movin’ around mysteriously “I didn’t do it,” he says, and he throws up his hands “I was only robbin’ the register, I hope you understand I saw them leavin’,” he says, and he stops “One of us had better call up the cops” And so Patty calls the cops…
x-l { display: block; padding-left: 1em; text-indent: -1em; Three bodies lyin’ there does Patty see hanging-punctuation: first allow-end last; And another man named Bello, movin’ around mysteriously } “I didn’t do it,” he says, and he throws up his hands “I was only robbin’ the register, I hope you understand I saw them leavin’,” he says, and he stops “One of us had better call up the cops” And so Patty calls the cops…
hanging-punctuation ✘ ✘ ✘ ✘ ✘
for (var xlElements = document.querySelectorAll(‘x-l’), l = xlElements.length, i = 0; i < l; i++) { if (/^([„“]+)/.test(xlElements[i].innerHTML)) { xlElements[i].classList.add(‘hanging-punctuation-start’); } }
.hanging-punctuation-start for { (var xlElements = document.querySelectorAll(‘x-l’), l = xlElements.length, text-indent: -1.42em;i = 0; i < l; i++) { } if (/^([„“]+)/.test(xlElements[i].innerHTML)) { xlElements[i].classList.add(‘hanging-punctuation-start’); } } ✘
for (var xlElements = document.querySelectorAll(‘x-l’), l = xlElements.length, i = 0; i < l; i++) { xlElements[i].innerHTML = xlElements[i].innerHTML .replace(/^([„“’]+)/, ‘<span class=”hanging-punctuation-start”>$1</span>’); }
x-l { display: block; padding-left: 1em; -1em; for (var xlElements = text-indent: document.querySelectorAll(‘x-l’), position: l = xlElements.length, i = 0; relative; i < l; i++) } { xlElements[i].innerHTML = xlElements[i].innerHTML .hanging-punctuation-start .replace(/^([„“’]+)/, { ‘<span class=”hanging-punctuation-start”>$1</span>’); position: absolute; right: 100%; text-align: right; }
var XLElementPrototype = Object.create(HTMLSpanElement.prototype); XLElementPrototype.createdCallback = function() { this.innerHTML = this.innerHTML.replace(/^([„“’]+)/, ‘<span class=”hanging-punctuation-start”>$1</span>’); } var XLElement = document.registerElement(‘x-l’, { prototype: XLElementPrototype });
Shadow DOM
<input placeholder=”…”> <input type=”range”> <audio>
var XLElementPrototype = Object.create(HTMLSpanElement.prototype); XLElementPrototype.createdCallback = function() { var root = this.createShadowRoot(); } root.innerHTML = this.innerHTML.replace(/^([„“’]+)/, ‘<span class=”hanging-punctuation-start”>$1</span>’); var XLElement = document.registerElement(‘x-l’, { prototype: XLElementPrototype });
x-l { var XLElementPrototype =display: Object.create(HTMLSpanElement.prototype); block; padding-left: 1em; XLElementPrototype.createdCallback function() text-indent:= -1em; { position: relative; var root = this.createShadowRoot(); } root.innerHTML = this.innerHTML.replace(/^([„“’]+)/, .hanging-punctuation-start ‘<span class=”hanging-punctuation-start”>$1</span>’); { } position: absolute; right: 100%; var XLElement = document.registerElement(‘x-l’, { text-align: right; prototype: XLElementPrototype } });
x-l { var XLElementPrototype =display: Object.create(HTMLSpanElement.prototype); block; padding-left: 1em; XLElementPrototype.createdCallback function() text-indent:= -1em; { position: relative; var root = this.createShadowRoot(); } root.innerHTML = this.innerHTML.replace(/^([„“’]+)/, x-l::shadow .hanging-punctuation-start ‘<span class=”hanging-punctuation-start”>$1</span>’); { } position: absolute; right: 100%; var XLElement = document.registerElement(‘x-l’, { text-align: right; prototype: XLElementPrototype } });
x-l { var XLElementPrototype =display: Object.create(HTMLSpanElement.prototype); block; padding-left: 1em; XLElementPrototype.createdCallback function() text-indent:= -1em; { position: relative; var root = this.createShadowRoot(); } root.innerHTML = this.innerHTML.replace(/^([„“’]+)/, x-l::shadow .hanging-punctuation-start It’s been suggested to ‘<span class=”hanging-punctuation-start”>$1</span>’); { remove this feature. } position: absolute; right: 100%; var XLElement = document.registerElement(‘x-l’, { text-align: right; prototype: XLElementPrototype } });
x-l { var XLElementPrototype =display: Object.create(HTMLSpanElement.prototype); block; padding-left: 1em; XLElementPrototype.createdCallback function() text-indent:= -1em; { position: relative; var root = this.createShadowRoot(); } root.innerHTML = this.innerHTML.replace(/^([„“’]+)/, x-l /deep/ .hanging-punctuation-start ‘<span class=”hanging-punctuation-start”>$1</span>’); { } position: absolute; right: 100%; var XLElement = document.registerElement(‘x-l’, { text-align: right; prototype: XLElementPrototype } });
x-l { var XLElementPrototype =display: Object.create(HTMLSpanElement.prototype); block; padding-left: 1em; XLElementPrototype.createdCallback function() text-indent:= -1em; { position: relative; var root = this.createShadowRoot(); } root.innerHTML = this.innerHTML.replace(/^([„“’]+)/, x-l >>> .hanging-punctuation-start ‘<span class=”hanging-punctuation-start”>$1</span>’); { } position: absolute; right: 100%; var XLElement = document.registerElement(‘x-l’, { text-align: right; prototype: XLElementPrototype } });
x-l { var XLElementPrototype =display: Object.create(HTMLSpanElement.prototype); block; padding-left: 1em; XLElementPrototype.createdCallback function() text-indent:= -1em; { position: relative; var root = this.createShadowRoot(); } It’s currently disputed root.innerHTML = this.innerHTML.replace(/^([„“’]+)/, x-l >>> .hanging-punctuation-start whether this combinator ‘<span class=”hanging-punctuation-start”>$1</span>’); { should exist. } position: absolute; right: 100%; var XLElement = document.registerElement(‘x-l’, { text-align: right; prototype: XLElementPrototype } });
var XLElementPrototype = Object.create(HTMLSpanElement.prototype); XLElementPrototype.createdCallback = function() { var root = this.createShadowRoot(); } root.innerHTML = this.innerHTML.replace(/^([„“’]+)/, ‘<span class=”hanging-punctuation-start”>$1</span>’) + ‘<style>.hanging-punctuation-start { position: absolute;\ right: 100%; text-align: right }</style>’; var XLElement = document.registerElement(‘x-l’, {
Templates
<template id=”hanging-punctuation-start-template”> <span class=”hanging-punctuation-start”></span> <style> .hanging-punctuation-start { position: absolute; right: 100%; text-align: right; } </style> </template>
var XLElementPrototype = Object.create(HTMLSpanElement.prototype); XLElementPrototype.createdCallback = function() { var result = /^([„“’]+)/.exec(this.innerHTML); if (result) { var template = document.querySelector(‘#hanging-punctuation-start-template’); template.content.querySelector(‘.hanging-punctuation-start’).innerHTML = result[0]; var clone = document.importNode(template.content, true); var root = this.createShadowRoot(); root.innerHTML = this.innerHTML.substr(result[0].length); root.appendChild(clone); } } var XLElement = document.registerElement(‘x-l’, { prototype: XLElementPrototype });
HTML Imports
hanging-punctuation-start-template.html <template id=”hanging-punctuation-start-template”> <span class=”hanging-punctuation-start”></span> <style> .hanging-punctuation-start { position: absolute; right: 100%; text-align: right; } </style> </template>
var XLElementPrototype = Object.create(HTMLSpanElement.prototype); XLElementPrototype.createdCallback = function() { var result = /^([„“’]+)/.exec(this.innerHTML); if (result) { var link = document.querySelector(‘link[rel=”import”]’); var template = link.import.querySelector(‘#hanging-punctuation-start-template’); template.content.querySelector(‘.hanging-punctuation-start’).innerHTML = result[0]; var clone = document.importNode(template.content, true); var root = this.createShadowRoot(); root.innerHTML = this.innerHTML.substr(result[0].length); root.appendChild(clone); } } var XLElement = document.registerElement(‘x-l’, { prototype: XLElementPrototype });
Templates HTML Imports Custom Elements Shadow DOM ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✘ ✘ ✘ ✔ ✘ ✘ ✘ ✔ ✘ ✘ ✘
progressive enhancement
An escalator can never break, it can only become stairs. You would never see an “Escalator Temporarily Out Of Order” sign, just “Escalator Temporarily Stairs. Sorry for the convenience. We apologize for the fact that you can still get up there.” —Mitch Hedberg
There’s a common misconception that progressive enhancement means that you’ll spend your time dealing with older browsers, but in fact the opposite is true. Putting the basic functionality into place doesn’t take very long at all. And once you’ve done that, you’re free to spend all your time experimenting with the latest and greatest browser technologies, secure in the knowledge that even if they aren’t universally supported yet, that’s okay: you’ve already got your fallback in place. —Jeremy Keith
The key to thinking about web development this way is realising that there isn’t one final interface— there could be many, slightly different interfaces depending on the properties and capabilities of any particular user agent at any particular moment. And that’s okay. Websites do not need to look the same in every browser. —Jeremy Keith
Once you truly accept that, it’s an immensely liberating idea. Instead of spending your time trying to make websites look the same in wildly varying browsers, you can spend your time making sure that the core functionality of what you’re building works everywhere, while providing the best possible experience for more capable browsers. —Jeremy Keith
✘ <x-sortable-table> <caption>Bruce Springsteen’s studio albums</caption> <thead> <tr> <th>title</th> <th sorted>release date</th> </tr> </thead> <tbody> <tr> <td>Greetings from Asbury Park, N.J.</td> <td> <time>1973-01-05</time> </td> </tr> ▼
var XSortableTableElementPrototype = Object.create(HTMLTableElement.prototype); var XSortableTableElement = document.registerElement(‘x-sortable-table’, { prototype: XSortableTableElementPrototype, extends: ‘table’ }); → http://codepen.io/gunnarbittersmann/pen/XXwZpP
Custom Elements Shadow DOM Templates HTML Imports
Custom Elements Templates Look Ma, no JS framework! Shadow DOM HTML Imports
AngularJS
analogClockTemplate.html <div class=”face”> <div class=”hour-hand” style=”transform: rotate({{ 30 * (now | date:’h’) + (now | date:’m’) / 2 }}deg)”></div> <div class=”minute-hand” style=”transform: rotate({{ 6 * (now | date:’m’) }}deg)”></div> <div class=”second-hand” style=”transform: rotate({{ 6 * (now | date:’s’) + (now | date:’m’) * 360 + (now | date:’h’) * 360 }}deg)”></div> </div>
.face { width: 250px; height: 250px; position: relative; background-position: left top; transform: translate(461px,51px) rotateX(46deg) rotateY(27deg) rotateZ(-38deg); } .hour-hand { width: 4%; height: 35%; background: hsl(0, 0%, 95%); position: absolute; left: 48%; top: 25%; transform-origin: center 71.43%; }
var analogClockApp = angular.module(‘analogClockApp’, []); analogClockApp.directive(‘analogClock’, function () { return { templateUrl: ‘analogClockTemplate.html’ }; });
analogClockApp.controller(‘AnalogClockCtrl’, function ($scope, $timeout) { $scope.now = ‘Loading…’; var updateTime = function () { $timeout(function () { $scope.now = new Date(); updateTime(); }, 1000); }; updateTime(); });
Web Components AngularJS
Web Components Hurricane Blinded by the Light written by Bob Dylan and Jacques Levy written by Bruce Springsteen Copenhagen Metro Escalators photo by Stig Nygaard, CC-BY-2.0
View Web Components on Notist.
Dismiss
An introduction to Custom Elements, Shadow DOM, Templates, and HTML Imports. A comparision to JavaScript frameworks like AngularJS.