The future of responsive web design
Web component queries
Nikos Zinas
Chapter 1
Web components
Web Components are a set of technologies, aimed at giving the developers the tools to create and share custom HTML tags, which fully encapsulate their functionality and style.
Custom Elements
Twitter Bootstrap
<div class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">Modal title</h4>
</div>
<div class="modal-body">
<p>One fine body…</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">
Close
</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
Web components
<twbs-modal animation="fade">
<twbs-modal-header>
<button is="twbs-modal-button-close">Close<button>
<h4>Modal title</h4>
</twbs-modal-header>
<p>One fine body…</p>
<twbs-modal-footer>
<button is="twbs-modal-button-close" class="btn btn-default">
Close
</button>
<button class="btn btn-primary">Save changes</button>
</twbs-modal-footer>
</twbs-modal>
Registering elements
// Create an object based on the HTMLElement prototype
var modal = Object.create(HTMLElement.prototype);
// Register the element
document.register('twbs-modal', {
prototype: modal
});
// You can also extend existing objects
document.register('twbs-button', {
prototype: Object.create(HTMLButtonElement.prototype),
extends: 'button'
});
Per-element APIs
// Create an object based on the HTMLElement prototype
var modal = Object.create(HTMLElement.prototype);
// Define your own functions
modal.hide = function () {
// do stuff...
};
// Register the element
document.register('twbs-modal', {
prototype: modal
});
// Assuming <twbs-modal id="login-window"></twbs-modal>
document.getElementById('login-window').hide();
Lifecycle callbacks
// Fires when an instance of the element is created
modal.createdCallback = function() {};
// Fires when an instance was inserted into the document
modal.attachedCallback = function() {};
// Fires when an instance was removed from the document
modal.detachedCallback = function() {};
// Fires when an attribute was added, removed, or updated
modal.attributeChangedCallback = function(attr, oldVal, newVal) {};
Templates
<template></template>
<script type="text/template">
-- Some HTML content --
</script>
<template id="profile-template">
<div class="profile">
<img
src="assets/default.png"
alt="a faceless profile icon"
title="Default Avatar" />
<h3 class="profile__name"></h3>
<a href="" class="profile__email"></a>
</div>
</template>
Content is inert
var content = document.getElementById('profile-template').content;
var node = document.importNode(content, true);
// treat clone as any other node
// eg. document.body.appendChild(node);
<template id="profile-template">
<div class="profile">
<img
src="assets/default.png"
alt="a faceless profile icon"
title="Default Avatar" />
<h3 class="profile__name"></h3>
<a href="" class="profile__email"></a>
</div>
</template>
Content is not part of the document
var content = document.getElementById('profile-template').content;
var node = document.importNode(content, true);
// treat clone as any other node
// eg. document.body.appendChild(node);
Shadow DOM
DOM Tree encapsulation
<div id="host-element"></div>
<script>
// Create your shadow root
var root = document.querySelector('#host-element').createShadowRoot();
// add content like in any other node
root.innerHTML = '...';
</script>
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="#">
<img alt="Brand" src="...">
</a>
</div>
</div>
</nav>
<nav class="navbar navbar-default">
<a class="navbar-brand" href="#">
<img alt="Brand" src="...">
</a>
</nav>
<template id="navbar-template">
<div class="container-fluid">
<div class="navbar-header">
<content></content>
</div>
</div>
</template>
var shadowRoot, templateContent, node;
// Handle template
templateContent = document.querySelector('#navbar-template').content;
node = document.importNode(templateContent, true);
// Add to Shadow DOM
shadowRoot = document.querySelector('.navbar').createShadowRoot();
shadowRoot.appendChild(node);
HTML Imports
<link
rel="import"
href="twbs-modal.html"
id="twbs-modal-import"
onload="handleSuccess()"
onerror="handleError()"
async>
var content = document.getElementById('twbs-modal-import').import;
// treat content like any other document. eg.
content.querySelector('...');
- HTML is fetched but not inserted in the importing document
- Requests are de-duped
- Scripts are executing in the context of the importing document
- Styles are applied to the importing document
HTML Imports
The modular web
Chapter 2
Responsive Web Design
Responsive web design (RWD) is a web design approach aimed at crafting sites to provide an optimal viewing experience—easy reading and navigation with a minimum of resizing, panning, and scrolling—across a wide range of devices (from mobile phones to desktop computer monitors).
A bit of history...
Cameron Adams - Resolution dependent layout
2004
Ethan Marcotte (A List Apart) - Responsive web design
2010
Fluid grids
Flexible images
Media queries
Chapter 3
Element Queries
?
Element query is the method of adapting an element's styling, based on the size of its container and not the size of the viewport
Conceptual example
.profile .avatar {
float: left;
width: 180px;
}
.profile ( max-width: 320px ) .avatar {
display: block;
float: none;
width: auto;
}
Don't get too excited...
Element queries do not exist
Circular dependency
.container {
display: inline-block;
}
.container .block {
width: 200px;
}
.container ( min-width: 150px ) .block {
width: 100px;
}
Can I do anything today?
eq.js
.profile .avatar {
float: left;
width: 180px;
}
.profile[data-eq-state$="small"] .avatar {
display: block;
float: none;
width: auto;
}
<div class="profile" data-eq-pts="small: 300, medium: 600, large: 900">
<div class="avatar"></div>
</div>
css-element-queries
.profile .avatar {
float: left;
width: 180px;
}
.profile[max-width="200px"] .avatar {
display: block;
float: none;
width: auto;
}
elementQuery
.profile .avatar {
float: left;
width: 180px;
}
.profile[max-width~="200px"] .avatar {
display: block;
float: none;
width: auto;
}
boomqueries
.profile .avatar {
display: block;
}
.profile--large .avatar {
float: left;
width: 180px;
}
boomQueries.add('.profile', [
[180, 'profile--large']
]);
Resources
Tab Atkins - 2014 State of Element Queries
Ian Storm Taylor - Media Queries are a Hack
Think in components
Think responsively
Thank you
Nikos Zinas - @nzinas
The future of responsive web design - web component queries
By Nikos Zinas
The future of responsive web design - web component queries
- 1,671