Chapter 11. The Future

So far in this book I’ve aimed to discuss only those web features that are pretty stable in at least a few browsers, or that should be stable sometime in the near future. But now that we’ve arrived at this last chapter, I can really cut loose and talk about some of the more experimental features on the horizon.

Changes are planned everywhere: A new revision of JavaScript, code-named Harmony, is due for release sometime in 2013 and should make its way into browsers over the coming years; many new APIs are being proposed to the W3C, including one for discovering devices on the same network using Universal Plug and Play (UPnP) and one for measuring ambient light; work on the draft specification for HTML5.1 is well underway; and many CSS modules are already moving to Level 4. I could talk about any number of changes, but I’ll focus on the ones that I think will have the greatest impact on the way we work and that have a good chance of being implemented.

I don’t think I’m exaggerating when I say that the Web Components specification proposes the most radical changes to HTML since its creation some 20+ years ago. Even the much-hyped HTML5 is a small point-version update that doesn’t really add anything genuinely new.

Web Components is a collective title for a group of additions to HTML and the DOM aimed at making rich interfaces for web applications—a kind of reusable widget specification. As I write this, four main components exist: templates, decorators, custom elements, and the Shadow DOM. I’ll explain what each does in turn, but first let me sum up what they do when combined.

One of the principal problems of building application components in HTML today is that the elements used to build them are part of the DOM and, as such, are open to conflicts from CSS or JavaScript. These could be inheritance conflicts, such as rules applied to parent elements cascading into component elements or, inversely, rules applied to component elements leaking or cascading to elements elsewhere in the DOM.

Another problem results from naming conflicts, where the same class or ID is unknowingly used in different pages of a site, meaning rules intentionally declared on one element are also unintentionally applied to others. This problem is commonly found on large sites that lack a clear naming scheme, and it can be made even worse by conflicts in JavaScript when selectors apply unwanted functional behavior to an element.

The best way to avoid conflicts like these is to separate the component from the rest of the DOM to prevent any inheriting or leaking. This technique is known as encapsulation and is fundamental to object-oriented programming languages.

Web Components attempts to bring encapsulation into the HTML DOM by allowing you to create elements that appear only in the rendering of a page, not in the DOM itself. Web Components will offer a way to build widgets that can be reused across many different pages on a site without having to worry about conflicts with existing CSS and JavaScript, since the widget lives in a parallel DOM.

The Web Components spec is still in the draft stage as I write this, so I won’t explore the concepts in great detail, but I will cover the basics since it could be so significant.

Probably the easiest way to grasp Web Components is with an understanding of templates. The idea of developing with reusable blocks of code, or templates, has been a staple of web development for quite some time, although we’ve never seen a native implementation in HTML; server-side languages or JavaScript (such as the Mustache library from Chapter 5) have been required in order to use templates.

Think of a Web Component template as a kind of inert block of DOM. The significance of this is that the contents are parsed, but not rendered, by the browser. This means images and other external elements aren’t loaded and included scripts won’t run, which can be a real performance boost compared to hiding elements with CSS, where assets are still loaded.

A template is declared with the template element, and any child elements form the content of the template. The following code block shows a template element with the id #foo, which has two child elements (an h2 and a p). Outside of the template is a div with the id #bar, which contains an h1 element.

<template id="foo">
  <h2>Gorilla Beringei</h2>
  <p>A species of the genus Gorilla…</p>
</template>
<div id="bar">
  <h1>Eastern Gorilla</h1>
</div>

If you were to view this page with your browser’s developer tools, you would see the template element with no content inside it because, essentially, the contents of this element are invisible to the DOM.

You access the template through script using the content object, which returns the child elements of the template as an HTML fragment. For example, you can see that the next code snippet assigns the template to the variable tpl and logs its content object to the console:

var tpl = document.getElementById('foo');
console.log(tpl.content);

Once you have the fragment, you can manipulate it as you see fit. The following code uses cloneNode() to create a clone of the content and appendChild() to add it inside #bar:

var bar = document.getElementById('bar'), clone = tpl.content.cloneNode(true);
bar.appendChild(clone);

At this point, you would see this markup if you inspected the DOM:

<template id="foo"></template>
<div id="bar">
  <h1>Eastern Gorilla</h1>
</div>

But the page would be rendered as if it were using this markup:

<div id="bar">
  <h1>Eastern Gorilla</h1>
  <h2>Gorilla Beringei</h2>
  <p>A species of the genus Gorilla…</p>
</div>

You can see it for yourself in the example file templates.html; the output is shown in Figure 11-1 (see Appendix M for information on current browser support). Note that in order for the contents of the template element to show in the DOM, I had to enable the Show Shadow DOM option in my developer tools; if that option wasn’t enabled, the element would appear to be empty.

Code that was inert inside the template element becomes active once it’s inserted into another DOM element, at which point any external resources will load, scripts will be parsed, and so on.

Decorators extend the utility of templates by allowing you to add custom markup through CSS. Decorators use the decorator element, which must have a unique id assigned. Inside the decorator element, you’ll find a template element with some custom markup and the content element, which is where the element that the rule is applied to is rendered. Not clear? It took me a while to get it too.

Let’s break this down into stages. The following code shows an example of a decorator. I gave it the unique id #foo (for a change). Inside is a template that contains a div, with the content element and an h2 inside that.

<decorator id="foo">
  <template>
    <div>
      <content></content>
      <h2>A great ape!</h2>
    </div>
  </template>
</decorator>

Now imagine that in the main document I have an h1 element with the id #bar, as in the following code:

<h1 id="bar">Gorilla</h1>

I apply the decorator using CSS and the new decorator property, which has as its value a url() function containing the decorator’s id.

h1#bar { decorator: url(#foo); }

Once I’ve done this, the markup in the template #foo is added to the markup of the element #bar, with #bar itself replacing the content element of #foo. However, this takes effect only at the point of rendering and doesn’t alter the DOM. Although an inspection of the DOM shows only the element #bar, the element will be rendered as though the markup were this:

<div>
  <h1 id="bar">Gorilla</h1>
  <h2>A great ape!</h2>
</div>

You can do more with templates and decorators, but to show you more, I first need to make a brief digression to talk about scoped styles.

Scoped Styles

One of CSS’s greatest strengths is its use of inheritance—that is, the way that values can cascade through selectors to apply to multiple elements. That strength can also be a drawback, however, if you’re working on large sites with many stylesheets, where experiencing the naming and inheritance conflicts that I mentioned at the start of this section is not uncommon.

Scoped styles are a way to avoid these conflicts. They’re applied in the document using the style element with the attribute scoped, and any rules contained therein are inherited only by the children of the element they’re used in, and won’t be applied anywhere else in the document.

You can see this in action in the following code: A scoped style tag is used inside a div element, and the rules applied to the h1 apply only to the h1 within that element (the one with the id of #foo), and not the one outside the div (with the id #bar). The scope of the rule applies only to the children of the div.

<div>
  <style scoped>
    h1 {
      background-color: #333;
      color: #FFF;
    }
  </style>
  <h1 id="foo">Scoped</h1>
</div>
<h1 id="bar">Not Scoped</h1>

Take a look at the example file scoped-style.html. Here, the h1 with the id #bar follows the one with the id #foo in DOM order, so you would expect the rules inside the style element to apply to both. In fact, the scoped attribute means the rules apply only inside the parent div. You can see the result in Figure 11-2 and in scoped-style.html.

Although decorators are handy for adding extra presentational markup to an element, when you want to make more substantial changes, use a custom element. The key difference between custom elements and decorators is that the latter are transitory; they can be applied or removed by changing an attribute or selector. Custom elements, on the other hand, are fixed; they are applied when the DOM is parsed and can be changed or removed only with scripting.

A custom element is like an extended template that replaces or enhances a standard element. You create a custom element with the element element (this paragraph is going for a new record in the number of occurrences of the word “element”), which has some new attributes that I’ll discuss shortly. Inside this element, you can add a template element with new markup, as well as scoped styles and even a script.

If this sounds a bit confusing, consider this illustration. The following code snippet shows a simple example: an element containing a template, which, in turn, contains a div, which itself contains the content element I introduced in Decorators. The element has two attributes: extends, which takes as a value the name of the element that it will extend (in this case, a button element), and name, a user-defined unique identifier value (which must start with x- to avoid conflicting with existing elements).

<element extends="button" name="x-foobutton">
  <template>
    <div id="foo">
      <content></content>
    </div>
  </template>
</element>

Once the custom element has been defined, you can apply it to an existing element with the is attribute. The is attribute is applied to the element to be extended and takes as a value the unique identifier from the name attribute (x-foobutton) defined on the custom element. Actually, this is simpler than it may sound:

<button is="x-foobutton">Go</button>

The resulting effect is the same as that of a decorator: The markup of the custom element extends the markup of the element it’s applied to but only in the rendered view. Although viewing the DOM shows only the button element, it renders like this:

<div id="foo">
  <button>Go</button>
</div>

This example is simple, but you can see how the extensibility of this technique would make it easy to build completely tailor-made widgets that could be reused across many documents. As a result, many of the cumbersome widgets we build today (such as carousels, accordions, and date pickers) could be applied to existing elements without filling the DOM with unnecessary markup, with the added benefit of implementing encapsulation to avoid conflicts.

I mentioned earlier that the core difference between a custom element and a decorator is in the permanence of the markup. One advantage of this is that scripts can be included in a custom element that will always be present (a benefit you can’t rely on for the more impermanent decorators). All this means you could even define an imperative API for each custom element, thereby taking interactivity to a whole new level.

The final piece of the Web Components specification is the Shadow DOM. This is not only a cool-sounding name for a supervillain, but it’s also a way to create and access, with script, the elements that exist in the parallel DOM I’ve shown you in this chapter. Just as decorators use CSS to alter elements and custom elements use HTML, Shadow DOM uses script to achieve the same ends.

The Shadow DOM describes the ability of a browser to create a new, fully encapsulated node tree inside the existing DOM. The browser does this by creating a shadow root inside an element, which can be traversed and manipulated like a regular node tree. (A shadow tree won’t show up in the DOM, but it will be rendered.)

Now for an example. The following code snippet contains some simple markup: a div called #foo, which contains a single h1 element. This is the base markup in the DOM, inside which I’ll add a new shadow root.

<div id="foo">
  <h1>Hello, world!</h1>
</div>

Now I’ll add a new shadow root inside the div, and then create and append a new element to the new root. I explain this code point by point in the discussion that follows.

  var foo = document.getElementById('foo'),
1   newRoot = foo.createShadowRoot(),
2   newH2 = document.createElement('h2');
  newH2.textContent = 'Hello, shadow world!');
3 newRoot.appendChild(newH1);

The first thing to note 1 is the creation of a new shadow root inside #foo, using the createShadowRoot() method. In the following two lines 2, I create a new h2 element with the text content 'Hello, shadow world!‘. And finally 3, I append the new h2 element into my new shadow root.

When this code executes, users see an h2 element with the text 'Hello, shadow world!', but if they viewed the DOM, users would see the original content, 'Hello, world!‘. The h1 element has been completely replaced by the new shadow node tree. The DOM remains unaffected.

Figure 11-3 shows how this renders in the Chrome developer tools, with the contents of the shadow root displayed in a new node tree below the identifier #shadow-root.

If you don’t want to replace the content in the element in which you’ve created a new root, you can once again use the content element (again introduced in Decorators) to include the original elements. I illustrate this in the following code, where I create the content element and then append it to the new shadow root. As a result, the user sees the new shadow h2 first, followed by the original h1, although only the h1 appears in the DOM.

var content = document.createElement(content);
newRoot.appendChild(content);

You can also use templates with shadow node trees. For example, here’s how to append an HTML fragment of the template #foo content into the Shadow DOM:

var foo = document.getElementById('foo');
newRoot.appendChild(foo.content);

The Shadow DOM goes even further than this simple example and is a very powerful and flexible tool. I can’t spend any more time on it here, but see Appendix L for some links to more detailed articles.

CSS3 has already revolutionized the Web in some ways, with its introduction of behavioral aspects such as transitions and animations and by seriously addressing the problem of layout mechanisms. But those features barely scratch the surface of what’s to come. Lots of big tech companies are betting their futures on the Web, and their involvement in shaping the future of web standards brings with it some incredible innovation.

For example, Adobe’s wholesale embrace of open standards (a pleasant surprise!) is making it a major player in browser development, and its experience with graphics and publishing is being applied to CSS. The first fruits of this labor are CSS Regions and Exclusions, which open up the possibility of major changes to the way we’ll lay out pages in the future, as dynamic web pages finally begin to catch up with what desktop publishing has been doing for years.

But the web development community is having the biggest effect on the development of CSS. Developer-built JavaScript libraries such as jQuery and Modernizr are directly influencing the language, as you’ve seen with querySelector() and querySelectorAll() (back in Chapter 5), and that influence will be felt further with the introduction of feature queries.

Additionally, the rise in popularity of CSS preprocessors such as Sass and LESS means that front-end developers are becoming accustomed to using programming principles, such as variables and functions. The demand for these to be introduced into the language is manifesting itself through cascading variables.

Regions

Back in Chapter 4, I discussed CSS columns, where inline content is divided into columns and flows through the first column and then the second, the third, and so on. Imagine that those columns are not immediately adjacent to each other; the first is on the left of the page, the second is on the right, and the third is at the bottom, but the content still flows sequentially through them. That’s the gist of a new CSS concept called Regions.

Regions work like this: An element is declared as a source, and the content of that source is flowed into another element, or series of elements, known as a region chain. What that means in practice is you can have content flowing across multiple elements in a sequence that doesn’t flow in natural DOM order.

Here’s a simple illustration that starts with three div elements: a #foo and two .bars. The first, #foo, is filled with content, and the others are empty:

<div id="foo">
  <p>…</p>
</div>
<div class="bar"></div>
<div class="bar"></div>

The next step is to get the content of #foo and put it into a named flow, kind of like storing it in a variable (or the clipboard on your computer). In CSS Regions, you create this named flow by declaring the flow-into property on the source element (#foo). The value of the property is a unique name of your choosing, so I’ll name mine myFlow. Having named my flow (or clipboard, if you’re still following the metaphor), I can flow it into other elements, which become known as the titular regions:

#foo { flow-into: myFlow; }

When this property is applied, the source element and all its children are no longer rendered on screen, although they are still visible and accessible in the DOM.

Next I must declare a region chain that the content will be flowed into. Each element that forms part of the region chain should have the flow-from property declared on it, the value of which is the previously defined named flow. The following code shows how to flow the content of the flow myFlow into all regions called .bar:

.bar { flow-from: myFlow; }

The content in myFlow flows through the region chain in DOM order; it starts by flowing into the first instance of .bar, and then any overflow flows into the second instance of .bar, and so on, until the end of the content. Try this out with the file regions.html, as shown in Figure 11-4.

As I mentioned at the beginning of this section, CSS Regions work like multiple columns, without the columns needing to be immediately adjacent. This new element creates some amazing opportunities for making dynamic, interesting page layouts, inspired by years of experience with the possibilities of print media.

CSS Exclusions can be thought of as a kind of positioned floats—indeed, an earlier concept described them as exactly that. In CSS2.1 you can float elements only to the left, where other content flows around their right side, or vice versa. But the idea of CSS Exclusions is that you can flow content around an element no matter where it’s positioned on the page.

To illustrate, consider the following markup with a container element #foo, some text content in a p, and a child element #bar:

<div id="foo">
  <p>…</p>
  <div id="bar"></div>
</div>

I want to position #bar absolutely over the content in #foo, which will require style rules somewhat like this:

#foo { position: relative; }
#bar {
  left: 20px;
  position: absolute;
}

As written here, #bar sits in a layer stacked above the text content, obscuring what’s behind it, as you can see in Figure 11-5. But I want to make #bar part of the same layer and to float the text content around it. In the parlance of Exclusions, I want #bar to become an exclusion element.

I can accomplish this with the wrap-flow property, which makes the element it’s applied to an exclusion element. Any sibling content flows around it according to the keyword value of the property.

The following example uses the keyword value both to make content flow around both sides of the exclusion element:

#bar { wrap-flow: both; }

You can see the difference this makes in Figure 11-6. The elements are in the same positions as before, but because #bar has now been declared an exclusion element, the content in #foo flows around it on both sides.

Alternative values for wrap-flow include:

Figure 11-7 shows a few of the different values at work. The first example has a value of start, so the content flows to the left of the exclusion element. The next has the end value, so the content flows on the opposite side. And in the final example, the clear value makes content flow on neither side of the element.

To permit more control over the flow of inline elements around the exclusion, you have the wrap-through property. This property takes one of two keyword values: flow and none. The former, the default, makes inline content flow around the exclusion element; the latter doesn’t. This is useful if you want to enable content flow on a per-element basis.

As I write this in early 2013, a series of new rules and properties that affect layout are at various degrees of implementation—from barely there to only a proposal. My hope is that they will all be adopted and implemented because they solve different problems. With the CSS specification in a constant state of flux, however, nothing can be taken for granted; these rules and properties may be implemented, partially implemented with a different syntax, or not implemented at all.

Still, I think looking at them is worthwhile for two reasons: First, so you can see the thinking that goes on in trying to find solutions to the problems of web layout; and second, if they are implemented, you may need to use them.

In Chapter 5 I discussed the JavaScript library Modernizr, which is used for detecting the existence of certain features in a visitor’s browser, and briefly mentioned its native adaptation into CSS through the @supports at-rule. I want to return to that now and explore it in a little more detail, as it’s extremely useful and fast making its way into browsers.

The @supports at-rule behaves like a media query: You create a logical query that, if it returns true, will apply the rules contained within the subsequent brackets. But instead of media features, the test conditions are CSS property-value pairs, known as feature queries. For example, to test whether a user’s browser supports the column-count property so you can serve appropriate styles, you could construct a query like this:

@supports (column-count: 1) { … }

As with media queries, you can build more advanced queries using logical operators. For example, the following query uses the and operator to serve styles to browsers that support both the column-count and box-sizing properties:

@supports (column-count: 1) and (box-sizing: border-box) { … }

You can also use the or operator to build queries that detect defined features, which is extremely useful when dealing with vendor-prefixed properties. Here, both the hyphens or -moz-hyphens properties are tested against, and if either is supported, the rules are applied:

@supports (-moz-hyphens: auto) or (hyphens: auto) { … }

The not operator allows you to serve styles to browsers that don’t support a given property. (Note that unlike the other operators, this one must be inside parentheses.)

@supports (not (-webkit-hyphens: auto)) { … }

Feature queries include an API that is as simple to use as the at-rule. For example, you can use the CSS.supports() method to detect a single feature by passing a property-value pair as two arguments. Here, it tests for the flex value on the display property:

var supports = CSS.supports('display','flex');

And you can pass in full queries as a single argument, quoted as a string:

var supports = CSS.supports('(column-count: 1) and (display: flex)');

The Modernizr project has already begun implementing this in its library; if native CSS.supports() implementation is present, the script will use that, and if not, it will fall back to Modernizr’s own tests.

Variables have proven their utility over the years in just about every programming language, but they have never been implemented in CSS, despite regular calls for implementation from the community. But with the surge in popularity of CSS preprocessors, a generation of coders is learning to love variables in their stylesheets, and calls to include them natively in the language can no longer be ignored.

As currently proposed, CSS variables have limited scope. A true variable permits any type of value and could be used at any point in the code—say, to assign a selector to a variable. The proposed CSS variables can be assigned only a valid CSS value and can be used only as the value of a property. For this reason, they’re distinguished with the name Cascading Variables.

Each Cascading Variable is declared using a custom property: a user-defined property name beginning with var- to which a value is assigned. Here, the color value #F00 is assigned to the custom property var-foo:

:root { var-foo: #F00; }

Notice that I’ve declared this custom property using the :root selector. (I explain why shortly.)

To use the value of the custom property, you call it using the var() function, with the user-defined name (the bit after var-) in parentheses. The value of the custom property is used as the value of the property it’s called on. For example, in the following listing, the h1 element calls the var-foo property using the var(foo) function twice: once on the border-bottom property and once on color. The color value #F00 will be applied appropriately to each property.

 h1 {
  border-bottom: 1px solid var(foo);
  color: var(foo);
}

Cascading Variables are scoped, meaning they apply only to the element on which they are declared and to any child element. My use of the :root selector to declare a custom property in the example in this section means the variable has global scope: It can be applied on any element on the page. Had I used a different selector, the value of the variable declared in the custom property would apply only to children of the matching element(s).

For example, in the following code the custom property var-foo, with a value of #F00, is declared on the :root element, but I’ll also add a different value and selector below it. In this case, the value of the variable would be #F00 for the whole document, but it will now be #00F for the .bar element and its children.

:root { var-foo: #F00; }
.bar { var-foo: #00F; }

In this chapter, we’ve looked at some of the more experimental features of the web platform. These are all still in the testing phase and are liable to change, but they’re so powerful and potentially important to the platform’s future that I couldn’t really finish this book without mentioning them.

First up was Web Components, the biggest change to HTML since its invention. Web Components is a suite of features. It makes a parallel DOM that allows reusable code blocks to enhance and extend the standard HTML elements with full encapsulation, protecting them from conflicts with other CSS rules and JavaScript functions.

Next we looked at the future of CSS, which is also undergoing huge changes thanks to the involvement of big tech companies. CSS Regions and Exclusions promise to provide the tools required to create dynamic custom layouts that rival (and exceed?) anything possible in print media.

Finally, I covered new CSS features that are being developed based on innovation from the web development community. These include feature queries that bring native Modernizr-like feature detection to CSS and Cascading Variables that begin the adoption of the best preprocessor features into the language itself.